代码review的时候看到同事把业务锁(insertDelete实现)和业务操作放在一个事务里。
代码结构如下:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
bizLockRepoImpl.insert(biz_id,id);//其中biz_id是主键
xxxxx;
xxxxx;
xxxxx;
……………;
bizLockRepoImpl.delete(biz_id,id);//其中biz_id是主键
});
顿感十分奇怪,这样根据『事务隔离性』的原则,岂不是等于没有做并发控制么?于是,立马安装了个mysql进行验证。实验如下,注意时序性:
实验一:
目的:
证明,虽然第一个事务还没提交,但是如果其他事务里的sql涉及到和执行中的事务有主键冲突或者update了相同行的时候,其他的事务也是不能正常提交的。
原因:在MVCC控制中,写操作是『当前读』,读取记录的最新版本。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁。
步骤:
1. 开启一个mysql终端:
2. 开启另外一个mysql终端:
mysql> insert into biz_lock vaules(8,8,now(),now());
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
输出insert语句,就挂住了。等待了一段时间之后(一直不要去commit第一个事务),报错如上。『等锁超时』。
结论:
虽然我们知道数据库具有隔离性『定义:当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。』。数据库引擎在事务commit前,也是会进行一些保护(因为数据库引擎是怎么实现的还没有去研究,先把表象说明白)。
实验二:
目的,看看我们所理解的数据库事务的『隔离性』.
1. 客户端一:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into biz_lock values(9,9,now(),now());
Query OK, 1 row affected (0.00 sec)
mysql> select * from biz_lock where biz_id = 9;
+------+--------+---------------------+---------------------+
| id | biz_id | gmt_create | gmt_modified |
+------+--------+---------------------+---------------------+
| 9 | 9 | 2018-01-09 19:36:47 | 2018-01-09 19:36:47 |
+------+--------+---------------------+---------------------+
1 row in set (0.00 sec)
在一个事务里insert了一条记录,在这个事务里select是可以看到的。
2. 客户端二:
mysql> select * from biz_lock where biz_id = 9;
Empty set (0.00 sec)
3. 客户端一:
mysql> commit work;
Query OK, 0 rows affected (0.00 sec)
4. 客户端二:
mysql> select * from biz_lock where biz_id = 9;
+------+--------+---------------------+---------------------+
| id | biz_id | gmt_create | gmt_modified |
+------+--------+---------------------+---------------------+
| 9 | 9 | 2018-01-09 19:36:47 | 2018-01-09 19:36:47 |
+------+--------+---------------------+---------------------+
1 row in set (0.00 sec)
结论:我们看到,在事务一提交前,如果我们在其他的客户端(即其他事务里)查询是看不到事务一里还没有commit的数据的。即我们讨论的事务隔离性。