本文共 1673 字,大约阅读时间需要 5 分钟。
有时候一个业务需要多次操作数据库,比如转账
如果reduce()执行成功,add执行失败,那钱是转出去了,但对方并没有收到,钱转丢了,应该加事务。事务:逻辑上的一组操作,要么全部成功,要么全部失败。
事务的4个特性
如果没实现隔离性,事务并发执行时可能会出现以下问题
示例 B取款的同时,A转账给B 虽然2个事务是并发执行的,但实际执行具体语句时仍有先后顺序。
一个事务读取到另一个事务未提交的数据。
eg. 事务A读取到事务B未提交的数据,事务B执行失败回滚,事务A之前读到的数据变成无效数据,但事务A并不知道这是无效数据,用这些数据来操作。
隔离级别 Read commited 已提交读,可解决脏读问题,等到使用这些记录的事务提交后才读取数据。
前后多次读取,读取到的数据内容不一致(期间已被其它事务使用update修改)。
eg. 事务A持续时间长,需要多次从数据库读取数据,但期间其它事务对数据库中的这部分数据进行了修改,事务A前后读取的数据对不上,前后执行的操作也就有误。
隔离级别 Repeatable read 重复读,可解决不可重复读的问题,当有事务读了某些行的数据后,这些行会被锁住,不允许其它事务对这些行进行修改,这样重复读取到的数据就是一致的。
因为使用某些行时,这些行会被锁定,其它事务不能读取这些行,也避免了脏读问题。
前后多次读取,读取到的记录数不一致(期间其它事务使用insert、delete造成记录数变化)。
隔离级别 Serializable 可解决幻读问题,不允许事务并发,最安全,但性能最差,基本不用。
丢失更新是不可重复读中的一种特殊情况,2个事务都要修改记录内容(update),后提交的覆盖了前面提交的
可通过设置事务的隔离级别,来解决读问题。
事务的4种隔离级别
一般折中使用第2、3项,mysql默认用Repeatable read,oracle默认用Read committed,使用默认的即可。
数据库自身提供了4种事务隔离级别,spring还提供一种:
事务管理是添加在业务层的,如果service层的方法发生相互调用
public void a(){ //.... b(); //....}
被调b()可能添加了事务,如果要给主调a()添加事务,如何添加?
事务的传播行为:service层发生方法的相互调用时,如何处理给主调方法加的事务
spring中定义了7种事务传播行为,默认使用REQUIRED,这个也是最常用的。
事务是针对多个数据库操作的(dao层),dao层在service层调用,所以事务要加到service层的方法上。
mybatis的依赖中已经包含了事务管理,不需要额外导包,要对service层的某些业务方法使用事务,直接在方法上标注 @Transactional 即可。
转载地址:http://dzhlb.baihongyu.com/