zoukankan      html  css  js  c++  java
  • 事务

    事务

    一、数据库事务

    它的思想:we are 伐木累。就是多个SQL语句(一个团队),要么所有执行success,不然就fail。

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

    二、ACID

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

    a)原子性

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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,实现了更大的原子,如下图。

    2

    b)一致性

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

    c)隔离性

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

    3

    但是聪明的小伙伴知道,如果事务完全隔离,每次只允许一个事务能访问数据库,那其他都是阻塞。会非常慢。

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

    d)持久性

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

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

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

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

    脏读: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),这时候避免这个情况只需要添加行级锁组织该行发生变化即可。

    四、事务隔离级别

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

    6

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

    好了,案例说了很多下面代码实战。

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

    五 、JDBC事务实战

    下面利用MYSQL JDBC驱动连接MySQL,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    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();
            }
     
        }
    }

    第 5、7行是连接数据库

    第 9 行:获取数据库元数据,这是包含数据库连接信息

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

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

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

    具体源码如下:

    4

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

    作者:泥瓦匠 原文链接:传送门

  • 相关阅读:
    Lombok 安装、入门
    详细解析@Resource和@Autowired的区别 , 以及@Qualifier的作用
    Spring中@Resource与@Autowired、@Qualifier的用法与区别
    springMVC整合swagger
    jetty maven插件
    【原创】Sagger使用
    Eclipse详细设置护眼背景色和字体颜色
    eclipse中相同代码的高亮显示
    Mybatis分页插件
    mybatis
  • 原文地址:https://www.cnblogs.com/meitanzai/p/5833508.html
Copyright © 2011-2022 走看看