• 事务隔离机制_悲观锁_乐观锁


    5. 事务并发处理
      a) 事务的特性:ACID
        i.Atomicity 原子性
        ii.Consistency 一致性
        iii.Isolation 隔离性
        iiii.Durability 持久性
      b) 事务并发时可能出现的问题
        i. 第一类丢失更新(Lost Update)

    时间 取款事务A 存款事务B
    T1 开始事务  
    T2   开始事务
    T3 查询账户余额为1000元  
    T4   查询账户余额为1000元
    T5  

    汇入100元把余额改为1100元

    T6   提交事务
    T7 取出100元把余额改为900元  
    T8 撤销事务  
    T9

    余额恢复为1000元(丢失更新)

     

        ii.脏读(Dirty Read)

    时间 取款事务A 转账事务B
    T1 开始事务  
    T2   开始事务
    T3   查询账户余额为1000元
    T4   汇入100元把余额改为1100元
    T5

    查询账户余额为1100元(读取脏数据)

     
    T6   回滚
    T7 取款 1100  
    T8 提交事务失败  

        iii.不可重复读(non-repeatable read) 

          在一个事务中前后两次读取的结果并不致,导致了不可重复读,会导致不一致的分析。

    时间 取款事务A 转账事务B
    T1 开始事务  
    T2   开始事务
    T3 查询账户余额为1000元  
    T4   汇入100元把余额改为1100元
    T5   提交事务
    T6 查询账户余额为1100元  
    T7 提交事务  

        iiii.第二类丢失更新——不可重复读的特殊情况(second lost update problem)

    时间 转账事务A 取款事务B
    T1   开始事务
    T2 开始事务  
    T3   查询账户余额为1000元
    T4 查询账户余额为1000元  
    T5   取出100元把余额改为900元
    T6   提交事务
    T7 汇入100元  
    T8 提交事务  
    T9

    把余额改为1100元(丢失更新)

     

        v.幻读(phantom read)

    时间 查询学生事务A 插入新学生事务B
    T1 开始事务  
    T2   开始事务
    T3 查询学生为10人  
    T4   插入一个新学生
    T5 查询学生为11人  
    T6   提交事务
    T7 提交事务  

    c) 数据库的事务隔离机制
      i. 查看 java.sql.Connection 文档
      ii.
        (1:read-uncommitted
           2:read-committed
           4:repeatable read
           8:serializable)
      1. 只要数据库支持事务,就不可能出现第一类丢失更新
      2. read-uncommitted 会出现 dirty read,phantom-read,non-repeatable read 问题
      3. read-commited 不会出现 dirty read.因为只有一个事务提交才会读出结果,但仍然会出现 non-repeatable 和 phantom-read
      4. repeatable read


    d) 设定 hibernate 的事务隔离级别
      i. hibernate.cfg.xml 配置文件中进行配置:hiberante.connection.isolation=2
      ii.用悲观锁解决 repeatable read 的问题(依赖于数据库的锁)
        1.select ... for update
        2.load(xx.class,i,LockMode.Upgrade),

       a) LockMode.NONE 无锁的机制,Transaction 结束时,切换到此模式

         b) LockMode.READ 在查询的时候 hibernate 会自动获取锁

         c) LockMode.WRITE insert update hibernate 或自动获取锁

       d) 以上三种锁的模式,是 hibernate 内部使用的

         e) LockMode.UPGRADE_NOWAIT Oracle 支持的锁的方式

        如下:

     1     @Test
     2     public void testPessimisticLock(){
     3         Session session = sf.getCurrentSession();
     4         session.beginTransaction();
     5         
     6         Account a = (Account) session.load(Account.class, 1,LockMode.UPGRADE);//一般用 UPGRADE
     7         int balance = a.getBalance();
     8         //do some caculations
     9         balance -= 10;
    10         a.setBalance(balance);
    11         
    12         session.getTransaction().commit();
    13     }

     e) Hibernate(JPA)乐观锁定(ReadCommitted)

     1 package com.bjsxt.hibernate;
     2 
     3 import javax.persistence.Entity;
     4 import javax.persistence.GeneratedValue;
     5 import javax.persistence.Id;
     6 
     7 @Entity
     8 public class Account {
     9     
    10     private Integer id;
    11     
    12     private int balance;
    13 
    14     @Id
    15     @GeneratedValue
    16     public Integer getId() {
    17         return id;
    18     }
    19 
    20     public void setId(Integer id) {
    21         this.id = id;
    22     }
    23 
    24     public int getBalance() {
    25         return balance;
    26     }
    27 
    28     public void setBalance(int balance) {
    29         this.balance = balance;
    30     }
    31     
    32 }

      保存:

     1     @Test
     2     public void testOptimisticLock(){
     3         Session session = sf.openSession();
     4         Session session2 = sf.openSession();
     5         
     6         session.beginTransaction();
     7         Account a1 = (Account) session.load(Account.class, 2);
     8         
     9         session2.beginTransaction();
    10         Account a2 = (Account) session2.load(Account.class, 2);
    11         
    12         a1.setBalance(900);
    13         a2.setBalance(1100);
    14         
    15         session.getTransaction().commit();
    16         System.out.println(a1.getVersion());
    17         
    18         session2.getTransaction().commit();//第二次提交时会对比 version 字段,如果值改变,则事务处理失败,回滚
    19         System.out.println(a2.getVersion());
    20         
    21         session.close();
    22         session2.close();
    23     }

    jar包链接: https://pan.baidu.com/s/1qYHdnbA 密码: p429

    悲观锁代码链接: https://pan.baidu.com/s/1o8Llad0 密码: 1x2x

    乐观锁代码链接: https://pan.baidu.com/s/1c1DhHtu 密码: ed4p

  • 相关阅读:
    任务调度之Quartz.Net配置文件
    任务调度之Quartz.Net可视化界面
    任务调度之Quartz.Net基础
    Asp.Net Core中完成拒绝访问功能
    Asp.Net Core Identity中基于角色授权
    Javascript 继承 图形化展示
    Try,Catch,Finally三块中如果有Return是怎么个运行顺序
    Autofac 一个使用Demo
    Autofac
    WCF代理是怎么工作的?用代码说话
  • 原文地址:https://www.cnblogs.com/ShawnYang/p/6774297.html
Copyright © 2020-2023  润新知