1  概述

事务是指一组原子性的SQL查询、或者是一个或多个SQL语句组成的独立工作单元;MyISAM不流行的原因很大是因为其不支持事务的处理功能。

2  事务日志

事务日志定义属性,有些参数可以运行时修改,写入在配置段里,事务日志相当于是中间的辅助功能,而且很关键。

事务日志表示把操作过程一笔一笔记录下来。如某个线程要对某个行操作,数据库会先保留老版本于事务日志中,对文件的写入,新版本的内容是先写入到日志里,提交前,数据在日志文件中,而不是在数据文件中,提交操作执行后,才将新旧版本的日志清除。

执行事务时,每个操作都需要从内存读入到日志中

事务日志主要是为了加速操作,同时为了辅助提交数据的功能,将随机写操作转换为顺序写操作

事务日志必须是固定大小,一般是有两个空间,一旦一个空间满了,就写入磁盘,另一个空间开始写入。轮替工作。

为了避免事务日志所在的磁盘,因硬盘故障导致破坏,可以用raid或者镜像组同步写入两份文件,保证了冗余,实现数据安全

以下是配置文件里事务日志的相关参数:

innodb_log_files_in_group:表示一组内有几个文件,一般要有两个

innodb_log_group_home_dir:指明家目录

innodb_log_file_size:指定日志文件的大小,默认5M

innodb_mirrored_log_groups:日志组有几个

3  ACID测试

如果一个存储引擎支持事务,那么关系型数据库就必须满足ACID测试:而非关系型数据库是base(碱性的单词)

A:AUTOMICITY,原子性;整个事务中的所有操作要么全部成功执行,要么全部失败后回滚到开始处;

C:CONSISTENCY,一致性;数据库总是应该从一个一致性状态转为另一个一致性状态; 

I:ISOLATION,隔离性;一个事务所做出的操作在提交之前,是否能为其它事务可见;出于保证并发操作之目的,隔离有多种级别; 隔离如果做得严格,可能导致串行执行,而失去了并发执行的意义。有四个级别,隔离性最低,并发性最高,隔离性最高,安全性也最高,但是并发性就最低。可以根据安全性和服务器的并发性选择一个合适的方案。

D:DURABILITY,持久性;事务一旦提交,其所做出的修改会永久保存;

4  事务控制

自动提交:单语句事务,影响性能

mysql> SELECT @@autocommit;#查看自动提交功能参数

mysql> SET @@session.autocommit=0;#关闭自动提交功能后需要手动控制事务

手动控制事务,事务一旦提交,就不能回滚:

启动事务:START TRANSACTION 

提交事务:COMMIT

回滚事务:ROLLBACK

事务支持savepoints:保存点,相当于是虚拟机的快照

SAVEPOINT identifier#创建保存点

ROLLBACK [WORK] TO [SAVEPOINT] identifier #还原到某个保存点

RELEASE SAVEPOINT identifier#销毁savepoint

例子

MariaDB [sunny]> insert into classlist values ("su",10,"91"),("chen",18,"88");MariaDB [sunny]> 

#创建保存点first

MariaDB [sunny]> savepoint first;

MariaDB [sunny]> update classlist set name=ghbsunny where nu=1;

#创建保存点second

MariaDB [sunny]> saveponit second;

如果不修改nu=1的name值,此时执行

MariaDB [sunny]> rollback to first;

#注意,执行完 rollback to first保存点second就不存在了,因为在保存点first的时候,second还没创建。一旦执行了commint后,就不能rollback

#销毁保存点first

MariaDB [sunny]> release savepoint first;

5  事务隔离级别

级别由低而高,最高级别是串行化。隔离性越来越好,但是并发性降低。低级别的事务一定有高级别的问题

mysql数据库默认是第三隔离级别REPEATABLE-READ,其他数据库一般默认第二级别READ-COMMITTED,所以mysql建议也修改为第二级别的READ-COMMITTED

查看当前会话级定义的事务隔离级别

MariaDB [sunny]> select @@session.tx_isolation;

mysql有四个隔离级别,如下:

READ-UNCOMMITTED:

读未提交 --> 容易导致脏读,不被确认的结果也可能被读取;即没有提交的情况下,别人也可以看到未提交的更新的记录

