一、事务介绍
事务管理是企业级应用程序开发中必不可少的技术, 用来确保数据的完整性和一致性。
事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用。
数据库向用户提供保存当前程序状态的方法,叫事务提交(commit);当事务执行过程中,使数据库忽略当前的状态并回到前面保存的状态的方法叫事务回滚(rollback)。
二、事务的四大特性(ACID)
-
原子性(atomicity):事务是一个原子操作 , 由一系列动作组成,事务的原子性确保动作要么全部完成要么完全不起作用。
-
一致性(consistency): 一旦所有事务动作完成,事务就被提交.,数据和资源就处于一种满足业务规则的一致性状态中。比如说,A和B的账户里面共有10000元,不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还是10000。
-
隔离性(isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如,A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
-
持久性(durability):一旦事务完成, 无论发生什么系统错误, 它的结果都不应该受到影响. 通常情况下,事务的结果被写到持久化存储器中。
事务四大特性之间的关系:
- 原子性是基础
- 隔离性是手段
- 持久性是目的
- 一致性是最终结果(老大)
三、事务的隔离级别
1、事务并发产生的问题
(1)脏读
事务A读取了事务B未提交的数据。例如:用户A向用户B转账1000元,A通知B查看账户,B发现钱确实已到账,而之后无论第二条SQL是否执行,只要该事务部提交,则所有操作都将回滚,当B再次查看账户时就会发现钱其实并没有到账。
(2)不可重复读
事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。例如:事务A在读取某一数据时,而事务B立马修改了这个数据并且提交事务给数据库,事务A再次读取该数据就得到了不同的结果,发生了不可重复读。
脏读与不可重复读的区别:
- 脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
(3)幻读(虚读)
这是当事务不是独立执行时发生的一种现象。例如:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
不可重复读与幻读的区别与联系:
不同点:
- 不可重复读侧重于修改,幻读侧重于新增或删除。
- 不可重复读查询的都是同一数据项,而幻读针对的是一批数据整体。
- 解决方式不同:解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。
相同点:
- 幻读和不可重复读都读取的是另一条已经提交的事务。
2、事务的隔离级别
事务的隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(Read-Uncommitted) | 是 | 是 | 是 |
读已提交(Read-Committed) | 否 | 是 | 是 |
可重复读(Repeatable-Read) | 否 | 否 | 是 |
串行化(Serializable) | 否 | 否 | 否 |
注意:
- 四种隔离级别,Seralizable级别最高,Read uncommitted级别最低。级别越高,执行效率就越低。
- 隔离级别的设置只对当前链接有效,对JDBC操作数据库来说,一个Connection对象相当于一个链接,只对该Connection对象设置的隔离级别有效,与其它链接connection对象无关。
- Mysql的默认隔离级别是:可重复读:Repeatable read。oracle数据库中,只支持seralizable(串行化)级别和Read committed(),默认的是Read committed级别。
- 设置数据库的隔离级别一定要是在开启事务之前。
- 事务的隔离级别并不是越高越好。事务的隔离级别越高,越消耗数据库性能。
3、四种隔离级别发生场景
1) Read uncommitted 读未提交
公司发工资了,领导把5000元打到小明的账户上,但是该事务并未提交,而小明正好去查看账户,发现工资已经到账,是5000元整,非常高兴。可是不幸的是,领导发现发给小明的工资金额不对,应该是4000元,于是迅速回滚了事务,修改金额后,将事务提交,最后小明实际的工资只有2000元,小明空欢喜一场。
2)Read committed 读已提交
小明拿着工资卡去消费,系统读取到卡里有4000元,而此时她的老婆正好在网上转账,把小明工资卡的4000元转到了另一账户,并在小明之前提交了事务,当singo扣款时,系统检查到小明的工资卡已经没有钱,扣款失败。小明十分纳闷,明明卡里有钱,为何就没了…
它是SQL Server与Oracle默认的隔离级别。
3)Repeatable read 可重复读
当小明拿着工资卡去消费时,一旦系统开始读取工资卡信息(即事务开始),小明的老婆就不能对该记录进行修改,也就是小明的老婆不能在此时转账。
它是MySQL的默认隔离级级别。
4)幻读
小明某一天去消费,他老婆经常会检查他的消费记录。有一天,她查询到小明当月信用卡的总消费金额(select sum(amount) from transaction where month = 本月)为500元,而小明此时正好在外面和朋友吃饭后在收银台买单,消费了800元,即新增了一条800元的消费记录(insert transaction … ),并提交了事务。随后,小明的老婆将小明当月信用卡消费的明细打印到纸上,却发现消费总额为1300元,突然多消费了800元,以为出现了幻觉,幻读就这样产生了。