欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据库事务和隔离级别的理解

程序员文章站 2022-06-14 17:13:31
...

数据库事务和隔离级别的理解

1.事务的概念

事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功

2. MySQL数据库事务操作命令

​ 直接通过例子来说明

1.事务开始但没有提交

start transaction事务开始
mysql> start transaction;
Query OK, 0 rows affected

mysql> update product set price=price+100 where id=3;
Query OK, 1 row affected
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update product set price=price-100 where id=4;
Query OK, 1 row affected
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from product;
+----+----------+-------+-----+
| id | name     | price | num |
+----+----------+-------+-----+
|  3 | nike     |   988 |   2 |
|  4 | ads      |   588 |   2 |
+----+----------+-------+-----+

​ 当我直接关闭当前的dos窗口,没有提交事务的时候再次select会发现之前的操作没有成功。

mysql> select * from product;
+----+----------+-------+-----+
| id | name     | price | num |
+----+----------+-------+-----+
|  3 | nike     |   888 |   2 |
|  4 | ads      |   688 |   2 |
+----+----------+-------+-----+

2.事务开始并提交

mysql> start transaction;
Query OK, 0 rows affected

mysql> update product set price=price+100 where id=3;
Query OK, 1 row affected
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update product set price=price-100 where id=4;
Query OK, 1 row affected
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected

mysql> select * from product;
+----+----------+-------+-----+
| id | name     | price | num |
+----+----------+-------+-----+
|  3 | nike     |   988 |   2 |
|  4 | ads      |   588 |   2 |
+----+----------+-------+-----+

3.回滚操作rollback(在commit之前才有效)

mysql> start transaction;
Query OK, 0 rows affected

mysql> update product set price=price+100 where id=2;
Query OK, 1 row affected
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update product set price=price+100 where id=1;
Query OK, 1 row affected
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from product;
+----+----------+-------+-----+
| id | name     | price | num |
+----+----------+-------+-----+
|  1 | 伊利     |   168 |   1 |
|  2 | 蒙牛     |   188 |   1 |
+----+----------+-------+-----+

mysql> rollback; 回滚
Query OK, 0 rows affected

mysql> select * from product;
+----+----------+-------+-----+
| id | name     | price | num |
+----+----------+-------+-----+
|  1 | 伊利     |    68 |   1 |
|  2 | 蒙牛     |    88 |   1 |
+----+----------+-------+-----+

3.JDBC中使用事务

​ 当Jdbc程序向数据库获得一个Connection对象时,默认情况下这个Connection对象会自动向数据库提交在它上面发送的SQL语句。若想关闭这种默认提交方式,让多条SQL在一个事务中执行,可使用下列的JDBC控制事务语句

  • Connection.setAutoCommit(false);//开启事务(start transaction)
  • Connection.rollback();//回滚事务(rollback)
  • Connection.commit();//提交事务(commit)

具体有关JDBC连接数据库的操作可以看这篇文章

4.事务的四大特性

1.原子性(Atomicity)

​ 事务是一个不可分割的单位,事务中的操作要么全部成功,要么全部失败。

2.一致性(Consistency)

​ 事务必须使数据库从一个一致性状态转变到另一个一致性状态;举个例子:A和B的总额为2000,无论他们之间如何转账,他们的总金额必须不变,这就是一致性。

3.隔离性(isolation)

​ 多个用户并发访问数据库时,数据库为每个用户开启事务,不会被其他事务操作所影响,多个并发事务操作互相隔离。这个隔离性有四种级别。

4.持久性(Durability)

​ 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

5.并发事务可能出现的问题

5.1.脏读

​ 事务A读取了事务B更新的数据,然后事务B回滚了,那么事务A读取的数据是脏数据,因为事务A读取了事务B未提交的数据。

5.2.不可重复读

​ 事务A多次读取同一个数据,但是事务B在事务A的读取间隙更新并提交了数据,导致事务A读取结果不一致。

5.3.幻读

​ 这里经常会和不可重复读弄混淆,首先明白一点幻读并不是说“一个事务内进行两次相同操作居然得到了不一样的结果” 直接从例子入手:

T1: select * from test where id=1;

T2: insert into test(id,name) values(1,“A”) ;

T1: insert into test(id,name) values(1,“A”) ;

T1:检索id=1的数据,发现没有,插入。

T2:干扰T1事务的进行,在T1事务插入数据之前,先插入数据提交。

T1:此时T1插入数据,会报主键冲突。

​ 对于T1来说第一次的查询并不能支持插入操作,但实际上是可以的,T1这里就是发生了幻读,数据就像凭空出现的一样。

​ 所以 mysql 的幻读并非什么读取两次返回结果集不同,而是事务在插入事先检测不存在的记录时,惊奇的发现这些数据已经存在了,之前的检测读获取到的数据如同鬼影一般。

​ 这里要灵活的理解读取的意思,第一次select是读取,第二次的 insert 其实也属于隐式的读取,只不过是在 mysql 的机制中读取的,插入数据也是要先读取一下有没有主键冲突才能决定是否执行插入。

不可重复读侧重表达 读-读,幻读则是说 读-写,用写来证实读的是鬼影。

6.事务的隔离级别

6.1.读未提交(read uncommitted)

​ 可以读取未提交的数据,会出现上面的脏读现象(此隔离级别不会使用,不做解释)

6.2.读已提交(read committed)

​ 不能读取未提交的数据,这里就防止了脏读现象,但是避免不了不可重复读

时间 事务A 事务B
T1 开始事务
T2 开始事务
T3 查询余额1000
T4 查询余额100
T5 取出1000,余额0
T6 提交
T7 查询余额0
T8 提交

从上面我们可以看出事务A什么都没做 只是查询了两次数据,余额就从1000变成0

6.3.可重复读(repeatable-read)(MySQL/InnoDB下的默认级别)

​ 针对当前读,RR隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),不存在幻读现象。

6.4.串行化(serializable)

​ 从MVCC并发控制退化为基于锁的并发控制。不区别快照读与当前读,所有的读操作均为当前读,读加读锁 (S锁),写加写锁 (X锁)。

​ Serializable隔离级别下,读写冲突,因此并发度急剧下降,在MySQL/InnoDB下不建议使用。

有关mysql加锁情况这篇文章有详细的解释:https://blog.csdn.net/qq_38238296/article/details/88362999