Hibernate事务相关内容:

  (1) 事务四大特性(简称ACID):

    (1)原子性(Atomicity)
      事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行。
    (2)一致性(Consistency)
      几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。

    (3)隔离性(Isolation)
      事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
    (4)持久性(Durability)
      对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。

  (2) 事务并发执行时会出现的四大问题:

    (1) 更新丢失,又分为两类:

      (1)回滚更新丢失:

        A、B事务同时读取某数据,并均做修改。A事务先做了提交,而B事务又做回滚。此时,A事务提交的更新数据丢失。

        对应实例:回滚更新丢失在一般的数据库中不会存在,因为数据库最低的事务隔离级别已经解决了这个问题。

      (2)提交更新丢失:

        A、B事务同时读取某数据,并均做修改。A事务先做了提交,然后B事务也做提交。此时,A事务提交的更新数据会被B事务的提交给覆盖。

        对应实例:

         1. 假设当当网上用户下单买了本书,这时数据库中有条订单号为 001的订单,其中有个status字段是’有效’,表示该订单是有效的;
           2. 后台管理人员查询到这条001的订单,并且看到状态是有效的
           3. 用户发现下单的时候下错了,于是撤销订单,假设运行这样一条 SQL: update order_table set status = ‘取消’ where order_id = 001;
           4. 后台管理人员由于在2这步看到状态有效的,这时,虽然用户在3 这步已经撤销了订单,可是管理人员并未刷新界面,看到的订单状态还是有效的,于是点击”发货”按钮,将该订单发到物流部门,同时运行类似如下SQL,将订单状态改成已发货:update order_table set status = ‘已发货’ where order_id = 001
         

         如果当当的系统这样实现,显然不对了,肯定要挨骂了,明明已经取消了订单,为什么还会发货呢?而且确实取消订单的操作发生在发货操作之前啊。 因为在这样的实现下,后台管理人员无论怎么做都有可能会出错,因为他打开系统看到有效的订单和他点发货之间肯定有个时间差,在这个时间差的时候总是存在用户取消订单的可能。

    (2)脏读:

      即读取到不正确的数据,因为A事务可能还没提交最终数据,B事务就读取了中途的数据,一旦A事务回滚了,这个数据就是是不正确的。

      对应示例: 公司发工资了,领导把5000元打到singo的账号上,但是该事务并未提交,而singo正好去查看账户,发现工资已经到账,是5000元整,非常高兴。可是不幸的是,领导发现发给singo的工资金额不对,是2000元,于是迅速回滚了事务,修改金额后,将事务提交,最后singo实际的工资只有2000元,singo空欢喜一场。

    (3)不可重复读:

      A事务读取某一数据后,B事务对其做了修改,当A事务再次读该数据时得到与前一次不同的值。

      对应示例: singo拿着工资卡去消费,系统读取到卡里确实有2000元,而此时她的老婆也正好在网上转账,把singo工资卡的2000元转到另一账户,并在singo之前提交了事务,当singo扣款时,系统检查到singo的工资卡已经没有钱,扣款失败,singo十分纳闷,明明卡里有钱,为何......

    (4)幻读:

      A事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据。这是因为在两次查询过程中有B事务插入数据造成的。

      对应示例:singo的老婆工作在银行部门,她时常通过银行内部系统查看singo的信用卡消费记录。有一天,她正在查询到singo当月信用卡的总消费金额(select sum(amount) from transaction where month = 本月)为80元,而singo此时正好在外面胡吃海塞后在收银台买单,消费1000元,即新增了一条1000元的消费记录(insert transaction ... ),并提交了事务,随后singo的老婆将singo当月信用卡消费的明细打印到A4纸上,却发现消费总额为1080元,singo的老婆很诧异,以为出现了幻觉,幻读就这样产生了。

  (3)事务隔离级别及对应会出现的问题:

    (1)Read uncommitted(未授权读取、读未提交):

      写事务阻止其他写事务,但是没有阻止其他读事务。避免了回滚更新丢失,却可能出现脏读。

    (2)Read committed(授权读取、读提交):

      写事务会阻止其他读写事务。读事务不会阻止其他任何事务。避免了脏读,但是却可能出现不可重复读。

    (3)Repeatable read(可重复读取):

      读事务会阻止其他写事务,但是不会阻止其他读事务。避免了不可重复读和脏读,但是有时可能出现幻读。

      可重复读阻止的写事务包括update和delete(只给存在的表加上了锁),但是不包括insert(新行不存在,所以没有办法加锁),所以一个事务第一次读取可能读取到了10条记录,但是第二次可能读取到11条,这就是幻读。

    (4)Serializable(序列化):

      提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。

      序列化是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读。

    大多数数据库的默认级别就是Read committed,比如Sql Server , Oracle。
    MYSQL的默认隔离级别就是Repeatable read。

   (4)提交更新丢失问题的解决:

     方法一,使用乐观锁(含义:这样的问题是小概率的,最后一步做更新的时候再锁住,免得锁住时间太长影响其他人做有关操作):

      乐观锁使用方法一:很简单,就是使用前面所说的这样一条SQL,这其实是所谓使用”前镜像”的方式来保证需要更新的数据是符合要求的,
        update order_table set status = ‘已发货’ where order_id = 001 and status = ‘有效’
      乐观锁使用方法二:使用版本列[比如时间戳或版本号]
        时间戳:这个方法比较简单,也最常用,就是在数据库表格中加一列last_modified_date,就是最后更新的时间,每次用户端更新的时候都将这列设成 systimestamp,当前系统时间;
        然后每次服务端更新的时候,就改成这样 update order_table set status = ‘已发货’ where order_id = 001 and last_modified_date = old (上次查看时的系统时间),last_modified_date这样,就可以检验出数据库的值是否在上次查看和这次更新的时候发生了变化,如果发生了变化,那么last_modified_date就变化了,以后的更新就会返回更新了0行,系统就可以通知用户数据发生了变化,然后选择刷新数据或者其他流程。

        版本号:用户端和服务端事务从数据库中读取数据时同时会读出一个数据版本号。当用户端事务将修改过的数据写入到数据库中时,会使版本号增1。当服务端事务发生回滚或覆盖时,会首先对比自己数据的版本号与数据库中数据的版本号。若它们相等,则说明数据库中数据没有发生变化,服务端事务可以将数据将修改写入到数据中。若小于数据库中的版本号,则说明用户端事务已经修改过该数据,将抛出异常。
    方法二,使用悲观锁(含义:这样的问题是高概率的,最好一开始就锁住,免得像使用乐观锁的时候,更新老是失败):

      服务端查询一条记录,并试图后续要做更新的时候,那么在查询的时候使用select *** for update nowait 语句,通过添加for update nowait语句,将这条记录锁住,避免其他用户更新,从而保证后续的更新是在正确的状态下更新的。

      但是存在一个问题:如果打开页面做查询的时候就将记录锁住,并且保持这个连接,那对连接的占用太长了,整个系统能承受的并发量就很小了。以oracle 10g为例,默认情况下,最大连接数是150,也就是说最多只能承受150个用户同时访问了。

    方法选择:乐观锁会导致更新失败频繁,悲观锁会降低并发性能。所以,一般在更新频繁的状况中使用悲观锁,其他情况用乐观锁较好。

  (5)Hibernate代码:

    (1)设置Hibernate事务隔离级别:

      在Hibernate的配置文件中可以显示的配置数据库事务隔离级别。每一个隔离级别用一个整数表示:

        8 - Serializable 串行化
        4 - Repeatable Read 可重复读
        2 - Read Commited 可读已提交
        1 - Read Uncommited 可读未提交

      在hibernate.cfg.xml中使用hibernate.connection.isolation参数配置数据库事务隔离级别。

    (2)乐观锁代码:

      在Hibernate映射文件的<class/>标签中,有一个子标签<version/>,其name属性用于指定作为版本的属性名称。其还有一个子标签<timestamp/>用于指定作为时间戳的属性名称。

      这两个子标签的用法相同,不同的是,作为版本的属性要求其类型为int,而作为时间戳的属性,要求为其类型为java.sql.timestamp。

      例如映射文件中是<version name="version" column="tversion"/>,则实体类中定义一个属性private int version;

      其他的事情由系统自己维护。

    (3)悲观锁代码:

      在测试代码中锁定,不需要修改实体类:

 @Test
