目录
特性
原子性:事物是数据库的逻辑工作单位,事物中包含的各个操作要么都成功要么都失败。
一致性:同一时空,事物执行前和执行后都必须处于一致性状态。比如 A B 在事物前钱数加在一起为1000元,那么不管事物中他们如何转账,事物结束后他们的钱加在一起都是1000元
隔离性:不同事物间相互隔离
持久性:事物一旦提交,那么就会写入数据库中
隔离模式
读未提交(Read uncommitted)
读未提交级别忽略其它事务放置的锁。
事物可以读到其他事物未提交的结果,会造成脏读、幻读、不可重复读
读已提交(Read committed)Oracle默认
别人提交了的事物才能够读到,这样能够避免脏读。但不能避免幻读和 不可重复读
可重复读(Repeatable read)MySQL默认
当前事物不能读到其他事物提交的结果,避免脏读和不可重复读,但无法避免幻读。
也会有会有更新丢失(第二类)的情况
串行化(Serializable)
事物排队处理,这样就不可能有两个事物同时操作的情况
隔离性引发的问题
脏读
脏读:事物A读到了事物B未提交的数据,然后事物B又回滚了(虚晃一下)
开启事物A | 开启事物B |
更新id为1的数据:保存money = 1000 | |
查询id为1的数据:money为1000 | |
回滚事物 |
不可重复读
不可重复读:事物A多次读取数据,但是中间事物B把数据修改了,这时事物A又读了一下这条数据,结果此次读到的数据与之前读的数据不同。
开启事物A | 开启事物B |
查询id为1的数据:money为0 | |
更新id为1的数据:保存money = 1000 | |
提交事物 | |
再次查询id为1的数据:money为1000 |
幻读
幻读:A事物批量查询数据的时候第一次查到两条,B事物插入两条数据,A事物再次批量查询发现查到了四条数据,与之前查到的数据不一致。
开启事物A | 开启事物B |
统计money总数为100 | |
插入id为100的数据:保存money = 1000 | |
提交事物B | |
再次统计统计money总数为1100 |
更新丢失(第二类)
开启事物A | |
修改age = 100 | 开启事物B |
提交事物 | 修改age = 200 |
提交事物 |
如表所示,事物A提交后,接着事物B马山提交,那么A更新的东西就会丢失。
如何避免:对于更新丢失可以在事物前上锁:乐观锁、悲观锁
悲观锁:
开启事物A | 开启事物A |
对Id为1加for update锁 | |
对数据进行操作 | 读取id为1的数据的锁,会阻塞读 |
commit | ... |
查询到id为1的数据 |
事物A:开启事物后,获取事物的锁
select * from test where id = 1 for update;
事物B:由于事物A已经获取到了id为1的数据的锁,所以事物B会阻塞,直到事物A提交
关于不可重复读与幻读
不可重复读和幻读有点像,都是一边在查询一边在修改导致的数据不一致问题。不可重复读针对的是update场景,幻读针对的是insert和delete的场景。
总结
一张老图
隔离级别越高安全度越高,但是并发性越差。