开发必会系列:hibernate事务
一 事务定义及特性
1、数据库事务的定义:数据库事务(Database Transaction) 是指由一个或多个SQL语句组成的工作单元,这个工作单元中的SQL语句相互依赖,如果有一个SQL语句执行失败,就必须撤销整个工作单元。
以银行转账为例:

2、数据库事务必须具备ACID特征
A: Atomic 原子性:整个事务不可分割,要么都成功,要么都撤销。
C: Consistency 一致性:事务不能破坏关系数据的完整性和业务逻辑的一致性,例如转账,应保证事务结束后两个账户的存款总额不变。
I: Isolation 隔离性:多个事务同时操纵相同数据时,每个事务都有各自的完整数据空间
D: Durability 持久性:只要事务成功结束,对数据库的更新就必须永久保存下来,即使系统发生崩溃,重启数据库后,数据库还能恢复到事务成功结束时的状态。
3、数据库事务的生命周期

4、声明事务的边界
事务的开始边界(BEGIN)
事务的正常结束边界(COMMIT): 提交事务,永久的保存被事务更新后的数据库状态。
事务的异常结束边界(ROLLBACK): 撤销事务,使数据库退回到执行事务前的初始状态。
5、通过JDBC API来声明事务边界
Connection类提供了用于控制事务的方法:
setAutoCommit(boolean autoCommit):设置是否自动提交事务
commit(): 提交事务
rollback(): 撤销事务
try {
con = java.sql.DriverManager.getConnection(dbUrl,dbUser,dbPwd);
//设置手工提交事务模式
con.setAutoCommit(false);
stmt = con.createStatement();
//数据库更新操作1
stmt.executeUpdate("update ACCOUNTS set BALANCE=900 where ID=1 ");
//数据库更新操作2
stmt.executeUpdate("update ACCOUNTS set BALANCE=1000 where ID=2 ");
con.commit(); //提交事务
}catch(Exception e) {
try{
con.rollback(); //操作不成功则撤销事务
}catch(Exception ex){
//处理异常
……
}
//处理异常
……
}finally{…}
二 声明事务的开始边界
Transaction tx = session.beginTransaction();
提交事务
tx.commit();
撤销事务
tx.rollback();
三 多个事务并发运行的问题
1、单个事务能保证单项业务的数据完整性,但是当多个事务同步运行时可能带来并发问题,具体体现在:
第一类丢失更新:在撤销一个事务时,把其它事务提交的更新数据覆盖。

脏读:一个事务读到另一事务未提交的更新数据。

虚读:一个事务读到另一事务已提交的新插入的数据。

不可重复读:一个事务读到另一事务已提交的更新数据。

第二类丢失更新:这是不可重复读中的特例,一个事务覆盖另一事务已提交的更新数据。

四 数据库系统锁的基本原理
1、当一个事务访问某种数据库资源时,如果执行select语句,必须先获得共享锁,如果执行insert、update或delete语句,必须获得独占锁。
2、当第二个事务也要访问相同资源时,如果执行select语句,也必须获得共享锁,如果执行insert、update或delete语句,也必须获得独占锁。此时根据已经放置在资源上的锁的类型,来决定第二个事务应该等待第一个事务解除对资源的锁定,还是可以立刻获得锁。
五 锁的分类:
1)从应用程序的角度分为:
(1)悲观锁
(2)乐观锁
2)数据库系统按照封锁程度可分为:
(1)共享锁:用于读数据操作,它非独占的,允许其他事务同时读取其锁定的资源,但不允许其他事务更新它。
(2)独占锁:也叫排他锁,适用于修改数据的场合。他所锁定的资源,其他事物不能读取也不能修改。
(3)更新锁:在更新操作的初始阶段用来锁定可能要修改的资源,这可以避免使用共享锁造成的死锁现象。
六 数据库的事务隔离级别
1、隔离级别的种类
为了解决数据库事务并发运行时的各种问题数据库系统提供四种事务隔离级别:
Read Uncommitted(读未提交数据):
它可以防止第一类丢失更新问题,但没有解决脏读以上的并发问题。它的事务隔离性最低。
Read Committed(读已提交数据):
它可以防止脏读以下的并发问题,但没有解决不可重复读以上的并发问题。
Repeatable Read(可重复读):
它可以防止不可重复读(包括第二类丢失更新)以下的并发问题,但没有解决幻读问题。
Serializable(串行化):
提供最严格的事务隔离性。它把事务隔离成连续的一个接一个地执行,而不是并发执行。在这种隔离级别下,不会出现任何的并发问题。
2、隔离级别所能避免能并发的问题