public void test01_SQL() {
//1. 获取Session
Session session = HbnUtils.getSession();
try {
//2. 开启事务
session.beginTransaction();
//3. 操作
//悲观锁中的写锁
//Student student = session.get(Student.class, 2, LockMode.PESSIMISTIC_WRITE);
//悲观锁中的读锁
Student student = session.get(Student.class, 2, LockMode.PESSIMISTIC_READ);
System.out.println(student);
//4. 事务提交
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
//5. 事务回滚
session.getTransaction().rollback();
}
}

      session.get方法的第三个参数就是用来设置悲观锁的,使用第三个参数之后,我们每次发送的SQL语句都会加上"for update"用于告诉数据库锁定相关数据。

Hibernate5笔记8--Hibernate事务相关内容的更多相关文章

  1. MySQL学习笔记-事务相关话题

    事务机制 事务(Transaction)是数据库区别于文件系统的重要特性之一.事务会把数据库从一种一致状态转换为另一个种一致状态.在数据库提交工作时,可以确保其要么所有修改都已经保存了,要么所有修改都 ...

  2. 学习笔记之html5相关内容

    写一下昨天学习的html5的相关内容,首先谈下初次接触html5的感受.以前总是听说html5是如何的强大,如何的将要改变世界.总是充满了神秘感.首先来谈一下我接触的第一个属性是  input的里面的 ...

  3. Hibernate 事务和并发控制

    首先关于Hibernate事务控制,下面是非常权威的资料, https://docs.jboss.org/hibernate/orm/4.0/devguide/en-US/html/ch02.html ...

  4. Spring的事务管理和数据库事务相关知识

    1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱.         比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱. ...

  5. Spring 源码学习笔记11——Spring事务

    Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...

  6. linux用户权限相关内容查看

    linux用户权限相关内容查看 1   用户信息 创建用户一个名为 webuser 的账号,并填写相应的信息: root@iZ94fabhqhuZ:~# adduser webuser Adding ...

  7. (转)Hibernate事务管理

    Hibernate的事务管理 事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整,或者在修改时受到用户干扰.作为一名软件设计 ...

  8. hibernate学习笔记之一 hibernate简介

    Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架 hibernate可以自动生成SQL语句,自 ...

  9. hibernate事务

    hibernate事务 9.3 Hibernate的事务管理 事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整,或者在修改 ...

