事务的属性
1.propagation 用来设置事务的传播行为
事务的传播行为:一个方法运行在了一个开启事务的方法中,当前方法是使用依附的方法事务还是使用自身的事务;
Propagation.REQUIRED默认值 使用其依附的别人方法的事务
Propagation.REQUIRES_NEW 将原来的事务挂起 开启一个新的事务(即执行自身的事务)
使用方法 在需要使用事务的方法上加注解 @Transactional 什么都不加默认为Propagation.REQUIRED
若想开启新事务执行自己的事务则可以在方法上加@Transactional(propagation=Propagation.REQUIRES_NEW)
2.isolation 用来设置事务的隔离级别
首先说一下为什么要使用事务的隔离级别。
数据库事务并发问题(假设现在有transaction1和transaction2两个事务并发执行)
⑴脏读(读取到了某个事物未提交的数据)
①transaction1将某条记录的AGE值从20改为了30。
②transaction2读取到transaction1更新后值:30。
③transaction1回滚,AGE值回滚为了20。
④transaction2读取的30就是一个无效的值。
(2)不可重复读 (某事务进行了两次读取,两次读取过程中另外一个事务进行了更新或删除提交,导致两次读取的数据不一致)
①transaction1读取到AGE:20。
②transaction2更新AGE:30(已提交)。
③transaction1再次读取:30,和第一次不一致。
(3)幻读(事务1进行了查询过程中,事务2进行了插入操作,导致事务1看到的数据变多了)
①Transaction01读取了STUDENT表中的一部分数据,并到出Excel
②Transaction02向STUDENT表中出入了新的数据
③Transaction01导出的Excel数据莫名其妙的多了一些数据
各个隔离级别解决并发问题的能力
- 读未提交 read uncommitted
- 读已提交 read commited
- (默认)可重复读 repeatable read
- 串行化 serializable
各种数据库产品对事务隔离级别的支持程度
总结
很多人容易搞混不可重复读和幻读,确实这两者有些相似。但不可重复读重点在于update和delete,而幻读的重点在于insert。
如果使用锁机制来实现这两种隔离级别,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会 发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免。
如果要解决幻读问题,需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。