事务

概念

事务是多条sql语句的集合,要么都成功,要么都失败,且事务是基于存储引擎实现的。

创建的事务都是基于DML语言来操作的


特点

1、原子性(atomicity):一个事务必须被视为一个不可分割的单元

2、一致性(consistency):数据库从一种状态切换到另一张状态 如:银行转账过程中,来回转金额的数量不会改变

3、隔离性(isolation):事务在提交之前对其他事务不可见

4、持久性(durablity):一旦事务提交,永久保存到数据库


事务的使用方法

开启事务

begin

start transaction

==如果执行第二次bigin,表示第一次的事务会自动提交,且不能回滚==

SHOW VARIABLES LIKE 'AUTOCOMMIT' 查看自动提交状态

SET autocommit=1(表示开启自动提交事务)0(表示关闭)

提交事务

commit

回滚

rollback

例:

mysql> CREATE TABLE bank(
    -> name VARCHAR(30),
    -> money DECIMAL(8,2));
mysql> INSERT INTO bank('ljj',20000),('yj',5000);
mysql> INSERT INTO bank VALUES('ljj',20000),('yj',5000);
mysql> SELECT * FROM bank;
+------+----------+
| name | money    |
+------+----------+
| ljj  | 20000.00 |
| yj   |  5000.00 |
+------+----------+
mysql> BEGIN;            /*开启事务*/
mysql> UPDATE bank SET money=money-20000 WHERE name='ljj';

mysql> SELECT * FROM bank;
+------+---------+
| name | money   |
+------+---------+
| ljj  |    0.00 |
| yj   | 5000.00 |
+------+---------+
mysql> rollback;        /*回滚数据*/

mysql> SELECT * FROM bank;
+------+----------+
| name | money    |
+------+----------+
| ljj  | 20000.00 |
| yj   |  5000.00 |
+------+----------+

mysql> UPDATE bank SET money=money-20000 WHERE name='ljj';

mysql> COMMIT;        /*提交事务*/

mysql> ROLLBACK;        /*回滚*/

mysql> SELECT * FROM bank;                /*发现没用*/                                                
+------+---------+
| name | money   |
+------+---------+
| ljj  |    0.00 |
| yj   | 5000.00 |
+------+---------+

mysql> UPDATE bank SET money=money+20000 WHERE name='yj';

mysql> SELECT * FROM bank;
+------+----------+
| name | money    |
+------+----------+
| ljj  |     0.00 |
| yj   | 25000.00 |
+------+----------+
2 rows in set (0.00 sec)

mysql> COMMIT;        /*提交事务*/

mysql隔离级别

设置隔离级别语法:SET SESSION TX_SIOLATION=隔离级别

查看隔离级别语法:SELECT @@TX_ISOLATION;

(1)read-uncommitted 未提交读

​ 未提交读的问题:

​ 1):脏读:事务未提交时,对其他事务可见

​ 2):不可重复读:事务提交后,不能对数据进行重复读取

​ 3):幻读:数据存在但是无法查看

例:

/*开启两个终端做如下设置*/1终端2终端
mysql> SET SESSION TX_ISOLATION='READ-UNCOMMITTED';        /*设置为未提交读*/
Query OK, 0 rows affected (0.00 sec)

mysql> BEGIN;            /*同时开启两个事务*/

/*其中1终端提交掉一个事务,并创建表并写入数据*/
mysql> COMMIT;
mysql> CREATE TABLE student(                /*创建测试表*/
    -> id INT NOT NULL AUTO_INCREMENT,
    -> name VARCHAR(30) NOT NULL,
    -> PRIMARY KEY(id));
mysql> BEGIN;        /*再次开启事务*/
mysql> INSERT INTO student(name) VALUES('ljj');        /*写入数据并没有提交*/

/*切换到2终端,进行查看student表数据*/
mysql> select * from student;        /*发现可以读取数据*/
+----+------+
| id | name |
+----+------+
|  1 | ljj  |
+----+------+

(2)read-committed 已提交读

解决了未提交读脏读的问题,不可重复读的问题依然没有解决,幻读还是存在

例:

/*同样是两个终端中设置*/1终端2终端
mysql> SET SESSION TX_ISOLATION='READ-COMMITTED';    /*设置为已提交度的隔离级别*/
mysql> BEGIN;
/*在1终端,继续写入数据*/
mysql> INSERT INTO student(name) VALUES('sy');
/*切换2终端,发现查看不到sy这条数据*/
mysql> select * from student;
+----+------+
| id | name |
+----+------+
|  1 | ljj  |
|  2 | yj   |
+----+------+
/*回到1终端,将事务提交*/
mysql> COMMIT;
/*再次切换2终端查看*/
mysql> select * from student;        /*只有提交事务之后才可以查看数据*/
+----+------+
| id | name |
+----+------+
|  1 | ljj  |
|  2 | yj   |
|  3 | sy   |
+----+------+

(3)repeatable-read 可重复读

没有脏读问题,没有不可重复读问题

