Mysql事务原理与优化最佳实践

117 阅读3分钟

如何使用事务

#显式开启一个事务
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 InnoDB processing 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膨胀

  • 容易导致死锁

  • 数据库连接池容易被撑爆

事务优化

所有目标都是为了减少事务的执行时间

  • 将查询等数据准备操作放到事务外
  • 事务中避免远程调用
  • 事务中避免一次性处理太多数据
  • 更新等涉及加锁的操作尽可能放在事务靠后的位置
  • 尽量异步处理
  • 应用侧(业务代码)保证数据一致性,非事务执行

参考文档: note.youdao.com/ynoteshare/…