在项目中遇到因为事务没有结束,导致插入表的操作将表给锁住了,关于这个表的其他接口也无法访问了。
解决过程:(救急解决)
在mysql新建查询
show processlist;
找到超时的sql语句,找对应线程
通过kill该线程
kill trx_mysql_thread_id
后期解决:
通过查看tomcat日志发现是某个接口里面发出http请求一直未收到响应,导致事务一直未结束,也导致该事务中的表被锁死。然后将该http请求放到线程中异步处理,解决了事务处理超时问题。应该也可以通过设置innodb_lock_wait_timeout的大小进行控制超时的时长(本人没有实验,查看资料,感觉应该可以)
在搜索表锁死的问题看到了一些关于事务回滚的问题(虽然没有遇到,但是也做一下小结)
如果将service的内部私有方法加上注解@Transational,并不能将该方法设为一个事务,事务不会回滚,因为Spring框架里面的事务是通过动态代理实现的,如果是内部私有方法只是该类的内部实例,并不在Spring的工厂里面,只有在外部被调用时,才会生成动态代理,所以也不会实现aop切面代码。
MySQL死锁导致未回滚
查看参数 innodb_rollback_on_timeout
show VARIABLES like 'innodb_rollback_on_timeout'
如果 innodb_rollback_on_timeout为ON,那么事务超时后将导致InnoDB终止并回滚整个事务;如果 innodb_rollback_on_timeout为OFF,那么事务超时后只回滚事务超时的最后一条语句。
嵌套事务
嵌套事务即内部,外部都有事务(如果有try catch但是没有把异常给扔出去)
- 内外都无try catch,事务正常回滚
- 外部try catch,内部异常,正常回滚,外部异常,回滚失败
- 内部有try catch,内部异常,回滚失败,外部异常,正常回滚
- 内外都有try catch,内部和外部异常,回滚都失败
正确做法是异常一定要抛出RuntimeException
事务的传播行为
事务传播行为类型 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED类 似的操作。 |