Transactional注解不生效
- 检查你方法是不是public的,不能作用在方法里的任何内部方法。
- 数据库是否支持事务,比如mysql中innodb引擎支持事务,myisam引擎不支持事务。
- 检查异常是否被catch了。
优先级顺序为:方法>类>接口;
推荐在类的实现类使用。在接口使用如果是CGLIB,根据CGLIB代理模式,接口的注解不能被继承。
Spring事务4种隔离级别
read-uncommit : 两个事务,事务A修改了数据d,未提交,事务B能感知数据d的变化。
read-commit :事务A修改了数据d,提交了之后事务B才能感知数据d的变化。
repeatable-read :事务A修改了数据d,提交了之后,事务B仍然未能感知数据d的变化。
serializable :事务A在修改数据d时,未提交,事务B是无法访问数据d。(一个数据不能同时有两个事务操作,只能一个一个地操作。这就是串行)
read uncommit < read commit < repeatable read < serializable.
从左往右:一致性越来越强,性能越来越低。
Spring事务7种传播行为
propagation_required : 需要,存在事务就加入,否则创建事务。
propagation_supports: 支持,存在事务就加入,否则不创建事务。
propagation_mandatory:强制,存在事务就加入,否则抛异常。
propagation_required_new :需要新的,存在事务就创建新的,否则也创建新的。
propagation_not_supported:不支持,存在事务就挂起,否则不是事务。
propagation_never:坚决不,存在事务就抛异常,否则不是事务。
propagation_nested:内嵌,存在事务就内嵌,否则创建新的(外部有保存点)。
Spring如何确保开启事务的连接mybatis连接数据库使用的连接是同一个?
(如果不是同一个,那开启事务等于白开,有可能多个操作用的不是开启事务的那个连接)
目的:在一个线程下,一个事务的多个操作拿到的是同一个连接。
主要在TransactionSynchronizationManager里用ThreadLocal线程本地绑定connection。
bindResource(DataSource,ConnectionHolder)绑定以DataSource为key,ConnectionHolder为value的map到ThreadLocal线程本地。
getResource(DataSource) 然后mybatis根据DataSource就可以取得到Connection。
每个线程有一个线程本地map(ThreadLocalMap)。
解决思路:把connection与线程捆绑,一个线程最多能有一个connection,在一个线程内的一切操作都是在绑定当前线程的连接上操作的。
Spring为什么只能是单线程事务?多线程不行吗?
多线程失效案例:
一开始用jmeter开超过tomcat最大线程数并发请求,结果事务还是回滚了,所以这个还是可用的。 所以方法外多线程调用事务是安全的。
然后在方法里加入多线程处理,如下,
@Override
subMoney方法绝对会抛异常,所以这里事务要回滚的是setAge。
启动访问后,这里甚至没有报错。。。(没加多线程前是必定输出报错的,而且也会返回出错信息,但是现在没有。
)
多线程:
查遍这个日志,并没有找到报错的。
现象:注意这个 “”age“”字段,每次调用都会增加,说明该操作没有回滚。
解释:这是因为Spring的开启事务的连接是线程(ThreadLocal)私有的,每个线程不一定有事务。当没有事务的线程执行了操作,这是非事务的操作,不安全操作,异常不会回滚。
总结:在方法内的多线程操作,Spring会出现事务失效问题。但是方法外的多线程访问是没问题的。(jmeter多线程测试)
参考文章:
spring事务详解(五)总结提高 - 只会一点java - 博客园
spring管理mybatis事务的保证数据库连接唯一的原理 - 心藏三叶生一花 - 博客园