spring的传播特性: (PROPAGATION是传播的意思)
PROPAGATION_REQUIRED,
PROPAGATION_SUPPORTS,
PROPAGATION_MANDATORY,
PROPAGATION_REQUIRES_NEW,
PROPAGATION_NOT_SUPPORTED,
PROPAGATION_NEVER,
PROPAGATION_NESTED
class A{
methodA(){
//逻辑处理
b.methodB();
//逻辑处理
}
}
class B{
methodB();
}
1.PROPAGATION_REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
/**
* Support a current transaction; create a new one if none exists.
* Analogous to the EJB transaction attribute of the same name.
* <p>This is typically the default setting of a transaction definition,
* and typically defines a transaction synchronization scope.
*/
int PROPAGATION_REQUIRED = 0;
翻译:
支持一个当前的事务,如果没有事务则创建一个新的事务;这通常是一个事务定义的默认设置,并且通常限定了事务同步范围
解释:
当A.methodA()和B.methodB()都打上REQUIRED的事务标志,执行A.methodA()方法的时候,看到上下文没有事务,会新建一个事务,当执行到b.methodB()的时候,发现上下文已经有事务了,则不会新建事务,用A.methodA()新建的那个事务。
如果b.methodB()执行成功,a.methodA()执行失败,那么b.methodB()和a.methodA()都会回滚(用的都是a.methodA()的事务)
2.PROPAGATION_SUPPORTS:如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
/**
* Support a current transaction; execute non-transactionally if none exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> For transaction managers with transaction synchronization,
* {@code PROPAGATION_SUPPORTS} is slightly different from no transaction
* at all, as it defines a transaction scope that synchronization might apply to.
* As a consequence, the same resources (a JDBC {@code Connection}, a
* Hibernate {@code Session}, etc) will be shared for the entire specified
* scope. Note that the exact behavior depends on the actual synchronization
* configuration of the transaction manager!
* <p>In general, use {@code PROPAGATION_SUPPORTS} with care! In particular, do
* not rely on {@code PROPAGATION_REQUIRED} or {@code PROPAGATION_REQUIRES_NEW}
* <i>within</i> a {@code PROPAGATION_SUPPORTS} scope (which may lead to
* synchronization conflicts at runtime). If such nesting is unavoidable, make sure
* to configure your transaction manager appropriately (typically switching to
* "synchronization on actual transaction").
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
*/
int PROPAGATION_SUPPORTS = 1;
翻译
支持当前事务; 如果不存在,则以非事务方式执行。 类似于同名的EJB事务属性。
注意:对于具有事务同步的事务管理器,PROPAGATION_SUPPORTS与完全没有事务稍有不同,因为它定义了同步可能适用的事务范围。 因此,相同的资源(JDBC连接,Hibernate会话等)将被共享给整个指定的范围。 请注意,确切的行为取决于事务管理器的实际同步配置!
一般来说,请小心使用PROPAGATION_SUPPORTS! 特别是,不要依赖PROPAGATION_SUPPORTS范围内的PROPAGATION_REQUIRED或PROPAGATION_REQUIRES_NEW(这可能会导致运行时出现同步冲突)。 如果这种嵌套是不可避免的,请确保正确配置事务管理器(通常切换到“实际事务同步”)。
解释:
当B.methodB()打上PROPAGATION_SUPPORTS的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则b.methodB()沿用该事务,反之b.methodB()就以非事物的方式执行。
3.PROPAGATION_MANDATORY:如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
MANDATORY是强制的,命令的意思,放在这里就是强制需要一个事务。
/**
* Support a current transaction; throw an exception if no current transaction
* exists. Analogous to the EJB transaction attribute of the same name.
* <p>Note that transaction synchronization within a {@code PROPAGATION_MANDATORY}
* scope will always be driven by the surrounding transaction.
*/
int PROPAGATION_MANDATORY = 2;
翻译
支持当前事务; 如果没有当前事务存在,则抛出异常。 类似于同名的EJB事务属性。
请注意,PROPAGATION_MANDATORY范围内的事务同步将始终由周围事务驱动。
解释:
当B.methodB()打上PROPAGATION_MANDATORY的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则b.methodB()沿用该事务,如果没有,则会抛出异常
4.PROPAGATION_REQUIRES_NEW:总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起
/**
* Create a new transaction, suspending the current transaction if one exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager}
* to be made available it to it (which is server-specific in standard J2EE).
* <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
* transaction synchronizations. Existing synchronizations will be suspended
* and resumed appropriately.
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
int PROPAGATION_REQUIRES_NEW = 3;
翻译
创建一个新的事务,如果存在,暂停当前事务。 类似于同名的EJB事务属性。
注意:实际的事务暂停将无法在所有事务管理器上直接使用。 实际的事务暂停将无法在所有事务管理器上开箱即用。
这特别适用于org.springframework.transaction.jta.JtaTransactionManager,它要求使javax.transaction.TransactionManager可用(它是标准Java EE中的服务器特定的)。
PROPAGATION_REQUIRES_NEW范围始终定义自己的事务同步。 现有的同步将被暂停并恢复正常
解释:
当B.methodB()打上PROPAGATION_REQUIRES_NEW的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则会挂起A.methodA()的事务,新建一个属于b.methodB()的事务,当b.methodB()的事务执行结束的时候,则会唤醒A.methodA()的事务。
和PROPAGATION_REQUIRED的差别在于回滚,当b.methodB()的事务提交后,A.methodA()执行失败,只会回滚A.methodA不会回滚b.methodB(),当b.methodB()执行失败,异常被A.methodA()方法catch到的话,A.methodA()事务不会回滚。
5.PROPAGATION_NOT_SUPPORTED:总是非事务地执行,并挂起任何存在的事务
/**
* Do not support a current transaction; rather always execute non-transactionally.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager}
* to be made available it to it (which is server-specific in standard J2EE).
* <p>Note that transaction synchronization is <i>not</i> available within a
* {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations
* will be suspended and resumed appropriately.
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
int PROPAGATION_NOT_SUPPORTED = 4;
翻译
不支持当前事务; 而总是执行非事务性的。 类似于同名的EJB事务属性。
注意:实际的事务暂停将无法在所有事务管理器上直接使用。
这特别适用于org.springframework.transaction.jta.JtaTransactionManager,它要求使javax.transaction.TransactionManager可用(它是标准Java EE中的服务器特定的)。
请注意,事务同步在PROPAGATION_NOT_SUPPORTED范围内不可用。 现有的同步将被暂停并恢复正常。
解释:
当B.methodB()打上PROPAGATION_NOT_SUPPORTED的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则会挂起A.methodA()的事务,当执行完b.methodB()方法的时候,A.methodA()方法继续以事务的方式执行
6.PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
/**
* Do not support a current transaction; throw an exception if a current transaction
* exists. Analogous to the EJB transaction attribute of the same name.
* <p>Note that transaction synchronization is <i>not</i> available within a
* {@code PROPAGATION_NEVER} scope.
*/
int PROPAGATION_NEVER = 5;
翻译
不支持当前事务; 如果当前事务存在,则抛出异常。 类似于同名的EJB事务属性。
请注意,事务同步在PROPAGATION_NEVER范围内不可用。
解释:
当B.methodB()打上PROPAGATION_NEVER的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果有事务,则抛出异常,如果没有则以非事务执行
7.PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, PROPAGATION_REQUIRED 属性执行
/**
* Execute within a nested transaction if a current transaction exists,
* behave like {@link #PROPAGATION_REQUIRED} else. There is no analogous
* feature in EJB.
* <p><b>NOTE:</b> Actual creation of a nested transaction will only work on
* specific transaction managers. Out of the box, this only applies to the JDBC
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
* when working on a JDBC 3.0 driver. Some JTA providers might support
* nested transactions as well.
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
int PROPAGATION_NESTED = 6;
翻译
如果当前事务存在,则在嵌套事务内执行,其行为类似于PROPAGATION_REQUIRED 。 EJB中没有类似的功能。
注意:实际创建嵌套事务只适用于特定事务管理器。
开箱即用,这只适用于在处理JDBC 3.0驱动程序时使用JDBC org.springframework.jdbc.datasource.DataSourceTransactionManager。 一些JTA提供者也可能支持嵌套事务。
解释:
当B.methodB()打上 PROPAGATION_REQUIRED的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,如果A.methodA()方法有事务,则会创建一个依赖于当前事务的嵌套事务,如果 b.methodB()执行失败,只会回滚 b.methodB(),不会回滚A.methodA(),只有当A.methodA()执行完成后才会提交b.methodB()的事务,因为嵌套事务不能单独提交;如果A.methodA()回滚了,则会导致内部嵌套事务的回滚。如果A.methodA()方法没有事务,就会新建一个事务;
事务隔离级别:
ISOLATION_DEFAULT,
ISOLATION_READ_UNCOMMITTED,
ISOLATION_READ_COMMITTED,
ISOLATION_REPEATABLE_READ,
ISOLATION_SERIALIZABLE
虚幻读 :一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致.
不可重复读 :一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致.
什么是脏读?
一个事务读到了另一个事务的未提交的数据
例如:
张三的工资为5000,事务A中把他的工资改为8000,但事务A尚未提交。
与此同时,
事务B正在读取张三的工资,读取到张三的工资为8000。
随后,
事务A发生异常,而回滚了事务。张三的工资又回滚为5000。
最后,
事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。
什么是幻读?
一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致.
例如:
目前工资为5000的员工有10人,事务A读取所有工资为5000的人数为10人。
此时,
事务B插入一条工资也为5000的记录。
这是,事务A再次读取工资为5000的员工,记录为11人。此时产生了幻读。
什么是不可重复读?
一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致.
例如:
在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。
与此同时,
事务B把张三的工资改为8000,并提交了事务。
随后,
在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。
提醒:
不可重复读的重点是修改,同样的条件,你读取过的数据,再次读取出来发现值不一样了
幻读的重点在于新增或者删除,同样的条件,第 1 次和第 2 次读出来的记录数不一样
不可重复读的和幻读很容易混淆,不可重复读侧重于修改update(行级别-通过行锁可以来控制),幻读侧重于新增或删除insert/delete(表级别-通过表锁来控制)。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
【幻读和不可重复读的区别如下:】参考博客:spring事务的隔离级别。如何避免脏读或者幻读_spring 事务的隔离级别有什么不足,怎么解决-优快云博客
数据库默认事务隔离级别
MYSQL:
InnoDB引擎的锁机制:InnoDB支持事务,支持行锁和表锁用的比较多,Myisam不支持事务,只支持表锁。
Mysql 在InnoDB引擎下默认:可重复读 ISOLATION_REPEATABLE_READ;通过加行锁,可以解决掉脏读、不可重复读
Oracle 默认:读已提交ISOLATION_READ_COMMITTED
1.ISOLATION_DEFAULT:这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别
/**
* Use the default isolation level of the underlying datastore.
* All other levels correspond to the JDBC isolation levels.
* @see java.sql.Connection
*/
int ISOLATION_DEFAULT = -1;
翻译
使用底层数据存储的默认隔离级别。 所有其他级别对应于JDBC隔离级别。
2. ISOLATION_READ_UNCOMMITTED :这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻读。
/**
* Indicates that dirty reads, non-repeatable reads and phantom reads
* can occur.
* <p>This level allows a row changed by one transaction to be read by another
* transaction before any changes in that row have been committed (a "dirty read").
* If any of the changes are rolled back, the second transaction will have
* retrieved an invalid row.
* @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
*/
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
翻译
表示可能发生脏读,不可重复读和幻读。
这个级别允许一个事务改变的行被另一个事务读取,然后该行的任何改变被提交(“脏读”)。 如果任何更改回滚,则第二个事务将检索到无效行。
3. ISOLATION_READ_COMMITTED :保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
/**
* Indicates that dirty reads are prevented; non-repeatable reads and
* phantom reads can occur.
* <p>This level only prohibits a transaction from reading a row
* with uncommitted changes in it.
* @see java.sql.Connection#TRANSACTION_READ_COMMITTED
*/
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
翻译
指示防止脏读; 不可重复读取和幻像读取可能发生。
这个级别只禁止一个事务读取一行,并在其中有未提交的变化
4. ISOLATION_REPEATABLE_READ :这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
/**
* Indicates that dirty reads and non-repeatable reads are prevented;
* phantom reads can occur.
* <p>This level prohibits a transaction from reading a row with uncommitted changes
* in it, and it also prohibits the situation where one transaction reads a row,
* a second transaction alters the row, and the first transaction re-reads the row,
* getting different values the second time (a "non-repeatable read").
* @see java.sql.Connection#TRANSACTION_REPEATABLE_READ
*/
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
翻译
指示防止脏读和不可重复读取; 幻读取可能会发生。
这个级别禁止一个事务读取一个没有提交变化的行,它也禁止如下情况:一个事务读取一行,
第二个事务改变行,第一个事务重新读取行,第二次获取不同的值(“不可重复读取”)。
5. ISOLATION_SERIALIZABLE :这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。
/**
* Indicates that dirty reads, non-repeatable reads and phantom reads
* are prevented.
* <p>This level includes the prohibitions in {@link #ISOLATION_REPEATABLE_READ}
* and further prohibits the situation where one transaction reads all rows that
* satisfy a {@code WHERE} condition, a second transaction inserts a row
* that satisfies that {@code WHERE} condition, and the first transaction
* re-reads for the same condition, retrieving the additional "phantom" row
* in the second read.
* @see java.sql.Connection#TRANSACTION_SERIALIZABLE
*/
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
翻译
表示禁止脏读,不可重复读取和幻像读取。
该级别包括ISOLATION_REPEATABLE_READ中的禁止条件,并进一步禁止如下的情况:一个事务读取满足WHERE条件的所有行,第二个事务插入一条满足该WHERE条件的行,
并且第一个事务以这些相同的条件重新读取,在第二次读取中检索另外的“幻像”行。
源码解析
TransactionDefinition:事务的定义接口
DefaultTransactionDefinition:TransactionDefinition 的一个实现类
就是对上述属性设置一些默认值,默认的传播特性为PROPAGATION_REQUIRED ,隔离级别为ISOLATION_DEFAULT
TransactionAttribute接口:定义对什么类型的异常进行回滚
DefaultTransactionAttribute:TransactionAttribute的实现类
指明了默认对RuntimeException 和Error都进行回滚
事务模板类TransactionTemplate(这个不常用,通常用Spring的AOP管理事务)
他的核心是里面有PlatformTransactionManager 这个事务管理类,用它来对事务提交和回滚。我们的业务逻辑只要写在TransactionCallback.doInTransaction()方法里面既可以,每次执行这个方法前,先会transactionManager.getTransaction(this)开启一 个事务,执行TransactionCallback.doInTransaction()异常的话会调用transactionManager.rollback(status)来回滚事务,正确的话就会调用transactionManager.commit(status)提交事务;
public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean {
protected final Log logger = LogFactory.getLog(this.getClass());
private PlatformTransactionManager transactionManager;
public TransactionTemplate() {
}
public TransactionTemplate(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public TransactionTemplate(PlatformTransactionManager transactionManager, TransactionDefinition transactionDefinition) {
super(transactionDefinition);
this.transactionManager = transactionManager;
}
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public PlatformTransactionManager getTransactionManager() {
return this.transactionManager;
}
public void afterPropertiesSet() {
if(this.transactionManager == null) {
throw new IllegalArgumentException("Property 'transactionManager' is required");
}
}
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
if(this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action);
} else {
TransactionStatus status = this.transactionManager.getTransaction(this);
Object result;
try {
result = action.doInTransaction(status);//业务逻辑代码写在这里
} catch (RuntimeException var5) {
this.rollbackOnException(status, var5);
throw var5;
} catch (Error var6) {
this.rollbackOnException(status, var6);
throw var6;
} catch (Exception var7) {
this.rollbackOnException(status, var7);
throw new UndeclaredThrowableException(var7, "TransactionCallback threw undeclared checked exception");
}
this.transactionManager.commit(status);
return result;
}
}
private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
this.logger.debug("Initiating transaction rollback on application exception", ex);
try {
this.transactionManager.rollback(status);
} catch (TransactionSystemException var4) {
this.logger.error("Application exception overridden by rollback exception", ex);
var4.initApplicationException(ex);
throw var4;
} catch (RuntimeException var5) {
this.logger.error("Application exception overridden by rollback exception", ex);
throw var5;
} catch (Error var6) {
this.logger.error("Application exception overridden by rollback error", ex);
throw var6;
}
}
}
基于上面的模板类,我们可以这样来实现数据库的事务,把每个逻辑都写在TransactionCallback.doInTransaction()方法里面,他会自动帮我们提交事务
TransactionTemplate transactionTemplate=new TransactionTemplate();
transactionTemplate.setTransactionManager(platformTransactionManager);
transactionTemplate.execute(new TransactionCallback<String>() {
@Override
public String doInTransaction(TransactionStatus status) {
//数据库操作
return "success";
}
});
但是这样会使每个数据库方法都要要写到TransactionCallback.doInTransaction(),其实耦合度还是很高。Spring于是推出了他的AOP管理事务!!!