1. 事务
- 一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。
- InnoDB支持事务,MyISAM和MEMORY不支持事务。
2. 事务的ACID
- 原子性:事务是一个不可分割的工作单元,要么都发生,要么都不发生。
- 一致性:事务必须使数据库从一个一状态变换到另一个一直状态。
- 隔离性:事物的执行不能被其他事务所干扰。
- 持久性:事务一旦被提交,它对数据库中数据的改变就是永久性的。
3. 事务的创建
- 隐式事务:事务没有明显的开启和结束标记,比如:INSERT、UPDATE、DELETE语句。
- 显式事务:事务具有明显的开启和结束标记,比如:START TRANSACTION。
# 查看数据库是否开启自动提交事务
SHOW VARIABLES LIKE 'autocommit';
# 设置数据库关闭自动提交事务(只针对当前会话)
SET autocommit = 0;
# 开启事务
START TRANSACTION;
# 编写一个或一组SQL语句
UPDATE `user` SET `price` = `price` - 500 WHERE `name` = '李白';
UPDATE `user` SET `price` = `price` + 500 WHERE `name` = '杜甫';
# 提交事务或者回滚事务
COMMIT;
ROLLBACK;
# 开启事务
START TRANSACTION;
# 修改李白的金额
UPDATE `user` SET `price` = `price` - 500 WHERE `name` = '李白';
# 设置保存点
SAVEPOINT point;
# 修改杜甫的金额
UPDATE `user` SET `price` = `price` + 500 WHERE `name` = '杜甫';
# 回滚事务到保存点
ROLLBACK TO point;
4. 事务的并发问题
- 脏读:对于两个事务t1和t2,t1读取了已经被t2更新但还没有被提交的字段后,若t2回滚,t1读取的数据就是临时无效的数据。
- 不可重复读:对于两个事务t1和t2,t1读取了一个字段,然后t2更新了该字段,t1再次读取相同的字段却读取到不同的数据。
- 幻读:对于两个事务t1和t2,t1读取了一个表,然后t2插入了新的数据,t1再次读取相同的表读取到多条记录。
5. 事务的并发解决
- 隔离级别:一个事务与其他事务的隔离程度。数据库中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
- READ UNCOMMITED:读未提交,允许事务读取未被其他事务提交的变更,脏读、不可重复读和幻读的问题都存在。
- READ COMMITED:读已提交,只允许事务读取已经被其他事务提交的变更,可以避免脏读,但不可重复读和幻读任然存在。
- REPEATABLE READ:可重复读,确保事务可以多次从一个字段中读取相同的值。在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读和不可重复读,但幻读仍然存在。
- SERIALIZABLE:串行化,确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表进行插入、更新和删除操作,所有并发问题都可以避免,但性能十分低下。
- 注意:Oracle支持READCOMMITED和SERIALIZABLE,默认为READCOMMITED。MySQL四种都支持,默认为REPEATABLEAD。
# 查看数据库隔离级别
SELECT @@tx_isolation;
# 设置数据库隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL read uncommited;