如何使用事务
#显式开启一个事务
BEGIN;
START TRANSACTION;
START TRANSACTION READ ONLY; #ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.
START TRANSACTION READ WRITE;(默认)
START TRANSACTION WITH CONSISTENT SNAPSHOT;
#提交事务 或 中止事务
SAVEPOINT 保存点名称;
RELEASE SAVEPOINT 保存点名称;
COMMIT;
ROLLBACK;
ROLLBACK TO [SAVEPOINT];
#自动提交系统变量
SHOW VARIABLES LIKE 'autocommit';
数据库多事务并发引起的问题
- 更新丢失(Lost Update)或脏写
- 脏读(Dirty Reads)
- 不可重读(Non-Repeatable Reads)
- 幻读(Phantom Reads)
mysql设计了 事务隔离级别、锁、MVCC、日志机制。
ACID
当您依赖acid兼容的特性时,您不需要重新发明一致性检查和崩溃恢复机制。
原子性(atomicity) :当前事务的操作要么同时成功,要么同时失败。原子性由 undo log日志来实现。
一致性(consistency) :使用事务的最终目的,由其它3个特性以及业务代码正确逻 辑来实现。
The *consistency* aspect of the ACID model mainly involves internal
InnoDBprocessing to protect data from crashes.
隔离性(isolation) :在事务并发执行时,他们内部的操作不能互相干扰。隔离性由 MySQL的各种锁以及MVCC机制来实现。
持久性(durability) :一旦提交了事务,它对数据库的改变就应该是永久性的。持久 性由redo log日志来实现。
事务隔离级别
InnoDB offers all four transaction isolation levels described by the SQL:1992 standard:
隔离级别越高,数据一致性就越好,但并发性越弱。
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ (default )
SERIALIZABLE
通过案例来分析
# 创建测试表及数据
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`balance` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `account` (`name`, `balance`) VALUES ('lilei', '450');
INSERT INTO `account` (`name`, `balance`) VALUES ('hanmei', '16000');
INSERT INTO `account` (`name`, `balance`) VALUES ('lucy', '2400');
# 设置隔离级别 READ-UNCOMMITTED
set transaction_isolation='READ-UNCOMMITTED';
#T1,开启事务,执行upate语句
START TRANSACTION;
update account set balance=balance-10 where id = 1;
rollback;
#T2可以读取到未提交的修改
select * from account;
#T2 设置隔离级别 READ-UNCOMMITTED
set transaction_isolation='READ-COMMITTED';
#读取不到未提交的事务了,相同查询语句结果不一致,即产生了不可重复读的问题
# 设置隔离级别 REPEATABLE-READ
set transaction_isolation='REPEATABLE-READ';
#无论别的事务是否提交,每次读取都是一致的,执行过update语句会获取最新的数据
# 设置隔离级别 SERIALIZABLE
set transaction_isolation='SERIALIZABLE';
#T1开启事务,执行查询后,所有的insert update delete 操作都被阻塞
#不允许其它事务修改
SELECT ... LOCK IN SHARE MODE;
#阻塞其它写锁和读锁
SELECT ... FOR UPDATE;
大事务的影响
-
锁定太多的数据,造成大量的阻塞和锁超时
-
执行时间长,容易造成主从延迟
-
回滚所需要的时间比较长
-
undo log膨胀
-
容易导致死锁
-
数据库连接池容易被撑爆
事务优化
所有目标都是为了减少事务的执行时间
- 将查询等数据准备操作放到事务外
- 事务中避免远程调用
- 事务中避免一次性处理太多数据
- 更新等涉及加锁的操作尽可能放在事务靠后的位置
- 尽量异步处理
- 应用侧(业务代码)保证数据一致性,非事务执行