spring boot中使用hibernate拦截器的问题
Problem of using hibernate interceptor in springboot
我想在 spring 启动时使用休眠拦截器,以便在事务提交后使用 afterTransactionCompletion()
方法做一些事情。
我按照How to use Spring managed Hibernate interceptors in Spring Boot配置(我只是在application.properties
中添加spring.jpa.properties.hibernate.ejb.interceptor=com.lc.demo.inteceptor.MyInteceptor
)
拦截器工作了,但是当我试图在方法afterTransactionCompletion()
中获取交易状态时仍然有问题,它总是NOT_ACTIVE
(我希望它可以是COMMITTED
):
import static org.hibernate.resource.transaction.spi.TransactionStatus.COMMITTED;
import org.hibernate.EmptyInterceptor;
import org.hibernate.Transaction;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.springframework.stereotype.Component;
@Component
public class MyInteceptor extends EmptyInterceptor{
private static final long serialVersionUID = -7992825362361127331L;
@Override
public void afterTransactionCompletion(Transaction tx) {
//The status is always NOT_ACTIVE
TransactionStatus status = tx.getStatus(); //
if (tx.getStatus() == COMMITTED) {
System.out.println("This is what I want to do");
} else {
System.out.println("This is what I do not want");
}
}
@Override
public void beforeTransactionCompletion(Transaction tx) {
// The status is ACTIVE
TransactionStatus status = tx.getStatus();
System.out.println(status);
}
}
我尝试调试它,发现在 afterTransactionCompletion()
被调用之前,
在扩展AbstractLogicalConnectionImplementor
的org.hibernate.resource.jdbc.internal.LogicalConnectionProvidedImpl
中,commit()
方法调用afterCompletion()
方法调用resetConnection(boolean initiallyAutoCommit)
设置事务状态NOT_ACTIVE
:
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.resource.jdbc.internal;
import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.TransactionException;
import org.hibernate.resource.jdbc.ResourceRegistry;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.resource.jdbc.spi.PhysicalJdbcTransaction;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
*/
public abstract class AbstractLogicalConnectionImplementor implements LogicalConnectionImplementor, PhysicalJdbcTransaction {
private static final Logger log = Logger.getLogger( AbstractLogicalConnectionImplementor.class );
private TransactionStatus status = TransactionStatus.NOT_ACTIVE;
protected ResourceRegistry resourceRegistry;
@Override
public PhysicalJdbcTransaction getPhysicalJdbcTransaction() {
errorIfClosed();
return this;
}
protected void errorIfClosed() {
if ( !isOpen() ) {
throw new IllegalStateException( this.toString() + " is closed" );
}
}
@Override
public ResourceRegistry getResourceRegistry() {
return resourceRegistry;
}
@Override
public void afterStatement() {
log.trace( "LogicalConnection#afterStatement" );
}
@Override
public void afterTransaction() {
log.trace( "LogicalConnection#afterTransaction" );
resourceRegistry.releaseResources();
}
// PhysicalJdbcTransaction impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
protected abstract Connection getConnectionForTransactionManagement();
@Override
public void begin() {
try {
if ( !doConnectionsFromProviderHaveAutoCommitDisabled() ) {
log.trace( "Preparing to begin transaction via JDBC Connection.setAutoCommit(false)" );
getConnectionForTransactionManagement().setAutoCommit( false );
log.trace( "Transaction begun via JDBC Connection.setAutoCommit(false)" );
}
status = TransactionStatus.ACTIVE;
}
catch( SQLException e ) {
throw new TransactionException( "JDBC begin transaction failed: ", e );
}
}
@Override
public void commit() {
try {
log.trace( "Preparing to commit transaction via JDBC Connection.commit()" );
getConnectionForTransactionManagement().commit();
status = TransactionStatus.COMMITTED;
log.trace( "Transaction committed via JDBC Connection.commit()" );
}
catch( SQLException e ) {
status = TransactionStatus.FAILED_COMMIT;
throw new TransactionException( "Unable to commit against JDBC Connection", e );
}
afterCompletion();
}
protected void afterCompletion() {
// by default, nothing to do
}
protected void resetConnection(boolean initiallyAutoCommit) {
try {
if ( initiallyAutoCommit ) {
log.trace( "re-enabling auto-commit on JDBC Connection after completion of JDBC-based transaction" );
getConnectionForTransactionManagement().setAutoCommit( true );
status = TransactionStatus.NOT_ACTIVE;
}
}
catch ( Exception e ) {
log.debug(
"Could not re-enable auto-commit on JDBC Connection after completion of JDBC-based transaction : " + e
);
}
}
@Override
public void rollback() {
try {
log.trace( "Preparing to rollback transaction via JDBC Connection.rollback()" );
getConnectionForTransactionManagement().rollback();
status = TransactionStatus.ROLLED_BACK;
log.trace( "Transaction rolled-back via JDBC Connection.rollback()" );
}
catch( SQLException e ) {
status = TransactionStatus.FAILED_ROLLBACK;
throw new TransactionException( "Unable to rollback against JDBC Connection", e );
}
afterCompletion();
}
protected static boolean determineInitialAutoCommitMode(Connection providedConnection) {
try {
return providedConnection.getAutoCommit();
}
catch (SQLException e) {
log.debug( "Unable to ascertain initial auto-commit state of provided connection; assuming auto-commit" );
return true;
}
}
@Override
public TransactionStatus getStatus(){
return status;
}
protected boolean doConnectionsFromProviderHaveAutoCommitDisabled() {
return false;
}
}
有人可以帮我解决这个问题吗?非常感谢。
这是我的 pom.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lc</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
如果您使用 Spring 交易,您可以利用 TransactionSynchronization
并使用 afterCommit()
default void afterCommit()
Invoked after transaction commit. Can perform further operations right
after the main transaction has successfully committed.
用法:
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
void afterCommit(){
//do your thing
}
})
您还可以探索 TransactionSynchronizationAdapter
- in a similar way you can implement you own "AfterCommitExecutor" that implements the Executor
interface and extends TransactionSynchronizationAdapter and overrides the afterCommit()
方法。
我使用了 hovanessyan 的答案并且有效,现在让我完整地描述一下我在这里所做的事情:
我试图将其他人的代码迁移到springboot,代码使用带persistence.xml的hibernate并且拦截器使用threadlocal存储事务中的所有实体,当事务提交时,选择一个"best" 实体发送给用户,否则什么都不做并清除线程本地,代码是:
public class MyInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = -7992825362361127331L;
//The MyThreadLocal used to store all the entities in a transaction, when the transaction
//committed, the interceptor will choose the "best" entity to email user
private static MyThreadLocal myThreadLocal;
public static void setMyThreadLocal(MyThreadLocal mTL) {
MyInterceptor.myThreadLocal = mTL;
}
@Override
public void afterTransactionCompletion(Transaction tx) {
TransactionStatus status = tx.getStatus();
if (tx.getStatus() == COMMITTED) {
MyThreadLocal.selectTheBestEntityToEmailUser();
} else {
MyThreadLocal.clear();
}
}
@Override
public void beforeTransactionCompletion(Transaction tx) {
TransactionStatus status = tx.getStatus();
MyThreadLocal.beforeTransactionCompletion();
}
@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
MyThreadLocal.resourceAdded((Entity) entity);
return false;
}
@Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
Diff diff = new Diff(previousState, currentState, propertyNames);
MyThreadLocal.resourceUpdated((Entity) entity, diff);
return false;
}
@Override
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
MyThreadLocal.resourceRemoved((Entity) entity);
}
@Override
public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {
if (!(collection instanceof PersistentCollection)) {
LOGGER.e("Unsupported collection type: {}", collection.getClass());
return;
}
Entity owner = (Entity) ((PersistentCollection) collection).getOwner();
String role = ((PersistentCollection) collection).getRole();
MyThreadLocal.collectionResourceUpdated(owner, role);
}
}
但是在afterTransactionCompletion()方法中,交易状态一直是NOT_ACTIVE,现在我用TransactionSynchronization接口来代替afterTransactionCompletion()方法:
public class MyInterceptor extends EmptyInterceptor implements TransactionSynchronization {
//the mothod of TransactionSynchronization interface
@Override
public void afterCompletion(int status) {
if (status == STATUS_COMMITTED) {
MyThreadLocal.selectTheBestEntityToEmailUser();
} else {
MyThreadLocal.clear();
}
}
//the old code which works not well
@Override
public void afterTransactionCompletion(Transaction tx) {
TransactionStatus status = tx.getStatus();
if (tx.getStatus() == COMMITTED) {
MyThreadLocal.selectTheBestEntityToEmailUser();
} else {
MyThreadLocal.clear();
}
}
...... other codes
}
并且新的拦截器也需要通过AOP全局配置:
@Component
@Aspect
public class InterceptorInit{
@Autowired
private MyInteceptor mI;
@Before("@annotation(org.springframework.transaction.annotation.Transactional)")
public void registerTransactionSyncrhonization() {
TransactionSynchronizationManager.registerSynchronization(mI);
}
}
现在看来一切正常,我会继续测试
虽然我也建议使用 Spring TransactionSynchronization。如果不能使用(或不想使用),有两点需要注意:
beforeTransactionCompletion - “在提交事务之前调用(但不在回滚之前)。” - 这意味着此方法实际上可用于在提交之前识别事务是否正常,并将其保存在某个临时(理想情况下是 ThreadLocal)状态。
afterTransactionCompletion - 如果事务被回滚,事务的状态不是“NOT_ACTIVE”而是“MARKED_ROLLBACK” - 因此状态“NOT_ACTIVE”与实际调用的 beforeTransactionCompletion 可用于确定交易是否成功。
我想在 spring 启动时使用休眠拦截器,以便在事务提交后使用 afterTransactionCompletion()
方法做一些事情。
我按照How to use Spring managed Hibernate interceptors in Spring Boot配置(我只是在application.properties
中添加spring.jpa.properties.hibernate.ejb.interceptor=com.lc.demo.inteceptor.MyInteceptor
)
拦截器工作了,但是当我试图在方法afterTransactionCompletion()
中获取交易状态时仍然有问题,它总是NOT_ACTIVE
(我希望它可以是COMMITTED
):
import static org.hibernate.resource.transaction.spi.TransactionStatus.COMMITTED;
import org.hibernate.EmptyInterceptor;
import org.hibernate.Transaction;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.springframework.stereotype.Component;
@Component
public class MyInteceptor extends EmptyInterceptor{
private static final long serialVersionUID = -7992825362361127331L;
@Override
public void afterTransactionCompletion(Transaction tx) {
//The status is always NOT_ACTIVE
TransactionStatus status = tx.getStatus(); //
if (tx.getStatus() == COMMITTED) {
System.out.println("This is what I want to do");
} else {
System.out.println("This is what I do not want");
}
}
@Override
public void beforeTransactionCompletion(Transaction tx) {
// The status is ACTIVE
TransactionStatus status = tx.getStatus();
System.out.println(status);
}
}
我尝试调试它,发现在 afterTransactionCompletion()
被调用之前,
在扩展AbstractLogicalConnectionImplementor
的org.hibernate.resource.jdbc.internal.LogicalConnectionProvidedImpl
中,commit()
方法调用afterCompletion()
方法调用resetConnection(boolean initiallyAutoCommit)
设置事务状态NOT_ACTIVE
:
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.resource.jdbc.internal;
import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.TransactionException;
import org.hibernate.resource.jdbc.ResourceRegistry;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.resource.jdbc.spi.PhysicalJdbcTransaction;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
*/
public abstract class AbstractLogicalConnectionImplementor implements LogicalConnectionImplementor, PhysicalJdbcTransaction {
private static final Logger log = Logger.getLogger( AbstractLogicalConnectionImplementor.class );
private TransactionStatus status = TransactionStatus.NOT_ACTIVE;
protected ResourceRegistry resourceRegistry;
@Override
public PhysicalJdbcTransaction getPhysicalJdbcTransaction() {
errorIfClosed();
return this;
}
protected void errorIfClosed() {
if ( !isOpen() ) {
throw new IllegalStateException( this.toString() + " is closed" );
}
}
@Override
public ResourceRegistry getResourceRegistry() {
return resourceRegistry;
}
@Override
public void afterStatement() {
log.trace( "LogicalConnection#afterStatement" );
}
@Override
public void afterTransaction() {
log.trace( "LogicalConnection#afterTransaction" );
resourceRegistry.releaseResources();
}
// PhysicalJdbcTransaction impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
protected abstract Connection getConnectionForTransactionManagement();
@Override
public void begin() {
try {
if ( !doConnectionsFromProviderHaveAutoCommitDisabled() ) {
log.trace( "Preparing to begin transaction via JDBC Connection.setAutoCommit(false)" );
getConnectionForTransactionManagement().setAutoCommit( false );
log.trace( "Transaction begun via JDBC Connection.setAutoCommit(false)" );
}
status = TransactionStatus.ACTIVE;
}
catch( SQLException e ) {
throw new TransactionException( "JDBC begin transaction failed: ", e );
}
}
@Override
public void commit() {
try {
log.trace( "Preparing to commit transaction via JDBC Connection.commit()" );
getConnectionForTransactionManagement().commit();
status = TransactionStatus.COMMITTED;
log.trace( "Transaction committed via JDBC Connection.commit()" );
}
catch( SQLException e ) {
status = TransactionStatus.FAILED_COMMIT;
throw new TransactionException( "Unable to commit against JDBC Connection", e );
}
afterCompletion();
}
protected void afterCompletion() {
// by default, nothing to do
}
protected void resetConnection(boolean initiallyAutoCommit) {
try {
if ( initiallyAutoCommit ) {
log.trace( "re-enabling auto-commit on JDBC Connection after completion of JDBC-based transaction" );
getConnectionForTransactionManagement().setAutoCommit( true );
status = TransactionStatus.NOT_ACTIVE;
}
}
catch ( Exception e ) {
log.debug(
"Could not re-enable auto-commit on JDBC Connection after completion of JDBC-based transaction : " + e
);
}
}
@Override
public void rollback() {
try {
log.trace( "Preparing to rollback transaction via JDBC Connection.rollback()" );
getConnectionForTransactionManagement().rollback();
status = TransactionStatus.ROLLED_BACK;
log.trace( "Transaction rolled-back via JDBC Connection.rollback()" );
}
catch( SQLException e ) {
status = TransactionStatus.FAILED_ROLLBACK;
throw new TransactionException( "Unable to rollback against JDBC Connection", e );
}
afterCompletion();
}
protected static boolean determineInitialAutoCommitMode(Connection providedConnection) {
try {
return providedConnection.getAutoCommit();
}
catch (SQLException e) {
log.debug( "Unable to ascertain initial auto-commit state of provided connection; assuming auto-commit" );
return true;
}
}
@Override
public TransactionStatus getStatus(){
return status;
}
protected boolean doConnectionsFromProviderHaveAutoCommitDisabled() {
return false;
}
}
有人可以帮我解决这个问题吗?非常感谢。
这是我的 pom.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lc</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
如果您使用 Spring 交易,您可以利用 TransactionSynchronization
并使用 afterCommit()
default void afterCommit()
Invoked after transaction commit. Can perform further operations right after the main transaction has successfully committed.
用法:
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
void afterCommit(){
//do your thing
}
})
您还可以探索 TransactionSynchronizationAdapter
- in a similar way you can implement you own "AfterCommitExecutor" that implements the Executor
interface and extends TransactionSynchronizationAdapter and overrides the afterCommit()
方法。
我使用了 hovanessyan 的答案并且有效,现在让我完整地描述一下我在这里所做的事情:
我试图将其他人的代码迁移到springboot,代码使用带persistence.xml的hibernate并且拦截器使用threadlocal存储事务中的所有实体,当事务提交时,选择一个"best" 实体发送给用户,否则什么都不做并清除线程本地,代码是:
public class MyInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = -7992825362361127331L;
//The MyThreadLocal used to store all the entities in a transaction, when the transaction
//committed, the interceptor will choose the "best" entity to email user
private static MyThreadLocal myThreadLocal;
public static void setMyThreadLocal(MyThreadLocal mTL) {
MyInterceptor.myThreadLocal = mTL;
}
@Override
public void afterTransactionCompletion(Transaction tx) {
TransactionStatus status = tx.getStatus();
if (tx.getStatus() == COMMITTED) {
MyThreadLocal.selectTheBestEntityToEmailUser();
} else {
MyThreadLocal.clear();
}
}
@Override
public void beforeTransactionCompletion(Transaction tx) {
TransactionStatus status = tx.getStatus();
MyThreadLocal.beforeTransactionCompletion();
}
@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
MyThreadLocal.resourceAdded((Entity) entity);
return false;
}
@Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
Diff diff = new Diff(previousState, currentState, propertyNames);
MyThreadLocal.resourceUpdated((Entity) entity, diff);
return false;
}
@Override
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
MyThreadLocal.resourceRemoved((Entity) entity);
}
@Override
public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {
if (!(collection instanceof PersistentCollection)) {
LOGGER.e("Unsupported collection type: {}", collection.getClass());
return;
}
Entity owner = (Entity) ((PersistentCollection) collection).getOwner();
String role = ((PersistentCollection) collection).getRole();
MyThreadLocal.collectionResourceUpdated(owner, role);
}
}
但是在afterTransactionCompletion()方法中,交易状态一直是NOT_ACTIVE,现在我用TransactionSynchronization接口来代替afterTransactionCompletion()方法:
public class MyInterceptor extends EmptyInterceptor implements TransactionSynchronization {
//the mothod of TransactionSynchronization interface
@Override
public void afterCompletion(int status) {
if (status == STATUS_COMMITTED) {
MyThreadLocal.selectTheBestEntityToEmailUser();
} else {
MyThreadLocal.clear();
}
}
//the old code which works not well
@Override
public void afterTransactionCompletion(Transaction tx) {
TransactionStatus status = tx.getStatus();
if (tx.getStatus() == COMMITTED) {
MyThreadLocal.selectTheBestEntityToEmailUser();
} else {
MyThreadLocal.clear();
}
}
...... other codes
}
并且新的拦截器也需要通过AOP全局配置:
@Component
@Aspect
public class InterceptorInit{
@Autowired
private MyInteceptor mI;
@Before("@annotation(org.springframework.transaction.annotation.Transactional)")
public void registerTransactionSyncrhonization() {
TransactionSynchronizationManager.registerSynchronization(mI);
}
}
现在看来一切正常,我会继续测试
虽然我也建议使用 Spring TransactionSynchronization。如果不能使用(或不想使用),有两点需要注意:
beforeTransactionCompletion - “在提交事务之前调用(但不在回滚之前)。” - 这意味着此方法实际上可用于在提交之前识别事务是否正常,并将其保存在某个临时(理想情况下是 ThreadLocal)状态。
afterTransactionCompletion - 如果事务被回滚,事务的状态不是“NOT_ACTIVE”而是“MARKED_ROLLBACK” - 因此状态“NOT_ACTIVE”与实际调用的 beforeTransactionCompletion 可用于确定交易是否成功。