3、设置隔离级别的原则
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
对于多数据应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读,而且具有较好的并发性能。尽管它会导致不可重复读,虚读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序悲观锁和乐观锁来解决。
4、在hibernate中设置隔离级别
JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate的配置文件中可以显示地设置隔离级别。每一种隔离级别对应着一个正整数。
1:Read Uncommitte
2:Read Committed
4:Repeatable Read
8:Serializable
七 在应用程序中采用悲观锁和乐观锁
1、应用程序中解决不可重复读问题
采用悲观锁和乐观锁的作用:当数据库系统采用Red Committed隔离级别时,会导致不可重复读和第二类丢失更新的并发问题。在可能出现这种问题的场合,可以在应用程序中采用乐观锁或悲观锁来避免这类问题。
2、悲观锁和乐观锁的概念
悲观锁:在数据有加载的时候就给其进行加锁,直到该锁被释放掉,其他用户才可以进行修改,优点:数据的一致性保持得很好,缺点:不适合多个用户并发访问。当一个锁住的资源不被释放掉的时候,这个资源永远不会被其他用户进行修改,容易造成无限期的等待。
乐观锁:就是在对数据进行修改的时候,对数据才去版本或者时间戳等方式来比较,数据是否一致性来实现加锁。
3、利用悲观锁协调并发运行的事务

4、使用乐观锁
乐观锁是由应用程序提供的一种机制,这种机制既能保证多个事务并发访问数据,又能防止第二类丢失更新问题。
在应用程序中,可以利用Hibernate提供的版本控制功能来实现乐观锁。对象-关系映射文件中的<version>元素和<timestamp>元素都具有版本控制功能:
<version>元素利用一个递增的整数来跟踪数据库表中记录的版本
<timestamp>元素用时间戳来跟踪数据库表中记录的版本
<version>进行版本控制: 当Hibernate更新一个Account对象时,会根据它的id与version属性到ACCOUNTS表中去定位匹配的记录,假定Account对象的version属性为0,那么在取款事务中Hibernate执行的update语句为:
update ACCOUNTS set NAME=’Tom’,BALANCE=900,VERSION=1
where ID=1 and VERSION=0; 如果存在匹配的记录,就更新这条记录,并且把VERSION字段的值加1。当支票转账事务接着执行以下update语句时:
update ACCOUNTS set NAME=’Tom’,BALANCE=1100,VERSION=1
where ID=1 and VERSION=0; 由于ID为1的ACCOUNTS记录的版本已经被取款事务修改,因此找不到匹配的记录,此时Hibernate会抛出StaleObjectStateException
乐观锁并发取款事务和支票转账:

