一、事务概述
我们的数据库一般都会并发执行多个事务,多个事务可能会并发的对相同的一批数据进行增
删改查操作,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。
这些问题的本质都是数据库的多事务并发问题,为了解决多事务并发问题,数据库设计了事
务隔离机制、锁机制、MVCC多版本并发控制隔离机制、日志机制,用一整套机制来解决多
事务并发问题
二、事务特性
原子性(Atomicity):当前事务的操作要么同时成功,要么同时失败。原子性由undo log日志来实现
一致性(Consistency):使用事务的最终目的,由其它3个特性以及业务代码正确逻辑来实现
隔离性(Isolation):在事务并发执行时,他们内部的操作不能互相干扰,隔离性由MySQL的各种锁以及MVCC机制来实现
持久性(Durability):一旦提交了事务,它对数据库的改变就应该是永久性的。持久性由redo log日志来实现
三、事务的隔离级别
InnoDB引擎中,定义了四种隔离级别供我们使用,级别越高事务隔离性越好,但性能就越低,而隔离性是由MySQL的各种锁以及MVCC机制来实现的
read uncommit (读未提交) :脏读
read commit (读已提交):不可重复读
repeatable read (可重复读) :幻读
serializable (串行):解决上面所有问题,包括脏写
四、大事务的影响
并发情况下,数据库连接池容易被撑爆
锁定太多的数据,造成大量的阻塞和锁超时
执行时间长,容易造成主从延迟
回滚所需要的时间比较长
undo log膨胀
容易导致死锁
五、事务优化实践原则
将查询等数据准备操作放到事务外
事务中避免远程调用,远程调用要设置超时,防止事务等待时间太久
事务中避免一次性处理太多数据,可以拆分成多个事务分次处理
更新等涉及加锁的操作尽可能放在事务靠后的位置
能异步处理的尽量异步处理
应用侧(业务代码)保证数据一致性,非事务执行
六、事务问题
查询方法需要事物吗?
看情况而定,一般如果在可重复读隔离级别情况下,如果是在报表统计业务场景下,一个事务中
有多个表的查询,如果没有在一个事务内,如果查询过程中部分数据修改,那就在某个时间点统计
的数据不一致,所以在这种场景下多个查询最好在一个事务内
普通的select查询加锁吗?
有可能加锁,要考虑隔离级别,在串行化隔离级别下select 默认加了共享锁,lock in share mode
在实际开发中是要使用哪种隔离级别?
一般我们考虑提交读或者可重复读隔离级别,未提交读容易产生脏读,串行化效率太低,都不考虑
提交读和可重复读该怎么选择,对并发要求高的用提交读,多数据时间维度还要统一的用可重复读
七、事务知识点
(1)可重复读是在事物开始后查询第一条数据开始的快照,不只是当前记录或者当前表读的快照,其他的表
中数据在之后又修改页是看不到的,读的之前的快照
(2)查看当前数据库的事务隔离级别: show variables like 'tx_isolation';
设置事务隔离级别:set tx_isolation='REPEATABLE-READ';
查询执行时间超过1秒的事务,详细的定位问题方法后面讲完锁课程后会一起讲解
SELECT * FROM information_schema.innodb_trx WHERE TIME_TO_SEC( timediff( now( ), trx_started ) ) > 1;
(3)强制结束事务 kill 事务对应的线程id(就是上面语句查出结果里的trx_mysql_thread_id字段的值)