手写事务地址: https://gitee.com/huang_bao_se/hbz-transaction
Spring事务类型- 编程式事务:手动的去begin, commit, rollback这些操作,叫编程事务,代码会产生冗余,一大堆事务代码,但编程式事务并不是一无是处,他更灵活,某些情况还必须要使用编程事务。但如果编程式事务没用好,容易把数据锁住,即没执行【提交】或【回滚】
- 声明式事务:在方法上加上事务的注解@Transaction,这就是声明式事务
- 声明式事务提交时机:当方法执行完毕 并 没有【抛出异常】则就会提交吗,注意:抛出异常和出现异常时两回事,如果异常被捕获了,则依然不会回滚,底层是AOP的机制,自行用try…catch捕获,底层AOP是无法感知的,即也不会回滚,如果要写catch,则catch一定要加上如下代码
try{
...
}catch(Exception e){
// 手动回滚,AOP将事务缓存到了当前线程,所以直接根据当前线程获取该事务对象,回滚即可
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
// 或者直接抛出异常(不推荐,如果在catch还要抛异常,则也没有必要加try..catch了)
// throw new Exception();
}
- spring事务的默认传播机制:事务传播机制主要应用于A方法中调用B方法。spring默认的事务传播机制是A方法加了事务,则B方法会延用A方法的事务,如果A方法没有事务,则B方法会自行创建一个事务
- spring事务的默认隔离级别:spring事务的隔离了级别默认和Mysql一致,而Mysql的事务隔离级别是可重复读,所以spring的隔离级别也是可重复读。
- spring事务隔离级别比mysql多一个,多这一个就是与mysql 隔离机制相同这个级别,即mysql 如果更改了隔离级别,spring也会跟着更改,其余4个隔离级别和MySQL完全一致–>请看后面【spring事务隔离级别】
编程式事务的源码:
// 事务类
public class TestTransaction{
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
// 开启事务,并配置默认的事务传播机制
public TransactionStatus begin(){
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
return transaction;
}
// 提交事务
public void commit(TransactionStatus transactionStatus){
dataSourceTransactionManager.commit(transactionStatus);
}
// 回滚事务
public void rollback(TransactionStatus transactionStatus){
dataSourceTransactionManager.rollback(transactionStatus);
}
}
// 测试方法
public static void main(String arg[]){
TestTransaction testTransaction = new TestTransaction();
// 开启事务
TransactionStatus transaction = testTransaction .begin();
try{
// 执行sql
sql.updateDate(obj);
// 提交事务
testTransaction.commit(transaction );
}catch(Exception e){
// 回滚事务
testTransaction .rollback(transaction )
}
}
Spring事务隔离级别
-
ISOLATION_DEFAULT(spring事务的默认隔离级别):使用后端数据库默认的隔离级别。后端数据库是什么他就是什么隔离级别,后端数据库用【未提交读】,那spring也用未提交读。如果选可重复读,那即使数据库的级别是未提交读,那spring的事务也会是可重复读
-
ISOLATION_READ_UNCOMMITTED:未提交读
-
ISOLATION_READ_COMMITTED: 提交读
-
ISOLATION_REPEATABLE_READ: 不可重复读
-
ISOLATION_SERIALIZABLE:串行化
- REQUIRED(required默认属性)
如果A方法调用B方法,B方法需要事务,则如果A方法已经创建了事务,则B方法不会再创建事务,会支持A方法的事务,如果当前没有事务,才会重新创建一个新事物 - MANDATOR(mandator)
仅支持当前事务,如果当前没有事务,就会抛异常。如果A没创建事务,那么B还需要,那就会抛异常 - NEVER(never)
不能存在事务,如果当前有事务,会抛出异常,A方法创建了事务,B方法就会抛异常,因为是NEVER不允许有事务。 - REQUIRES_NEW(requires_new)
新建事务。如果当前存在事务,则当前事务挂起。即如果A创建了事务,B依然会创建事务,并且会挂起A的事务 - SUPPORTS(supports)
支持当前事务,如果当前没有事务,也不会创建事务,就直接执行了。即A方法创建了事务,B方法会使用这个事务。A没有创建事务,B就进行无事务操作,总之B不会创建新事物
- 访问权限不是public
- 加了final修饰,此时该方法不可被子类重写
- 方法内部调用,即A方法调用本类中B方法,事务加在B方法上,此时不生效,因为spring事务就是一个切面,通过动态代理对象进行事务,同方法调用是通过this,并不是动态代理类
- 自己类注入了自己对象,即A类中注入A类的对象,再通过A类对象调用带有事务的方法,此时不生效
- 未被spring管理,没有加到springIOC容器
- 多线程调用中
- 表本身不支持事务,比如使用了MyISAM
- 未开启事务
- 被try…catch捕捉了,而且还没手动抛异常
- spring的传播属性写错了,比如用了NEVER这种,根部就不让存在事务,那事务必然失效。默认是REQUIRED,是可以存在事务的。



