事务属性、隔离级别、乐观锁、悲观锁
一、事务属性
事务是为解决应用程序并行问题产生的,并不是数据库天生的。
1、原子性(Atomicity)
事务执行要么全部成功,要么全部失败。类似与二进制,并不是0就是1。
2、一致性(Consistency)
事务执行前后应用程序状态一致。一致性通常由上层来实现,如正常执行的逻辑关联(A发生支付动作,余额就会减少,商户余额就会增加)或者回滚中的反向操作。
3、隔离性(Isolation)
不同事务执行互不影响
4、持久性(Durability)
事务执行成功后,状态变化是永久的。即使数据库故障(断电)等也不能更改状态
二、隔离级别
隔离级别可以简单理解为对读写锁的控制,详见下图

1、读未提交(Read uncommitted)
顾名思义,读到了未提交的数据,如果写事务发生回退就会导致读到错误数据,也就是脏读,如图中1
2、读已提交(Read committed)
只有写事务提交的数据才可以读,这样可以防止脏读,如图2。如果读事务先执行查询,中间执行写事务然后在执行读事务中的第二次查询,会导致两次查询的数据不一致,也就是不可重复读,如图5
3、可重复读(Repeatable read)
读事务不允许写事务(针对同一行数据),这样可以防止不可重复读,如图3。如果写事务新增/删除同类型的数据(满足查询条件就是同类型数据)如查询age大于18员工个数,读事务的过程中插入符合条件的一条数据就会导致前后两次查询数据不一致,也就是幻读。幻读和不可重复读区别在一个是数据更新,一个是新增/删除数据。
4、序列化(Serializable)
序列化执行事务,不能并发执行,如图4。序列化性能很低,一般很少使用。
- 注:mysql默认的隔离级别是读已提交,图中6是不允许的,也就是对相同数据两个写事务的并行执行。
三、悲观锁、乐观锁
1、悲观锁
悲观锁是指在整个数据处理过程中将数据处于锁定状态。悲观锁的实现依赖于数据库提供的锁机制,也只有数据库提供的锁机制才能实现数据的排他性。
mysql innoDB为例:
-
设置mysql为非自动提交:set autocommit = 0
-
执行事务
begin;
select age from user where id = 1 for update;
update user set status = 1
commit;
在InnoDB中默认是row-level lock,只有明确低指定主键或者索引mysql才会执行row lock,否则将会执行table lock把整个表格锁住。
select ... for id = 1 update #id是主键/索引,且id=1的只存在,否则执行table lock
select ... for id > 1 update #主键不明确
select ... for name = "xx" update #非主键/索引
2、乐观锁
乐观锁假设认为数据一般情况下不会造成冲突,只有在数据提交的时候才对数据是否冲突进行检测。乐观锁通常在数据库表格中增加一个字段(version或者timestamp)实现。在提交数据的时候判断timestamp是否一致,如果一致就更新,否则就是版本冲突。