随机推荐

  1. Java词频统计

    public class WordCount { public static void main(String[] args) { String[] stopWords = { "" ...

  2. 解决MySQL Slave 触发 oom-killer

    最近经常有收到MySQL实例类似内存不足的报警信息,登陆到服务器上一看发现MySQL 吃掉了99%的内存,God ! 有时候没有及时处理,内核就会自己帮我们重启下MySQL,然后我们就可以看到 dme ...

  3. 【转载】JSP生成静态Html页面

    在网站项目中,为了访问速度加快,为了方便百度爬虫抓取网页的内容,需要把jsp的动态页面转为html静态页面.通常有2种常用的方式: 1.伪静态,使用URL Rewriter 2.纯静态,本文中代码实现 ...

  4. C++模式学习------策略模式

    当遇到同一个对象有不同的行为,方法,为管理这些方法可使用策略模式. 策略模式就是对算法进行包装,是把使用算法的责任和算法本身分割开来.通常把一个系列的算法包装到一系列的策略类里面,这些类继承一个抽象的 ...

  5. 【刷题】BZOJ 1901 Zju2112 Dynamic Rankings

    Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[j]中第k小的数是 ...

  6. java Class.getSimpleName() 的用法

    Usage in android: private static final String TAG = DemoApplication.class.getSimpleName(); public cl ...

  7. Android 通知之 Notification

    Notifications | Android Developershttp://developer.android.com/guide/topics/ui/notifiers/notificatio ...

  8. Android仿iPhone 滚轮控件 实现

    Android_开发 实用滚轮效果选择数字http://blog.csdn.net/zhangtengyuan23/article/details/8653771 Android仿iPhone滚轮控件 ...

  9. Python之旅:集合

    Python数据类型 #作用:去重,关系运算, #定义: 知识点回顾 可变类型是不可hash类型 不可变类型是可hash类型 #定义集合: 集合:可以包含多个元素,用逗号分割, 集合的元素遵循三个原则 ...

  10. 《剑指offer》— JavaScript(23)二叉搜索树的后序遍历序列

    二叉搜索树的后序遍历序列 题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 相关知识 二叉查找树(B ...