数据库事务学习练习总结
四个特性
原子性:操作一组指令,要么全部成功,要么全部失败。
一致性:比如转账,无论你做什么操作,最后的总钱数不会改变。
隔离性:两个事务并发进行,并发事务之间要相互隔离。
持久性:事务完成后,对数据的改变是永久的。
并发事务导致的问题
脏读:一个事务读取了另一个事务未提交的数据,之后未提交的事务回滚了。
幻读:一个事务执行两次,发现查询到的数据多了,或者少了。
不可重复度:事务A读取了一个数据 num = 1,事务A还没有提交,但是事务B修改 num = 2 提交了, 事务A再次读物num的时候,发现数据变了。
脏读和不可重复读的区别:脏读是A事务读取了B事务没有提交的数据,然后B事务回滚了
不可重复读是A事务读取了B事务没有提交和提交后的数据。
事务的隔离级别
读未提交:顾名思义,就是一个事务可以读取到另一个事务没有提交的事务,可能出现脏读。
解决:Read committed (读提交)
读提交:就是一个事务需要等到另一个事务提交之后才能读取数据,可能会出现不可重复读。
解决:Repeatable read(重复读)
重复度:开始读取数据的时候(事务开启),不再允许修改操作。但是可能会出现幻读。(mysql不存在幻读,因为mysql的innodb引擎实现RR的时候加了间隙锁)
解决:serializable (序列化)
序列化:最高级别的事务隔离级别,事务串行化顺序执行。(一般不使用)
事务的七大传播行为
PROPAGATION_REQUIRED: A事务方法调用B事务方法,如果A事务方法的事务存在,那么B事务就 在A事务中运行,如果A事务不存在,那么就新建一个事务运行。
回滚:
A事务如果存在,B事务就和A事务共用一个事务,那么无论哪儿发生异常,AB都会回滚
A方法事务如果不存在,B事务会新建一个事务,那么只有B方法发生异常,才会导致B事 务回滚,A方法不受影响。
PROPAGATION_REQUIRES_NEW:A事务方法调用B事务方法,不管A事务是否存在,都会新建一个 事务来运行B事务。
回滚:如果B事务发生异常,A事务也会跟着回滚
如果A事务发生异常,B事务不会跟着回滚
上面两个是最常用的两种事务。
PROPAGATION_SUPPORTS: 支持当前事务,假设当前没有事务,就以非事务方式运行
PROPAGATION_MANDATORY:支持当前事务,假设当前没有事务,就抛出异常
PROPAGATION_NOT_SUPPORTED:以非事务方式运行操作。假设当前存在事务,就把当前事务挂起
PROPAGATION_NEVER:以非事务方式运行,假设当前存在事务,则抛出异常
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED类似的操作。
事务方法的嵌套调用问题:
在一个service内部,事务方法之间的嵌套调用,普通方法和事务方法之间的嵌套调用,都不会开启新的事务,因为spring的事务是通过动态代理实现的,但是动态代理最后都是要用原始对象调用方法的,原始对象调用就不会再次触发代理了。
解决方法:用代理对象去调用,spring的ioc用的就是动态代理,用@AutoWride注入的对象去调用这个方法就可以了。
MYSQL行锁表锁
用一个没有索引的字段做条件-----------表锁
这个事务还没提交,我又发起一个事务
这个事务就会等待上一个事务释放锁,但是我这儿更新的不是同一行。所以应该是表锁。
用主键做条件
再发起一个更新请求:
提交成功了!!
再试试修改同一行的数据:
再发起一个修改请求:
嘿嘿嘿:果然在等待锁。
如果用其他的索引做条件呢??
修改同一行数据会出现等待锁的现象。
但修改不同行的数据不会
所以innodb的表锁行锁问题:如果普通的crud是表锁,但是如果索引生效的crud就是行锁