事务就是一组应该一起成功或一起失败的SQL语句。

事务的ACID特性

名称 简介 举例
Atomicity原子性 所有的SQL语句要么全部成功,要么全部失败,不会存在部分更新。 假设有以下场景,A转账100元给B。这里有两个动作:一是A账号减少100元,二是B账号增加100元,这两个动作不可分割。
Consistency一致性 事务只能以允许的方式改变受其影响的数据。 假设A和B两者的钱加在一起一共100元,那么无论A和B之间如何转账,转几次账,事务结束后两个用户的钱加起来一定还是100元。
Isolation隔离性 同时发生的事务(并发事务)不应该导致数据库出于不一致的状态中。系统中每个事务都应该像唯一事务一样执行。任何事务都不应影响其他事务的存在。 隔离性即是要达到这样一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
Durability持久性 无论数据库或系统是否发生故障,数据都会永久保存在磁盘上,并且不会丢失。 当开发人员在使用JDBC操作数据库时,在提交事务后,提示用户事务操作完成,那么这个时候数据就已经存储在磁盘上了。即使数据库重启,该事务所做的更改操作也不会丢失。

隔离级别

当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,所以对于不同的事务,采用不同的隔离级别会有不同的结果。如果不考虑事务的隔离性,则会发生以下情况:

现象 简介 举例
Dirty Read脏读 一个事务读取了已被另一个事务修改,但尚未提交的数据。当一个事务正在多次修改某个数据,而这个事务中这多次的修改都还未提交,这时另一个并发的事务来访问该数据时,就好造成两个事务得到的数据不一致。 用户A向用户B转账100元,对应SQL语句如下:
UPDATE ACCOUNT
SET MONEY = MONEY + 100 WHERE NAME = ‘B’(此时A通知B)
UPDATE ACCOUNT
SET MONEY = MONEY - 100 WHERE NAME = ‘A’
当只执行第一条SQL时,A通知B查看账户,B发现钱确实已经到账(此时触发了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,所有操作都会回滚,那么B以后再次查看账户时就会发现钱其实没有转账成功。
Nonrepeatable Read不可重复读 在同一个事务中,同一个查询在T1时刻读取某一行,在T2时刻重新读取这一行数据的时候,发现这一行的数据已经发生了修改,可能是被更新UPDATE了,也可能是被删除DELETE了。 事务1在读取某一行数据,而事务2立刻修改了这个数据并且提交事务给数据库,事务1再次读取该数据时就得到了不同的结果,发生了不可重复读。
Phantom Read幻读 在同一事务中,当同一查询多次执行的时候,由于其他插入INSERT操作的事务提交,会导致每次返回不同的结果集。幻读是事务非独立执行时发生的一种现象 事务1对一个表中所有的行的某个数据执行从“1”修改为“2”的操作,这时事务2又在这个表中插入一行数据,而这个数据项的数值还是“1”并且提交给了数据库。而操作事务1的用户如果再查看刚刚修改的数据,那么会发现还有一行没有修改,其实这行是从事务2中添加的,就好像产生了幻觉一样,这就是产生了幻读。

不可重复读是由于事务并发修改同一条记录导致的,要想避免这种情况,最简单的方法就是对要修改的记录加锁,这会导致锁竞争加剧,影响性能。另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。
幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。

脏读、不可重复读和幻读的区别是什么?

脏读和不可重复读的区别:脏读是指某一事务读取了另一个事务未提交的脏数据,而不可重复读则是在同一个事务范围内多次查询同一条数据却返回了不同的数据值,这是由于在查询间隔期间,该条数据被另一个事务修改并提交了。
幻读和不可重复读的区别:幻读和不可重复读都是读取了另个一个事务中已经提交的数据,不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一个数据整体(如数据的条数)

事务的4种隔离级别

Read Uncommitted Read Committed Repeatable Read Serializable
中文名 未提交读,读取未提交内容 提交读,读取提交内容 可重复读 可串行化、序列化
简介 在该隔离级别,所有的事务都可以看到其他未提交事务的执行结果,即在未提交读级别中,数据的修改,对其他事务也都是可见的,该隔离级别很少用于实际应用。读取未提交的数据,也被称为脏读。该隔离级别最低,并发性能最好。 一个事务只能看到已经提交事务所做的改变,换句话说,一个事务从开始到提交之前,所做的任何修改对其他事务都是不可见的。这是大多数数据库系统的默认隔离级别。 可重复读可以确保同一个事务,在多次读取同样的数据的时候,得到同样的结果。它解决了脏读的问题,不过理论上,这会导致另一个问题:幻读。 这是最高的隔离级别,它通过强制事务排序,强制事务串行执行,使之不可能相互冲突,从而解决幻读问题。换言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。实际应用中也很少用到这种隔离级别,只有在非常需要确保数据一致性而且可以接受没有并发的情况下,才考虑用该级别。这是花费代价最高但是最可靠的事务隔离级别。
脏读 支持
不可重复读 支持 支持
幻读 支持 支持 支持
默认级别数据库 Oracle、SQL Server MySQL
并发性能 最高 比Read Uncommitted低 比Read Committed低 最低

Oracle|MySQL|SQL Server的事务隔离级别

| 支持 |
- Read Committed提交读

  • Serializable可串行化

    |
    - Read Uncommitted未提交读

  • Read Committed提交读

  • Repeatable Read可重复读

  • Serializable可串行化

    |
    - Read Uncommitted未提交读

  • Read Committed提交读

  • Repeatable Read可重复读

  • Serializable可串行化

  • Snapshot快照

  • Read Committed Snapshot已经提交读隔离

    | | :—- | —- | —- | —- | | 默认 | Read Commit提交读 | Repeatable Read可重复读 | Read Commit提交读 |