2023补充:
事务级别:
4个级别,读未提交<读已提交<可重复读<串行
有两个update,更新同一条数据
1、一个update刚修改完,还没提交,另一个update就开始读了,读到了未提交的数据,以为这个是正确数据,直接按这个update,导致数据乱了
2、加了个小锁,每个update都会执行2次查询,最后才修改,然后提交。一个update查了2次,另一个update查了一次,他们查到的值都一样,然后查了2次的开始修改,另一个update查第二次,此时卡住(有锁了),一直等第一个update修改完成并提交成功,才查出新值,它查到了2个值,迷茫了,可以抛异常。
如果另一个update不是查2次,只查了一次,那就会覆盖第一个update提交的结果,也不安全
面对这两个可能出现的问题,需要应用程序(自己写代码)增加悲观锁、乐观锁解决
悲观锁,模仿串行,两个事务可以一起开始,开始事务直接锁数据,别的事务直接卡住等锁释放
乐观锁,模仿可重复读,两个事务可以一起开始,某个事务修改时,比较时间戳或版本号,默认能执行成功,如果别的事务修改并提交过,时间戳或版本号就会不一致,事务直接报错 (mvcc就是乐观锁的一种实现,mysql在2,3这俩级别,都是默认使用mvcc的
具体解释:
MVCC,Multi-Version Concurrency Control,多版本并发控制
需要注意的是:MVCC只在读已提交和可重复读这两个隔离级别下有效,因为串行化这个隔离级别,是通过加排他锁让事务串行执行,串行执行不会有并行执行带来的并发问题,也就不需要用MVCC进行并发控制。而读未提交这个隔离级别,是让事务读取最新的数据,不需要用版本号进行数据版本范围的限制,所以也用不到MVCC。
MVCC的好处是什么呢?MVCC实现事务的可重复读和读已提交这两个隔离级别,用的是版本号比对机制而非加锁的手段,避免了加锁所带来的性能问题,实现了读操作的高性能。但是MVCC也有缺点:一是需要为每条数据多保存两个字段,会占用一定的存储空间;二是数据版本的比较操作也会造成一定的开销。
)
3、加个大点的锁,每个update都会执行2次查询,最后才修改,然后提交。一个update查了2次,另一个update第一次查时直接卡住,等人家提交完事了,这边才能第一次查。安全多了。
但还有个小问题,另一个update第一次出个值,突然来了个insert,还提交成功了,然后update查第二次时,总数的值变了(如果update只更新一条数据,且这条数据和总数无关,那就没关系,否则就有错),迷茫了,可以抛异常。
4、加最大的锁,只要有DML语句,直接全锁,其他DML不能查。
大部分数据库默认级别2,mysql默认级别3
一条sql就是一条事务,默认执行一条会自动提交,批量更新应该关自动提交,用批量执行。
数据库自带的行锁和表锁什么时候用?
Mysql的行锁是通过通过给索引上的索引项加锁来实现的,即是行锁是加在索引相应的行上的,要是对应的SQL语句没有走索引,则会全表扫描,行锁则无法实现,取而代之的是表锁。
InnoDB这种行锁实现的特点意味着:只有通过索引条件检索数据,并且执行时真正使用到了索引,InnoDB才使用行级锁,否则,InnoDB 将使用表锁。
不论是使用主键索引、唯一索引还是普通索引,当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行。
执行update语句耗时很久,我在等待过程中执行select count时需要等update锁么?
count(1)会自己找个辅助索引列去查,如果update在改索引列,那就会触发行锁,count就要等update执行完释放锁。
八 缓存
缓存是计算机领域的概念,它介于应用程序和永久性数据存储源之间
Hibernate的缓存一般分为3类:
一级缓存
二级缓存
查询缓存
1、Session内的缓存即一级缓存;
2、二级缓存是进程或集群范围内的缓存,可以被所有的Session共享;
二级缓存是可配置的插件;
选择合适的缓存插件,配置其自带的配置文件。
选择需要使用二级缓存的持久化类,设置它的二级缓存的并发访问策略。
3、查询是数据库技术中最常用的操作,Hibernate为查询提供了缓存,用来提高查询速度,优化查询性能
查询缓存依赖于二级缓存
开发必会系列:hibernate事务的更多相关文章
- ASP.NET MVC开发必看系列
一.关于HTTP协议的那些事 这可以说我们开发WEB程序的空气,推荐不断温故知新! HTTP协议 (一) HTTP协议详解 HTTP协议 (二) 基本认证 HTTP协议 (三) 压缩 HTTP协议 ( ...
- SSM框架开发web项目系列(二) MyBatis真正的力量
前言 上篇SSM框架环境搭建篇,演示了我们进行web开发必不可少的一些配置和准备工作,如果这方面还有疑问的地方,可以先参考上一篇“SSM框架开发web项目系列(一) 环境搭建篇”.本文主要介绍MyBa ...
- SSM框架开发web项目系列(五) Spring集成MyBatis
前言 在前面的MyBatis部分内容中,我们已经可以独立的基于MyBatis构建一个数据库访问层应用,但是在实际的项目开发中,我们的程序不会这么简单,层次也更加复杂,除了这里说到的持久层,还有业务逻辑 ...
- Visual Studio (VS IDE) 你必须知道的功能和技巧 - 【.Net必知系列】
前言 本文主要阐述一些Visual Studio开发下需要知道的少部分且比较实用的功能,也是很多人忽略的部分.一些不常用而且冷门的功能不在本文范围,当然本文的尾巴[.Net必知系列]纯属意淫,如有雷同 ...
- (转)Hibernate事务管理
Hibernate的事务管理 事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整,或者在修改时受到用户干扰.作为一名软件设计 ...
- hibernate事务
hibernate事务 9.3 Hibernate的事务管理 事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整,或者在修改 ...
- hibernate 事务理解
简介: Hibernate本身并不具备事务管理能力 .在事务管理层, Hibernate将其委托给底层的JDBC或者JTA ,以实现事务管理和调度功能. Hibernate的默认事务处理机制基于JDB ...
- mysql 开发进阶篇系列 46 物理备份与恢复( xtrabackup的 选项说明,增加备份用户,完全备份案例)
一. xtrabackup 选项说明 在操作xtrabackup备份与恢复之前,先看下该工具的选项,下面记录了xtrabackup二进制文件的部分命令行选项,后期把常用的选项在补上.点击查看xtrab ...
- mysql 开发进阶篇系列 10 锁问题 (相同索引键值或同一行或间隙锁的冲突)
1.使用相同索引键值的冲突 由于mysql 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但如果是使用相同的索引键,是会出现锁冲突的.设计时要注意 例如:city表city_ ...
- Linux驱动开发必看详解神秘内核(完全转载)
Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html IT168 技术文档]在开始步入L ...
随机推荐
- Power BI 6 DAY
Power BI 数据建模与数据汇总分析 层级关系 跨表取字段时类型二可用 父子级关系条件 一个父级下对应多个子级值 一个子级值只属于一个父级 跨表取字段的条件:维度连接用关键字段间是父子级关系时,可 ...
- NC22544 车站
题目链接 题目 题目描述 一个国家有n个城市,有n-1条道路连接,保证联通.还有m条铁路,从1~m编号,第i条铁路是从ui到vi的简单路径,多次询问一段区间的铁路的车站. 一个点可以作为区间[L,R] ...
- NC20164 [JSOI2008]最大数MAXNUMBER
题目链接 题目 题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作.语法:Q L 功能:查询当前数列中末尾L 个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度. ...
- NC20568 [SCOI2012]滑雪与时间胶囊
题目链接 题目 题目描述 a180285非常喜欢滑雪.他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1 ≤ i ≤ N)和一高度Hi.a18 ...
- Linux中$home和波浪号~
在Linux中当前用户的主目录可以有三种表示方法,都是等效的[正常不改配置情况下]例如用户名为sy,进入当前用户的主目录/home/sy 输入cd ~ 或输入cd $HOME 或输入cd /home/ ...
- es6 快速入门 系列 —— 解构
其他章节请看: es6 快速入门 系列 解构 我们经常使用数组或对象存储数据,然后从中提取出相关数据信息 试图解决的问题 以前开发者为了从对象或数组中提取出特定数据并赋值给变量,编写了很多重复的代码, ...
- 【Unity3D】点选物体、框选物体、绘制外边框
1 需求描述 绘制物体外框线条盒子 中介绍了绘制物体外框长方体的方法,本文将介绍物体投影到屏幕上的二维外框绘制方法. 点选物体:点击物体,可以选中物体,按住 Ctrl 追加选中,选中的物体设置为红 ...
- 使用virtualenv新建django项目
# 安装virtualenv pip install virtualenv # 创建虚拟环境 virtualenv venv # 进入虚拟环境 venv\Scripts\activate # 安装dj ...
- Linux后台进程启停脚本模板
目录 启动脚本 停止脚本 在Linux上启动程序后台运行时,往往需要输入一堆复杂的命令,为了能快速编写一个完善的启动脚本,整理一个通用的启停脚本模板如下. 脚本支持从任意位置执行,不存在路径问题,启动 ...
- del,str,repr,call,bool,add,len等魔术方法以及与类相关的魔术属性---day23
1.__del__ # ### __del__魔术方法(析构方法) ''' 触发时机:当对象被内存回收的时候自动触发(1.页面执行完毕回收所有变量2.所有对象被del的时候) 功能:对象使用完毕后资源 ...