Hibernate5笔记8--Hibernate事务相关内容
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事务相关内容的更多相关文章
- MySQL学习笔记-事务相关话题
事务机制 事务(Transaction)是数据库区别于文件系统的重要特性之一.事务会把数据库从一种一致状态转换为另一个种一致状态.在数据库提交工作时,可以确保其要么所有修改都已经保存了,要么所有修改都 ...
- 学习笔记之html5相关内容
写一下昨天学习的html5的相关内容,首先谈下初次接触html5的感受.以前总是听说html5是如何的强大,如何的将要改变世界.总是充满了神秘感.首先来谈一下我接触的第一个属性是 input的里面的 ...
- Hibernate 事务和并发控制
首先关于Hibernate事务控制,下面是非常权威的资料, https://docs.jboss.org/hibernate/orm/4.0/devguide/en-US/html/ch02.html ...
- Spring的事务管理和数据库事务相关知识
1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱. ...
- Spring 源码学习笔记11——Spring事务
Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...
- linux用户权限相关内容查看
linux用户权限相关内容查看 1 用户信息 创建用户一个名为 webuser 的账号,并填写相应的信息: root@iZ94fabhqhuZ:~# adduser webuser Adding ...
- (转)Hibernate事务管理
Hibernate的事务管理 事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整,或者在修改时受到用户干扰.作为一名软件设计 ...
- hibernate学习笔记之一 hibernate简介
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架 hibernate可以自动生成SQL语句,自 ...
- hibernate事务
hibernate事务 9.3 Hibernate的事务管理 事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整,或者在修改 ...
随机推荐
- JVM内存管理机制
Java与C++之间有一堆由内存动态分配与垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来. —— <深入理解Java虚拟机:JVM高级特性与最佳实践> Java虚拟机在 ...
- app流畅度测试--使用SM
通过测量应用的帧率FPS并不能准确评价App的流畅度,FPS较低并不能代表当前App在UI上界面不流畅,而1s内VSync这个Loop运行了多少次更加能说明当前App的流畅程度. 那么我们可以直接在A ...
- UVA10054_The Necklace
很简单,求欧拉回路.并且输出. 只重点说一下要用栈来控制输出. 为啥,如图: 如果不用栈,那么1->2->3->1就回来了,接着又输出4->5,发现这根本连接不上去,所以如果用 ...
- 将javaweb项目部署到阿里云服务器
主要步骤:1. 购买阿里云服务器2. 远程连接3. 在云服务器上配javaweb环境:jdk,tomcat,MySQL4. 将项目的war文件放到Tomcat下关于云服务器ECS:如果还想在买服务器之 ...
- Day22-Django之信号
1. 如果往数据库中增加数据的时候,希望生成一个日志.在数据保存之前以及保存之后. Django中提供了“信号调度”,用于在框架执行操作时解耦.通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去 ...
- linux 批量更改文件名 rename 命令
rename 的典型应用: # rename $1 $2 $3# $1: 要被取代的關鍵字# $2: 新的關鍵字# $3: 檔名符合這個規則的才取代 # 把 IMG001.jpg, IMG002.jp ...
- 【刷题】BZOJ 2154 Crash的数字表格
Description 今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数a和b,LCM(a, b)表示能同时被a和b整除的最小正整数.例如 ...
- 【BZOJ4559】成绩比较(动态规划,拉格朗日插值)
[BZOJ4559]成绩比较(动态规划,拉格朗日插值) 题面 BZOJ 洛谷 题解 显然可以每门课顺次考虑, 设\(f[i][j]\)表示前\(i\)门课程\(zsy\)恰好碾压了\(j\)个\(yy ...
- Android中Selector的用法(改变ListView和Button的默认背景)
Android中的Selector的用法 http://blog.csdn.net/shakespeare001/article/details/7788400#comments Android中的S ...
- 解题:USACO14MAR Sabotage
题面 题外话:我的实数二分有什么问题=.= 仍然(我为什么要这么说)是二分答案,如何检查呢?将所有的数减去二分出来的$mid$后求和得到和$sum$,然后如果在减出来的数列中能找出一段大于$sum$的 ...