隔离级别:
1、READ UNCOMMITTED:最低级别的隔离,通常又称为dirty read,它允许一个事务读取还没commit的数据,这样可能会提高性能,但是dirty read可能不是最期望的结果
2、READ COMMITTED:在一个事务中只允许已经commit的记录可见,如果session中select还在查询中,另一session此时insert一条记录,则新添加的数据不可见
3、REPEATABLE READ:在一个事务开始后,其他session对数据库的修改在本事务中不可见,直到本事务commit或rollback。在一个事务中重复select的结果一样,除非本事务中update数据库
4、SERIALIZABLE:最高级别的隔离,只允许事务串行执行。为了达到此目的,数据库会锁住每行已经读取的记录,其他session不能修改数据直到前一事务结束,事务commit或取消时才释放锁
悲观锁:在读取数据时锁住那几行,其他对这几行的更新需要等到悲观锁结束时才能继续
乐观锁:读取数据时不锁,更新时检查是否数据已经被更新过,如果是则取消当前更新
大多是基于数据版本(Version)记录机制实现。即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。
读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据
乐观锁实例:
操作员B操作如下:
说明:
操作员A已修改成功,实际account.balance=1100、account.version=2,操作员B也将版本号加一(version=2)试图向数据库提交数据(balance=950),但此时比对数据库记录版本时发现,操作员B提交的数据版本号为2,数据库记录当前版本也为2,不满足"提交版本必须大于记录当前版本才能执行更新"的乐观锁策略,因此,操作员B的提交被驳回。
1、READ UNCOMMITTED:最低级别的隔离,通常又称为dirty read,它允许一个事务读取还没commit的数据,这样可能会提高性能,但是dirty read可能不是最期望的结果
2、READ COMMITTED:在一个事务中只允许已经commit的记录可见,如果session中select还在查询中,另一session此时insert一条记录,则新添加的数据不可见
3、REPEATABLE READ:在一个事务开始后,其他session对数据库的修改在本事务中不可见,直到本事务commit或rollback。在一个事务中重复select的结果一样,除非本事务中update数据库
4、SERIALIZABLE:最高级别的隔离,只允许事务串行执行。为了达到此目的,数据库会锁住每行已经读取的记录,其他session不能修改数据直到前一事务结束,事务commit或取消时才释放锁
悲观锁:在读取数据时锁住那几行,其他对这几行的更新需要等到悲观锁结束时才能继续
乐观锁:读取数据时不锁,更新时检查是否数据已经被更新过,如果是则取消当前更新
大多是基于数据版本(Version)记录机制实现。即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。
读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据
乐观锁实例:
场景:比如A、B操作员同时读取一余额为1000元的账户,A操作员为该账户增加100元,B操作员同时为该账户扣除50元,A先提交,B后提交。最后实际账户余额为1000-50=950元,但本该为1000+100-50=1050。这就是典型的并发问题
操作员A操作如下:
mysql> select id, balance, version from account where id="1";
+----+---------+---------+
| id | balance | version |
+----+---------+---------+
| 1 | 1000 | 1 |
+----+---------+---------+
1 row in set (0.00 sec)
mysql> update account set balance=balance+100, version=version+1 where id="1" and version=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select id, balance, version from account where id="1";
| id | balance | version |
+----+---------+---------+
| 1 | 1100 | 2 |
+----+---------+---------+
1 row in set (0.00 sec)
操作员B操作如下:
mysql> select id, balance, version from account where id="1";
+----+---------+---------+
| id | balance | version |
+----+---------+---------+
| 1 | 1000 | 1 |
+----+---------+---------+
1 row in set (0.00 sec)
mysql> update account set balance=balance-50, version=version+1 where id="1" and version=1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0
mysql> select id, balance, version from account where id="1";
+----+---------+---------+
| id | balance | version |
+----+---------+---------+
| 1 | 1100 | 2 |
+----+---------+---------+
1 row in set (0.00 sec)
说明:
操作员A已修改成功,实际account.balance=1100、account.version=2,操作员B也将版本号加一(version=2)试图向数据库提交数据(balance=950),但此时比对数据库记录版本时发现,操作员B提交的数据版本号为2,数据库记录当前版本也为2,不满足"提交版本必须大于记录当前版本才能执行更新"的乐观锁策略,因此,操作员B的提交被驳回。