/*同样是两个终端中设置*/1终端2终端
mysql> SET SESSION TX_ISOLATION='READ-COMMITTED';    /*设置为不可重复读的隔离级别*/
mysql> BEGIN;            /*开启事务*/
/*在1终端,更新数据*/
mysql> UPDATE student SET name='a' WHERE id =1;
mysql> SELECT * FROM student;        /*在本终端可以看到*/
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | yj   |
|  3 | sy   |
+----+------+
mysql> COMMIT;            /*提交事务*/
/*在2终端查看表,发现还没有变*/(可重复读)
mysql> select * from student;
+----+------+
| id | name |
+----+------+
|  1 | ljj  |
|  2 | yj   |
|  3 | sy   |
+----+------+
/*将2终端的事务提交*/
mysql> COMMIT;            /*提交事务*/
mysql> select * from student;      /*发现可以看到了*/
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | yj   |
|  3 | sy   |
+----+------+

(4)serializable 可串行读

最高的隔离级别,解决一切问题

将事务进行排序,逐一执行

/*同样是两个终端中设置*/1终端和2终端
mysql> SET SESSION TX_ISOLATION='SERIALIZABLE';            /*设置为可串行读*/
mysql> BEGIN;
/*用1终端查看数据可以正常查看*/
/*切换2终端,进行写入数据*/
mysql> INSERT INTO student(name) VALUES('b');        /*会一直卡着,直到报错*/(加了写锁)
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
/*将1终端事务提交后,发现w2终端可以写入b数据*/
/*再次切换回1终端,开启一个事务*/
mysql> BEGIN;
mysql> SELECT * FROM student;        /*不能查看数据*/
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

缺点:逐一执行之后,效率变低,并发低

读锁

共享锁,s锁,如果事务T对于A加了一个s锁,其他事务不能对A加写锁,但是可以对A加读锁,直到T释放对A的加锁,能读不能写。

写锁

排他锁,x锁,如果事务T对A加了一个x锁,其他事务不能对A加任何锁,直到T释放对A的x锁,保证数据既不能读也不能写

表锁

操作对象是表,属于开销最低但是并发也最低的策略,如果事务T对表加读锁,那么其他事务可读不可写,操作对象为整个表。

行级别锁

将表中的数据进行加锁,不会锁整个表,仅锁住使用的数据,对于该表的其他数据来说,其他事务仍可以对数据进行操作,并发高但是开销大

MVCC(InnoDB)

属于锁的妥协机制,在很多情况下避免使用锁,提供更小的开销,允许非阻塞式读取,

优点:在读取数据时,对写数据的锁要求不冲突,不会阻塞写,也不会阻塞读。

事务保存点

设置事务保存点:SAVEPOINT 保存点名

回滚至指定保存点:ROLLBACK TO 保存点名

保存点只适用于事务,对于事务之外的数据没有任何作用

mysql> CREATE TABLE student(id INT NOT NULL PRIMARY KEY,grade DECIMAL(8,2));
/*创建测试表*/

mysql> INSERT INTO student VALUES(1,80.2),(2,90);
/*创建测试数据*/

mysql> BEGIN;        /*开始事务*/

mysql> INSERT INTO student VALUES(3,84.9);    /*插入一条数据*/

mysql> SAVEPOINT A;            /*将上一条数据添加保存点A*/

mysql> INSERT INTO student VALUES(4,95.5);        /*插入一条数据*/

mysql> SAVEPOINT B;        /*将开始事务到上条数据添加保存点B*/

mysql> INSERT INTO student VALUES(5,50);    /*插入一条数据*/

mysql> SAVEPOINT C;        /*从开始事务到上条数据添加保存点C*/

mysql> INSERT INTO student VALUES(6,1);    /*在插入一条数据*/

mysql> SELECT * FROM  student;        /*查看表中数据*/
+----+-------+
| id | grade |
+----+-------+
|  1 | 80.20 |
|  2 | 90.00 |
|  3 | 84.90 |
|  4 | 95.50 |
|  5 | 50.00 |
|  6 |  1.00 |
+----+-------+
6 rows in set (0.00 sec)

mysql> ROLLBACK TO C;        /*回滚到保存点C*/

mysql> SELECT * FROM  student;
+----+-------+
| id | grade |
+----+-------+
|  1 | 80.20 |
|  2 | 90.00 |
|  3 | 84.90 |
|  4 | 95.50 |
|  5 | 50.00 |
+----+-------+
5 rows in set (0.00 sec)

mysql> ROLLBACK TO A;            /*回滚到保存点A*/

mysql> SELECT * FROM  student;    
+----+-------+
| id | grade |
+----+-------+
|  1 | 80.20 |
|  2 | 90.00 |
|  3 | 84.90 |
+----+-------+
mysql> ROLLBACK TO B;        /*保存点B已经消失*/        
ERROR 1305 (42000): SAVEPOINT C does not exist

评论




正在载入...
PoweredHexo
HostedAliyun
DNSAliyun
ThemeVolantis
UV
PV
BY-NC-SA 4.0