事务
事务是一个整体,由一条或者多条SQL语句组成,这些SQL语句要么都执行成功,要么都执行失败, 只要有一条SQL出现异常,整个操作就会回滚,整个业务执行失败。
事务的四大特性 ACID
原子性(Atomicity):每个事务都是一个整体,不可再拆分,事务中所有的 SQL 语句要么都执行成功, 要么都失败。
一致性(Consistency):事务在执行前数据库的状态与执行后数据库的状态保持一致。如:转账前2个人的总金额是 2000,转账后2个人总金额也是 2000。
隔离性(Isolation):事务与事务之间不应该相互影响,执行时保持隔离的状态。
持久性(Durability):一旦事务执行成功,对数据库的修改是持久的。就算关机,数据也是要保存下来的。
事务隔离级别
数据并发访问
一个数据库可能拥有多个访问客户端,这些客户端都可以并发方式访问数据库. 数据库的相同数据可能被多个事务同时访问,如果不采取隔离措施,就会导致各种问题, 破坏数据的完整性。
并发访问会产生的问题
事务在操作时的理想状态:所有的事务之间保持隔离,互不影响。因为并发操作,多个用户同时访问同一个数据。可能引发并发访问的问题 。
并发访问的问题 | 说明 |
---|---|
脏读 | 一个事务读取到了另一个事务中尚未提交的数据 |
不可重复读 | 一个事务中两次读取的数据内容不一致, 要求的是在一个事务中多次读取时数据是一致的. 这是进行 update 操作时引发的问题 |
幻读 | 一个事务中,某一次的select操作得到的结果所表征的数据状态, 无法支撑后续的业务操作. 查询得到的数据状态不准确,导致幻读. |
举例:
脏读:A开启事务,自己减钱,别人加钱,B开启事务,查看钱到账,A回滚事务,B再查看钱没了。
张三向李四购买商品,张三开启事务,向李四账号转入 500 块,然后打电话给李四说钱 已经转了。李四一查询钱到账了,发货给张三。张三收到货后回滚事务,李四的再查看钱没了。
不可重复读:B开启事务先查一下数据,A开启事务,加钱,提交事务,B再查,两次查询的数据不一致。
比如银行程序需要将查询结果分别输出到电脑屏幕和发短信给客户,结果在一个事务中针对不同的输出目的地进行的两次查询不一致,导致文件和屏幕中的结果不一致,银行工作人员就不知道以哪个为准了。所以说这是一个问题。
幻读:A、B都开启事务,A先查询,可以添加为3的数据,B插入一条数据,提交事务,A再插入,就报错,产生了幻读。
select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。
隔离级别
通过设置隔离级别,可以防止上面的三种并发问题。
MySQL数据库有四种隔离级别上面的级别最低,下面的级别最高。
✔ 会出现问题
✘ 不会出现问题
级别 | 名字 | 隔离级别 | 脏 读 | 不可重复读 | 幻读 | 数据库的默认隔离级别 |
---|---|---|---|---|---|---|
1 | 读未提交 | read uncommitted | ✔ | ✔ | ✔ | |
2 | 读已提交 | read committed | ✘ | ✔ | ✔ | Oracle和SQLServer |
3 | 可重复读 | repeatable read | ✘ | ✘ | ✔ | MySQL |
4 | 串行化 | serializable | ✘ | ✘ | ✘ |
脏读解决:将全局的隔离级别进行提升为: read committed。
不可重复读解决:将全局的隔离级别进行提升为: repeatable read。
幻读解决:将事务隔离级别设置到最高 SERIALIZABLE ,以挡住幻读的发生。
如果一个事务,使用了SERIALIZABLE——可串行化隔离级别时,在这个事务没有被提交之前 , 其他的线程,只能等到当前操作完成之后,才能进行操作,这样会非常耗时,而且,影响数据库的性能,数据库不会使用这种隔离级别。