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
原文地址:http://blog.51cto.com/ghbsunny/2060554