一直很想对数据库事务作一点总结,今天终于静下心来小小的总结一下。 sql
1、数据库事务的特征 数据库
一、原子性 浏览器
原子,顾名思义,天然界中的最小粒子(尽管物理上原子还可分割成夸克的什么玩意,这个咱们就无论了)。定义一组操做集合,若是只执行一个子集,这就破坏的事务的目标,事务必须不可分割,要么所有执行,要么所有不执行。 安全
二、一致性 session
在事务完成时,全部数据必须保持一致的状态。例如:张三给李四转帐100,元,张三帐号扣除了100,而李四帐号却没有变化,这就违背了一致性。 多线程
三、隔离性 并发
多用户操做同一条数据时,必须时相互隔离,以避免A用户操做影响了B用户.。 分布式
四、持久性 高并发
一个事务成功了,那么就一定持久化到磁盘了,就算断电了,下次重启,数据依然正确无缺。 性能
2、几个有趣的现象
不少时候,咱们习惯这样描述咱们的系统,高并发、分布式、集群等等,对于一个多用户、多线程的应用,不可避免的共同访问相同的资源,若是没有一套规则去约束这些操做,势必要出乱子,这就是咱们要重点讨论的事务隔离。
咱们先来看看几个有趣现象:
一、脏读
期末考过了半个月,小明正在急切的查分,一遍一遍的刷新着浏览器,数学分数怎么还没出来??碰巧数学老师在录入分数,恰好录到小明90分,提交请求,刚好小明刷新,90分,欣喜若狂。而此时数学老师发现录入错误,撤销了事务,小明再次查询,分数消失,小明此时是各类猜想。
这个过程当中,有两个事务在操做同一条数据:以下表,T表明时间
事务1
|
事务2
|
T1开启事务
|
|
|
T2开启事务
|
|
T3数学老师开始录入分数90
|
T4小明查到分数90
|
|
|
T5老师发现录入错误回滚数据
|
T6小明忧伤的查不到分数了
|
|
T7提交事务
|
|
很明显,事务1读到了事务2未提交的数据。
二、不可重复读
最终小明查到了分数为59,伤心的要准备补考了,准备把成绩打印出来,发现打印出来的成绩是69,原来老师发现有道题目解题思路新颖,要额外给小明加10分。
事务1 |
事务2 |
T1事务开启 |
|
T2小明查到分数59 |
|
|
T3事务开启 |
|
T4修改分数为69 |
|
T5提交事务 |
T6小明打印成绩69 |
|
T7提交事务 |
|
三、幻读
小明一直在焦急的等待最后一门英语成绩,发现始终没有出来,便想把已经出来的成绩先打印,最后发现打印出来的有英语成绩。
事务1 |
事务2 |
T1事务开启 |
|
T2小明查分,不包括英语 |
|
|
T3开启事务 |
|
T4英语老师录入分数 |
|
T5提交事务 |
T6小明打印到了英语成绩 |
|
T7提交事务 |
|
注:有人要问了,不可重复读和幻读,一个德行,有什么区别,不可重复读是读到了修改数据,幻读是读到了新增的数据,有又有什么不一样呢,数据库的锁不同,下次分享。
3、事务的隔离级别
以上的现象,不一样的事务隔离级别,会产生对于的现象。
事务隔离级别:
一、读未提交(READ-UNCOMMITTED);
二、读已提交(READ-COMMITTED);
三、可重复读(REPEATABLE-READ);
四、序列化(SERIABLIABLE)
隔离级别 |
脏读 |
不可重复读 |
幻读 |
READ-UNCOMMITTED |
Y |
Y |
Y |
READ-COMMITTED |
N |
Y |
Y |
REPEATABLE-READ |
N |
N |
Y |
SERIALIZABLE |
N |
N |
N |
4、MySql的隔离级别和对应现象
Mysql默认的隔离级别是REPEATABLE-READ。
一、脏读
(1)、设定数据库隔离级别为READ-UNCOMMITTED;
(2)、A事务开启,查询,没查到数据;
(3)、B事务开启,修改分数,但不提交;
(4)、A事务查询,小明查到了分数90
(5)、B事务回滚
(6)、A事务再次查询,已经查不到;
(7)、A事务提交;
下面咱们看把隔离级别设置成READ-COMMITTED可否解决这个问题。
(1)、设定隔离级别为READ-COMMITTED;;
(2)、A事务查询
(3)、B事务修改,但不提交;
(4)、A事务再次查询,却查询不到;
(5)、B事务提交;
(6)、A事务再次查询,查询到了分数;
二、不可重复读
紧接着上面的例子,上面的A事务还没结束。
(1)、B事务再次修改分数提交;
(2)、A事务再次查询;
那么这个时候有同窗要问了,若是B事务没有提交,有C事务来修改小明的分数会怎么样??下面咱们就来看看:
很明显,C事务没法修改这条记录,这条记录已经被加锁。咱们略过这个小插曲。
两次读取的数据不同,这就是不可重复读。读到的是其余事务已提交的数据,这也是无可厚非,固然有些系统特别变态要求可重复读。
下面咱们看看REPEATABLE-READ,可否解决咱们的问题:
(1)、设定事务隔离级别为REPEATABLE-READ;
(2)、A事务开启,读数据;
(3)、B事务开启,修改数据,并提交;
(4)、A事务再次查询,发现结果没变;
很明显,在REPEATABLE-READ级别下,A事务读取数据是彻底不受其余事务影响的,这就解决了不可重复读的问题。
三、幻读
紧接着上面的例子,事务A再次查询,碰巧再次以前B事务新增了一条记录,英语成绩被录入进来。
(1)、B事务新增一条记录,并提交;
(2)、A事务再次查询;
这里有同窗就要奇怪了,为何没有查到英语成绩,理论上要出现幻读了,这是Why??
Mysql的可重复读的实现和其余数据库是有区别的,不会形成幻读,那么仍是要说说幻读,幻读,就是同一个事务内,屡次查询,读取到其余session 事务insert并已经提交的数据。
那么咱们来看看最后一个隔离级别SERIALIZABLE。
(1)、设置隔离级别为SERIALIZABLE
(2)、B事务开启,新增记录,并不提交;
(3)、A事务开启事务查询;
B事务没提交,A事务就阻塞,就连select也会阻塞,这就是串行化得名的缘由,只能顺序执行,全部安全级别最高,性能最低。
至于JDBC与隔离级别,请听下回分解。