一.数据库事务的四大特性(ACID)
1.原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,不会出现一半成功一半失败的情况;
2.一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
3.隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
4.持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
二.事务的隔离级别
1.异常情况
首先看一下若没有事务隔离,会出现的集中情况;
(1)脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
update account set money=money+100 where name=’B’;
update account set money=money - 100 where name=’A’;
假设A还款100元给B,提交请求执行完上面的sql并不提交事务,然后通知B前已经转过去了;
这时B查询账户:
select money from account where name = 'A';
发现钱确实到账了,回复B收到了;
而这时A回滚事务,等到B想用这笔钱时发现钱不见了... ...
(2)不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
当事务A在两次读取数据的时间中间,事务B提交了一次修改,导致事务A两次读取结果不一致;
(3)虚读(幻读)
事务内两次读取的记录数不同;与脏读不同的是,脏读读取的是数据项,而幻读则读取的是记录数,如行数;但相同的是都是读取了前一个事务已经提交的数据;
2.四种隔离级别
Read Uncommitted(读未提交) | 最低级别,任何情况都无法保证 | |
Read Committed(读已提交) | 可避免脏读的发生 | Oracle默认 |
Repeatable Read(可重复读) | 可避免脏读、不可重复读的发生 | MySQL默认 |
Serializable(串行化) | 可避免脏读、不可重复读、幻读的发生 |
查询当前MySql隔离级别:
select @@tx_isolation;
设置MySql隔离级别:
set tx_isolation=’隔离级别名称’
三.数据库锁机制
锁包括行级锁、表级锁、悲观锁、乐观锁;
1.行级锁 (for update)
INSERT、UPDATE、DELETE、SELECT … FOR UPDATE [OF columns] [WAIT n | NOWAIT];
SELECT… FOR UPDATE;
上面语句允许用户一次锁定多条记录更新.使用从commit或者rollback释放锁;
演示:
SHOW VARIABLES LIKE 'autocommit'; //查看当前提交模式
SET autocommit = off //取消自动提交改为手动提交
在一个数据库连接中执行:
在另一个数据库连接中执行:
可以看到执行在等待中... ...(执行结果为长时间等待后的显示);
这时第一个数据库连接执行commit或者rollback时,第二个连接就有结果了;
2.表级锁
待续... ...
(2)间隙锁(Next-Key锁)
下面这条sql只会锁住满足 id = 1 条件的记录,
SELECT * FROM tabletest WHERE id = 1 FOR UPDATE
但是这条sql会锁住满足 id > 10的记录,假设数据库中只有id = 1,2,3,... ...10,11,12共十二条记录,也会对13,14等加锁,即使目前它们并不存在;
SELECT * FROM tabletest WHERE id > 10 FOR UPDATE
演示:
原数据库数据:
执行sql:
SELECT * FROM tabletest WHERE id > 0 FOR UPDATE
该条sql将会锁住所有id>0的记录;
我们执行
INSERT INTO tabletest VALUES(3,'5555',CURRENT_TIME,6)
可以看到正在锁等待,说明原来并不存在的记录也被行锁了,正常来讲我们是不希望如此的;
因此,在实际开发中,尤其是并发插入比较多的应用,我们要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。