图解 & 深刻浅出JavaWeb:事务必会必知

事务,你们所熟悉的事务(Transcation),基本上会就往Spring事务靠。其实Spring事务管理基于底层数据库自己的事务处理机制。数据库事务的基础,是掌握Spring事务管理的基础。这篇总结下数据库事务。java

1、数据库事务

它的思想:we are 伐木累。就是多个SQL语句(一个团队),要么全部执行success,否则就fail。git

它最终的目标:数据不会被破坏。即事务操做成功,数据的结果和业务期待的结果是一致的。这也就是ACID中的一致性(Consistency)。那什么是ACID呢?github

 

2、ACID

上面是思想,牛人立刻根据思想建模,DBMS中数据库事务知足4各特性,即原子性、一致性、隔离性和持久性。下面一一辈子动解释:sql

a)原子性数据库

原子是物质的最小单元,即不可再分。安全

例如,以MySQL为例,每个简单的 SQL 语句即包含在一个事务中,具备原子性。这时候有人问了,那多个SQL呢?并发

BEGIN TRANSACTION;



INSERT INTO `test`.`city` (`state`, `country`, `name`)



VALUES



('1', 'China', 'CHINA','错误语句多了个VALUE');



INSERT INTO `test`.`city` (`state`, `country`, `name`)



VALUES



('1', 'China', 'CHINA');



COMMIT;


结果:执行不经过。行3-5:为一个错误SQL。行6-8:是一个正确的SQL。它们各自被包裹在各自的隐式事务中,即Read Uncommited。T-all包裹了上面具备原子性的T-1和T-2,实现了更大的原子,以下图。socket

2

b)一致性分布式

终极目标:数据不会被破坏。(这不是废话?确实有点)具体说,事务操做成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。举个栗子:两句UPDATE语句,从A帐户转帐到B帐户,无论成功失败,A和B帐户的总额是不变的。高并发

c)隔离性

隔离:表示互不干扰。事务与事务之间没法干扰,即每一个事务独立,不会交叉。这样可让多个线程并发访问数据库。如图:

3

可是聪明的小伙伴知道,若是事务彻底隔离,每次只容许一个事务能访问数据库,那其余都是阻塞。会很是慢。

可是聪明的小伙伴也知道,这样会形成数据的并发问题。(是的,在下面第三节讲)。

d)持久性

数据必须持久化到数据库(存储在磁盘)中。已提交的事务,即便在提交后数据库崩溃,重启数据库时也可以根据日志对未持久化的数据进行重执行操做。(同窗会问,那没提交的事务呢?那就悲剧了(>﹏<))

小结:数据的一致性是最终目标,其余特性都是其要求或手段。

 

3、隔离性中的问题:脏读、不可重复读和幻读

对应上面的隔离性,事务并发访问的时候会出现:脏读、不可重复读和幻读。案例转自勇哥博客

脏读:A事务读取了B事务未提交的更改数据。通常数据库事务默认不容许该问题出现。

好比这里查询应该是1500,如今出现了脏读。

     
时间 事务 A(存款) 事务 B(取款)
T1 开始事务  
T2   开始事务
T3   查询余额(1000 元)
T4   取出 1000 元(余额 0 元)
T5 查询余额(0 元)  
T6   撤销事务(余额恢复为 1000 元)
T7 存入 500 元(余额 500 元)  
T8 提交事务  

不可重复读:A事务读取了B事务已提交的更改数据。

幻读:A事务读取了B事务提交的新增数据。

上面的案例脑补吧,主要仍是看下面。

 

不可重复读和幻读区别:一个更改,一个新增数据。其实两个区别在于一个是新增(insert语句),处理幻读这个操做须要加表级别的锁,将整个表锁定,防止新增数据形成幻读。另外一个则是更改(update delete),这时候避免这个状况只须要添加行级锁组织该行发生变化便可。

 

4、事务隔离级别

既要求高的隔离性(安全性),又要求高并发性。这种是不可能的任务。根据各类锁的操做机制出现了一个事务隔离级别。即相同状况下的输入,不一样隔离级别结果不一样。为啥了,固然是在并发性和安全性的抉择。如图:

6

按着图说的,根据程序的并发性和安全性的抉择。鱼和熊掌不可兼得也~ 但分布式的时候,能够吧安全性关键的单独分布式锁。

好了,案例说了不少下面代码实战。

 

ps: 休息下,泥瓦匠的代码都会这github上~ ,这段代码地址:https://github.com/JeffLi1993/jee-component-learning

 

五 、JDBC事务实战

下面利用MYSQL JDBC驱动链接MySQL,代码以下:

public class TransactionLevels extends BaseJDBC {

    public static void main(String[] args) {

        try {

            // 加载数据库驱动

            Class.forName(DRIVER);

            // 数据库链接

            Connection conn = DriverManager.getConnection(URL,USER,PWD);

            // 数据库元数据

            DatabaseMetaData metaData = conn.getMetaData();



            // 是否支持事务

            boolean isSupport = metaData.supportsTransactions();

            System.out.println(isSupport);

            // 是否支持的事务

            boolean isSupportLevel = metaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE);

            System.out.println(isSupportLevel);

            // 获取默认事务

            int defaultIsolation = metaData.getDefaultTransactionIsolation();

            System.out.println(defaultIsolation);



            /** 关闭数据库链接 */

            if (conn != null) {

                try {

                    conn.close();

                } catch (SQLException e) {

                    e.printStackTrace();

                }

            }

        } catch (Exception e) {

            e.printStackTrace();

        }



    }

}


第 9 行:获取数据库元数据,这是包含数据库链接信息第 五、7行是链接数据库

第 12 行:从元数据中,判断是否支持事务

第 15 行:从元数据中,判断是否支持事务级别 TRANSACTION_SERIALIZABLE

第 18 行:这里能够看出MySQL默认支持的事务级别是 READ_COMMITTED,默认会隔离脏读。

具体源码以下:

4

所以在安全性要求不高,支持高并发的状况下,选择MySQL默认事务等级。但在安全性极高,几乎不会出现高并发状况下,选择更高的事务等级。根据上小节的图一幕了然。

 

6、补充

关于事务,还有你们熟悉的Spring事务管理、具体数据库事务的实现,推荐一本书《MySQL技术内幕InnoDB存储引擎 》。

下一篇:ThreadLocal的工做机制,揭示Spring事务同步管理器的工做原理

如以上文章或连接对你有帮助的话,别忘了分享到朋友圈,让更多的人阅读这篇文章。


 

标签:Transcation事务

相关文章
相关标签/搜索