什么是数据库事务
数据库事务是访问并可能更新数据库中各种数据项的程序执行单元,也就是说事务是有0个或多个查询和修改语句组合而成的,即使没有查询语句和更新语句,如果定义一个操作是事务也成立。
一个数据库的事务通常包括对数据库进行读或写的一个操作序列。
事务的相关特性(ACID特性)
A:原子性(Atomicity)
数据库事务可以包含一个或多个数据库操作,但这些操作合起来构成一个逻辑整体,不可分割。构成逻辑整体的这些操作,要么全部执行成功,要么全部执行失败。
C:一致性(Consistency)
事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态
I:隔离性(Isolation)
在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务。事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。
D:持续性/永久性(Durability)
事务正确提交后,其结果将永久保存在数据库中,即使在事务提交后有了其他故障,事务的处理结果也会得到保存。
为什么使用事务
事务使系统能够更方便的进行故障恢复以及并发控制,从而保证数据库状态的一致性。
事务并发异常
- 丢失更新
丢失更新是指事务覆盖了其他事务对数据已经提交的修改,导致其他事务的修改好像丢失了一样。分为两种情况:
- 回滚丢失
- 覆盖丢失
标准定义的隔离级别不允许出现回滚丢失发生。
- 脏读
脏读是指读取了另外一个事务还没有提交的数据。
- 幻读
指当多次统计某一范围的数据时,其他事务提交后新增了数据或删除了数据导致前后统计的数据不一致。
- 不可重复读
指事务对同一个数据重复读取前后的结果不一致
为了避免并发下的事务问题,可以通过调整数据库的隔离级别实现
数据库隔离级别
- 读未提交(READ UNCOMMITTED)
- 读已提交(READ COMMITTED)–Oracle默认级别
- 可重复读(REPEATABLE READ)–MySQL默认级别
- 串行化(SERIALIZABLE)
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | √ | √ | √ |
读已提交 | × | √ | √ |
可重复读 | × | × | √ |
串行化 | × | × | × |
修改数据库隔离级别的命令
- 查看数据库版本:select version();
- 查看数据库现在的隔离级别:select @@session.tx_isolation;
- 隔离级别:READ-UNCOMMITTED,READ-COMMITTED,REPEATABLE-READ,SERIALIZABLE
- 设置数据库隔离级别:set global transaction isolation level read uncommitted;
set tx_isolation=‘read-uncommitted’; - 开启事务:start transaction;
- 提交/回滚:commit/rollback;
数据库更新丢失的解决方式
悲观锁
悲观锁适用于系统并发较少但是冲突较多的时候,具体实现如下:
- 添加共享锁的方式:select * from account lock in share mode;
- 添加排他锁的方式:select * from account for update;
乐观锁
乐观锁适用于大多数并发场景,具体实现如下:
在表中增加timestamp字段,当更新时记录当前字段的值,提交事务前校验当前字段值和之前是否一致,一致就提交事务,不一致则回滚事务。