
说到隔离性,肯定就会想到隔离级别,SQL标准的事务隔离级别包括:
MySQL隔离级别修改:transaction_isolation,可设置的值为: READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ,或 SERIALIZABLE
为了实现隔离级别,数据库会创建一个视图,访问的时候以视图的逻辑结果为准,当然这个视图在“读未提交”和“串行化”这两种隔离级别下是没有的,“读未提交”隔离级别下直接返回记录上的最新值,而“串行化”则直接使用加锁的方式避免并发访问同一行记录。
在“可重复读”隔离级别下,这个视图是在开启事务的时候创建的,整个事务期间都使用这个视图;
在“读已提交”隔离级别下,这个视图是在每次执行SQL的时候创建的
ReadView中并不是真正的存储数据,如果是存储数据的话,每个事务都创建一个ReadView未免也太浪费内存了,ReadView会记录4个非常重要的属性:
ReadView会根据这4个属性,再结合回滚段来实现MVCC机制,决定让一个事务能读到哪些数据,不能读取到哪些数据。
假设在对账户流水进行对账时,希望在对账过程中,即使有用户发生了一笔新的交易,也不影响校对的过程,这个时候使用“可重复读”隔离级别就很方便
我们通过“可重复读”隔离级别进行阐述:
我们对记录的每次更新MySQL都会记录一条回滚操作,通过回滚操作,记录可以得到前一个状态的值。
比如表T的c字段的值被事务C从1被修改为2->3>4,在回滚日志中就会有三个回滚日志,分别为4>3、3>2、2>1。
理解“多版本并发控制”
在“可重复读”隔离级别下,
当事务A启动时会创建一个视图Read Videw A,字段值是1;同时事务C也启动了,也同样的创建了一个视图Read View C,并且把字段的值从1被修改为2->3>4,如上图的字段值行,对应的就会生成三个回滚日志,对应上图的回滚段行。
此时事务A读该记录的字段仍然应该是1,但是但是要读到1,就必须将当前值依次执行上图的所有回滚操作得到,这个问题在数据视图部分已经讲过了;
这时候就算事务C提交了,但是针对这行记录的回滚日志也不能删除,因为事务A可能还会使用它来还原到自己开启事务的版本。
如果事务A是一个长事务,回滚日志就一直不能删除,这样就占用了大量的存储空间,因此得出一个结论:尽量不要使用长事务
information_schema库的innodb_trx表可以查看事务,下面的语句是查找持续时间超过60s的事务。
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60如何避免长事务对业务的影响
应该从应用开发端和数据库端来看
开启 general log 将所有到达MySQL Server的SQL语句记录下来,查询日志开启 方法一: mysql>set global general_log_file=’/tmp/general.lg’; #设置路径 mysql>set global general_log=on; # 开启general log模式 mysql>set global general_log=off; # 关闭general log模式 命令行设置即可,无需重启 在general log模式开启过程中,所有对数据库的操作都将被记录 general.log 文件 方法二: 也可以将日志记录在表中 set global log_output=‘table’ 运行后,可以在mysql数据库下查找 general_log表 二、查询日志关闭 查看是否是开启状态: mysql> show global variables like ‘%general%’; 关闭 mysql> set global general_log = off; // 关闭查询日志
事务的启动方式innodb_undo_tablespaces是控制undo是否开启独立的表空间的参数 为0表示:undo使用系统表空间,即ibdata1 不为0表示:使用独立的表空间,一般名称为 undo001 undo002,存放地址的配置项为:innodb_undo_directory 一般innodb_undo_tablespaces 默认配置为0,innodb_undo_directory默认配置为当前数据目录
显式启动
使用begin或start transaction启动,对应使用commit提交,rollback回滚
自动启动
set autocommit=0,这个命令会将这个线程的自动提交关掉,只执行一个select语句,这个事务就启动了,并且不会自动提交,持续到主动执行commit、rollback语句,或者断开连接。set autocommit=0会导致意外的长事务(如果忘记手动commit或者rollback),建议使用set autocommit=1,表示MySQL自动开启和提交事务。 比如执行一个update语句,语句只完成后就自动提交了。不需要显示的使用begin、commit来开启和提交事务。 所以,当我们需要对某些操作使用事务的时候,手动的用begin、commit来开启和提交事务。
自动提交autocommit
数据库事务默认是自动提交的,如果语句没有返回错误,MySQL会在每个SQL语句后提交一次。
commit work and chain
在autocommit=1的情况下,如果使用begin显式启动事务,也可以使用commit work and chain来提交事务,意思是提交事务并开启下一个事务,省去了再次执行begin语句的开销。