例子:打开两个crt窗口,登录mysql,分别关闭自动提交功能和设置隔离级别为READ-UNCOMMITTED

MariaDB [sunny]> SET @@session.autocommit=0;

MariaDB [sunny]> set @@session.tx_isolation="READ-UNCOMMITTED";

MariaDB [sunny]> start transaction;

在窗口1上执行

MariaDB [sunny]> update classlist set name="bf" where nu=10;

此时,窗口1没有执行commit,但是在窗口2上能够看到已经更新后的数据,即窗口2上执行如下语句,看到nu=10的name已经更改为bf了,即窗口2可以随时看到窗口1的任何修改

MariaDB [sunny]> select * from classlist where nu=10;

+------+----+-------+

| name | nu | score |

+------+----+-------+

| bf   | 10 | 91.00 |

+------+----+-------+

READ-COMMITTED:

读提交--> 读别人确认的数据,可能导致不可重复读的问题,可能多次读的结果不一样;

例子:打开两个crt窗口,登录mysql,分别关闭自动提交功能和设置隔离级别为READ-COMMITTED

MariaDB [sunny]> SET @@session.autocommit=0;

MariaDB [sunny]> set @@session.tx_isolation="READ-COMMITTED";

MariaDB [sunny]> start transaction;

在窗口1上执行

MariaDB [sunny]> delete from classlist where nu=1;

此时,窗口1没有执行commit操作,窗口1上查看到的nu=1已经被删除,但是查看2还是可以看到nu=1的记录

窗口2上执行如下

MariaDB [sunny]> select * from classlist where nu=1;

+-------+----+--------+

| name  | nu | score  |

+-------+----+--------+

| sunny |  1 | 100.00 |

+-------+----+--------+

1 row in set (0.00 sec)

窗口1上执行commit后,窗口2页查看不到记录

REPEATABLE-READ:

可重复读,mysql数据库默认的隔离级别 --> 导致幻读的问题,如别的事务已经修改过数据,但是看到的还是旧数据;

例子:打开两个crt窗口,登录mysql,分别关闭自动提交功能和设置隔离级别为READ-COMMITTED

MariaDB [sunny]> SET @@session.autocommit=0;

MariaDB [sunny]> set @@session.tx_isolation="REPEATABLE-READ";

MariaDB [sunny]> start transaction;

在窗口1上执行

MariaDB [sunny]> insert into classlist values ("mei",5,99);

此时还没commit,在窗口1上可以看到新增的数据,但是窗口2上看不到新增加的数据

在窗口1上执行

MariaDB [sunny]> commit;

此时,窗口1上任然可以看到新增加的数据,但是窗口2上看不到新增的nu=5的数据,

窗口2以为没有nu=5的数据,但是窗口2要插入nu=5的数据,会出现报错重复数据的提示

MariaDB [sunny]> insert into classlist values ("mei2",5,98);

ERROR 1062 (23000): Duplicate entry '5' for key 'PRIMARY'

MariaDB [sunny]> select * from classlist;

+----------+----+-------+

| name     | nu | score |

+----------+----+-------+

| sunny    |  1 | 98.00 |

| chao     |  3 | 98.00 |

| tracy su |  6 | 95.00 |

+----------+----+-------+

如果要看到新增的数据,窗口2可以退出sql窗口,重新登录,就可以看到新增nu=5的数据

SERIALIZABLE:

串行化,隔离度最高;只有对方的事务结束(要么commit,要么rollback),另一窗口才能执行对同一表格的操作

例子:打开两个crt窗口,登录mysql,分别关闭自动提交功能和设置隔离级别为READ-COMMITTED

MariaDB [sunny]> SET @@session.autocommit=0;

MariaDB [sunny]> set @@session.tx_isolation="SERIALIZABLE";

MariaDB [sunny]> start transaction;

在窗口1上执行如下语句,但是不执行commit;自己操作后,没有确认,则别人也不能查看该表,因为已经该表琐死。只能在自己提交会回滚后,别人才能查询到结果。

delete from classlist where nu=8;

此时在窗口2上执行如下语句,那么窗口2的查询结果就出不来,等待时间超时后,就会出现报错

MariaDB [sunny]> select * from classlist;

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction