事务Transactions:一组原子性的SQL语句,或一个独立工作单元
事务日志:记录事务信息,实现undo,redo等故障恢复功能
ACID特性:
A:atomicity原子性;整个事务中的所有操作要么全部成功执行,要么全部
失败后回滚
C:consistency一致性;数据库总是从一个一致性状态转换为另一个一致性
状态
I:Isolation隔离性;一个事务所做出的操作在提交之前,是不能为其它事务
所见;隔离有多种隔离级别,实现并发
D:durability持久性;一旦事务提交,其所做的修改会永久保存于数据库中
Transaction生命周期
一、begin是开启事务:
MariaDB [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
MariaDB [hellodb]> begin;
Query OK, 0 rows affected (0.00 sec)
我自己插入一条记录,自己看看到:
MariaDB [hellodb]> insert teachers (name,age)values(‘abc‘,30);
Query OK, 1 row affected (0.01 sec)
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
| 7 | abc | 30 | NULL |
+-----+---------------+-----+--------+
5 rows in set (0.00 sec)
但是在另一终端上就看不到记录,还是4条:
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
rollback:撤销操作的命令,在begin后,可以撤销:
先修改tid=4的值,再撤销,就会恢复到从前,如下:
MariaDB [hellodb]> update teachers set age=100 where tid=4;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 7 | abc | 30 | NULL |
+-----+---------------+-----+--------+
MariaDB [hellodb]> rollback;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 93 | F |
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
二、我们重做begin后并commit提交:
MariaDB [hellodb]> begin;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> insert teachers (name,age)values(‘abc‘,30);
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> update teachers set age=100 where tid=4;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [hellodb]> commit;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 8 | abc | 30 | NULL |
+-----+---------------+-----+--------+
5 rows in set (0.00 sec) 可以查看更新的结果。
这时在另一终端上,也能同步查询出结果:
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 8 | abc | 30 | NULL |
+-----+---------------+-----+--------+
5 rows in set (0.00 sec)
这时的另一终端前后两次查询的结果是不同的,这种现象就不可重复读。
但是并不是所有的命令都能撤销,如下:
MariaDB [hellodb]> begin;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select * from courses;
+----------+----------------+
| CourseID | Course |
+----------+----------------+
| 1 | Hamo Gong |
| 2 | Kuihua Baodian |
| 3 | Jinshe Jianfa |
| 4 | Taiji Quan |
| 5 | Daiyu Zanghua |
| 6 | Weituo Zhang |
| 7 | Dagou Bangfa |
+----------+----------------+
7 rows in set (0.00 sec)
MariaDB [hellodb]> truncate table courses;
Query OK, 0 rows affected (0.01 sec)
MariaDB [hellodb]> commit;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> rollback;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select from courses;
Empty set (0.00 sec)
所以“ truncate ”不能撤销,因为它不记录日志,delete可以撤销。
在“ mysql ”中,delete之类的命令是系统自动提交的,如下:
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 8 | abc | 30 | NULL |
+-----+---------------+-----+--------+
5 rows in set (0.00 sec)
MariaDB [hellodb]> delete from teachers where tid=8;
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
因为默认的set autocommit=1
MariaDB [hellodb]> show variables like ‘autocommit‘;
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.01 sec)
事务支持保存点:savepoint 实现部分撤销;
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
RELEASE SAVEPOINT identifier
先存入数据,再savepoint:
MariaDB [hellodb]> insert teschers (name,age) values(‘a‘,20);
ERROR 1146 (42S02): Table ‘hellodb.teschers‘ doesn‘t exist
MariaDB [hellodb]> insert teachers (name,age) values(‘a‘,20);
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> insert teachers (name,age) values(‘b‘,30);
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> savepoint b;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> insert teachers (name,age) values(‘c‘,40);
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 9 | a | 20 | NULL |
| 10 | b | 30 | NULL |
| 11 | c | 40 | NULL |
+-----+---------------+-----+--------+
7 rows in set (0.00 sec)
MariaDB [hellodb]> rollback to b;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 9 | a | 20 | NULL |
| 10 | b | 30 | NULL |
+-----+---------------+-----+--------+
6 rows in set (0.00 sec)
MariaDB [hellodb]> rollback to a;
ERROR 1305 (42000): SAVEPOINT a does not exist
只有一次撤销机会,用过就没了。
事务隔离级别
事务隔离级别:从上至下更加严格
READ UNCOMMITTED 可读取到未提交数据,产生脏读
READ COMMITTED 可读取到提交数据,但未提交数据不可读,产
生不可重复读,即可读取到多个提交数据,导致每次读取数据不一致
REPEATABLE READ 可重复读,多次读取数据都一致,产生幻读,即
读取过程中,即使有其它提交的事务修改数据,仍只能读取到未修改
前的旧数据。此为MySQL默认设置
SERIALIZABILE 可串行化,未提交的读事务阻塞修改事务,或者未
提交的修改事务阻塞读事务。导致并发性能差
MVCC: 多版本并发控制,和事务级别相关
select @@ tx_isolation; 查看隔离级别
MariaDB [hellodb]> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)
接着,我们修改配置文件:/etc/my.cnf 加入:transaction-isolation=READ-UNCOMMITTED
现在是可读到未提交数据:
MariaDB [hellodb]> select @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set (0.00 sec
下面我们去做实验:1、READ UNCOMMITTED 可读取到未提交数据,产生脏读
MariaDB [hellodb]> begin; 开启事务
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select @@tx_isolation; 可读未提交数据(脏读)
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
MariaDB [hellodb]> insert teachers (name,age)values(‘mage‘,30);插入
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> select from teachers; 本机显示更新
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 5 | mage | 30 | NULL |
+-----+---------------+-----+--------+
5 rows in set (0.00 sec)
MariaDB [hellodb]> select from teachers;另一终端也显示更新
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 5 | mage | 30 | NULL |
+-----+---------------+-----+--------+
5 rows in set (0.01 sec)
rollback;撤销
MariaDB [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 5 | mage | 30 | NULL |
+-----+---------------+-----+--------+
5 rows in set (0.00 sec)
MariaDB [hellodb]> rollback;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
+-----+---------------+-----+--------+
4 rows in set (0.00 sec)
2、READ COMMITTED 修改配置文件
MariaDB [hellodb]> begin;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> insert teachers (name,age)values(‘mage‘,50);插入
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 5 | mage | 50 | NULL |
+-----+---------------+-----+--------+
5 rows in set (0.00 sec)
MariaDB [hellodb]> commit;提交
Query OK, 0 rows affected (0.01 sec)
MariaDB [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 5 | mage | 50 | NULL |
+-----+---------------+-----+--------+
5 rows in set (0.00 sec)
MariaDB [hellodb]> insert teachers (name,age)values(‘guo‘,40);再次插入
Query OK, 1 row affected (0.00 sec)
MariaDB [hellodb]> commit;
Query OK, 0 rows affected (0.00 sec)
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 5 | mage | 50 | NULL |
| 6 | guo | 40 | NULL |
+-----+---------------+-----+--------+
6 rows in set (0.00 sec)
在另一台终端上查看:
MariaDB [hellodb]> select from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 5 | mage | 50 | NULL |
+-----+---------------+-----+--------+
5 rows in set (0.00 sec)
MariaDB [hellodb]> select * from teachers;
+-----+---------------+-----+--------+
| TID | Name | Age | Gender |
+-----+---------------+-----+--------+
| 1 | Song Jiang | 45 | M |
| 2 | Zhang Sanfeng | 94 | M |
| 3 | Miejue Shitai | 77 | F |
| 4 | Lin Chaoying | 100 | F |
| 5 | mage | 50 | NULL |
| 6 | guo | 40 | NULL |
+-----+---------------+-----+--------+
6 rows in set (0.00 sec) 在一个事务中,两次不一样结果,所以就产生不可重复读。
3、REPEATABLE READ 可重复读 产生幻读,优:在一个事务中数据是一致的,缺:产生幻读,数据不是同步的
4、可串行化 优:数据在修改时,在同一事务中,一个在修改,一个在查询,就会卡住,只有在修改提交后,才能在另一台同一事务中同步查询到更新数据,串行性安全,并行性差,平时都用可重复读。串行性操作会自动加锁。
事务隔离级别:从上至下更加严格
? READ UNCOMMITTED 可读取到未提交数据,产生脏读
? READ COMMITTED 可读取到提交数据,但未提交数据不可读,产生不可重复读,即可读取到多个提交数据,导致每次读取数据不一致
? REPEATABLE READ 可重复读,多次读取数据都一致,产生幻读,即读取过程中,即使有其它提交的事务修改数据,仍只能读取到未修改前的旧数据。此为MySQL默认设置
? SERIALIZABILE 可串行化,未提交的读事务阻塞修改事务,或者未提交的修改事务阻塞读事务。导致并发性能差eg:insert teacher(name,age) values (‘abc‘,20)
?MVCC: 多版本并发控制,和事务级别
事务隔离级别
事务隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读
读未提交(read-uncommitted) 是 是 是 否
不可重复读(read-committed) 否 是 是 否
可重复读(repeatable-read) 否 否 是 否
串行化(serializable) 否 否 否 是
死锁:系统会自动识别,会牺牲其中一个事务,
MariaDB [hellodb]> begin;开启事务
?指定事务隔离级别:
?服务器变量tx_isolation指定,默认为REPEATABLE-READ,可在GLOBAL和
SESSION级进行设置
SET tx_isolation=‘‘
READ-UNCOMMITTED
READ-COMMITTED
REPEATABLE-READ
SERIALIZABLE
?服务器选项中指定
vim /etc/my.cnf
[mysqld]
transaction-isolation=SERIALIZABLE
三、事务日志:transaction log
事务型存储引擎自行管理和使用,建议和数据文件分开存放: redo log undo log
[root@centos7 ~]#cd /var/lib/mysql/
[root@centos7 mysql]#ll -b
total 28708
-rw-rw----. 1 mysql mysql 16384 Feb 21 15:09 aria_log.00000001
-rw-rw----. 1 mysql mysql 52 Feb 21 15:09 aria_log_control
drwx------. 2 mysql mysql 20 Feb 19 15:59 db1
drwx------. 2 mysql mysql 159 Feb 21 11:58 hellodb
-rw-r--r--. 1 root root 7786 Dec 1 2017 hellodb_innodb.sql
-rw-rw----. 1 mysql mysql 18874368 Feb 21 15:09 ibdata1
-rw-rw----. 1 mysql mysql 5242880 Feb 21 15:09 ib_logfile0两个5K大小的存
-rw-rw----. 1 mysql mysql 5242880 Feb 19 14:32 ib_logfile1 放日志的文件
drwx------. 2 mysql mysql 4096 Feb 19 14:32 mysql
drwx------. 2 mysql mysql 4096 Feb 19 14:32 performance_schema
drwx------ 2 mysql mysql 20 Feb 21 11:14 test
drwx------. 2 mysql mysql 20 Feb 19 20:07 wordpress
修改配置文件:vim /etc/my.cnf
[mysqld]
innodb_log_files_in_group=3 innodb_log_group_home_dir=/mysql/log
innodb_log_file_size=100M
#transaction-isolation=SERIALIZABLE (串行性操作会自动加锁)
我们创建一个文件夹,存放事务日志: mkdir /mysql/log/ --> chown mysql.mysql /mysql/log/
错误日志相关配置
SHOW GLOBAL VARIABLES LIKE ‘log_error‘
错误文件路径 log_error=/PATH/TO/LOG_ERROR_FILE
是否记录警告信息至错误日志文件log_warnings=1|0 默值为1
查看事务日志:
MariaDB [hellodb]> show variables like ‘%innodb_log%‘;
+---------------------------+---------+
| Variable_name | Value |
+---------------------------+---------+
| innodb_log_block_size | 512 |
| innodb_log_buffer_size | 8388608 |
| innodb_log_file_size | 5242880 |
| innodb_log_files_in_group | 2 |
| innodb_log_group_home_dir | ./ |
+---------------------------+---------+
5 rows in set (0.00 sec)
Innodb事务日志相关配置:
show variables like ‘%innodb_log%‘;
innodb_log_file_size 5242880 每个日志文件大小
innodb_log_files_in_group 2 日志组成员个数
innodb_log_group_home_dir ./ 事务文件路径
innodb_flush_log_at_trx_commit 默认为1
查看通用日志:show variable like ‘general%’;
MariaDB [hellodb]> show variables like ‘general%‘;
+------------------+-------------+
| Variable_name | Value |
+------------------+-------------+
| general_log | OFF |
| general_log_file | centos7.log |
+------------------+-------------+
2 rows in set (0.00 sec) set global general_log=on; 改为on状态
查看日志存放在哪里:show variable like ‘log_output%’;
跟踪日志:tail -f centos7.log
日志改名:set global log_output=‘table‘定义“表”,
慢查询日志:
log_slow_rate_limit = 1 多少次查询才记录,mariadb特有
log_slow_verbosity= Query_plan,explain 记录内容
log_slow_queries = OF同slow_query_log 新版已
在/etc/my.cnf 文件中,加入“long_query_tim=0.1” 这是慢查询的阀值
加入“slow_query_log”这是开始慢查询的日志
MariaDB [hellodb]> show variables like ‘long_query_time‘;
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 0.100000 |
+-----------------+----------+
1 row in set (0.00 sec)
MariaDB [hellodb]> select sleep(1) from teachers; 文件有多少个数据,就会sleep多少秒。
+----------+
| sleep(1) |
+----------+
| 0 |
| 0 |
| 0 |
| 0 |
| 0 |
| 0 |
+----------+
6 rows in set (6.00 sec)
select * from testlog where name=‘wang100000‘;这是全表扫描,
innodb_flush_log_at_trx_commit
?说明:设置为1,同时sync_binlog = 1表示最高级别的容错
innodb_use_global_flush_log_at_trx_commit的值确定是否可以使用SET语句
重置此变量
?1默认情况下,日志缓冲区将写入日志文件,并在每次事务后执行刷新到磁盘。
这是完全遵守ACID特性
?0提交时没有任何操作; 而是每秒执行一次日志缓冲区写入和刷新。 这样可以提
供更好的性能,但服务器崩溃可以清除最后一秒的事务
?2每次提交后都会写入日志缓冲区,但每秒都会进行一次刷新。 性能比0略好一
些,但操作系统或停电可能导致最后一秒的交易丢失
?3模拟MariaDB 5.5组提交(每组提交3个同步),此项MariaDB 10.0支持
?格式配置show variables like ‘binlog_format 默认是" STAEMENT " 语句型日志, delect from students; 进制只会记录下这一个命令。
基于行的日志,会记录“update students set age=now(); 这一个日志,
语句型的日志, 20;数值
二进制日志:
记录导致数据改变或潜在导致数据改变的SQL语句,记录已提交的日志,不依赖于存储引擎,记录提交的完整事务日志,有监控器的作用,数据库文件只记录结果不记录过程,它可进行数据还原,靠完全备份才能做到完全还原,它一直在记录变化的数据,要一直开启,减少数据丢失,要把数据库的数据文件和二进制日志分开存放,若单独丢失某一个都可以还原,二进制日志不能独立使用,依赖于备份,所以要时刻备份,用“row”行记录二进制的日志数据,虽然行的记录结果很多,保证不丢数据,因为要监控二进制日志的大小,在mysql中的折中办法是用“mixed”。
原文地址:https://blog.51cto.com/14128387/2353187