开发必会系列: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 ...
随机推荐
- 五一不休息,每天都学习,从零教你手写节流throttle
壹 ❀ 引 我在 从零教你手写实现一个防抖debounce方法 一文中详细的介绍了防抖概念,以及如何手写一个防抖.既然聊到防抖那自然避不开同等重要的节流throttle,老规矩,我们先阐述节流的概念, ...
- IntersectionObserver对象
IntersectionObserver对象 IntersectionObserver对象,从属于Intersection Observer API,提供了一种异步观察目标元素与其祖先元素或顶级文档视 ...
- Redhat7更改网易yum源
说明 之前写了一篇关于Redhat6更换Yum源的文章,时隔已久很多包都变了,正好最近搭建环境需要用到Redhat7.3所以就再记录一下如何更换为国内最新最常用的yum源. 操作步骤 1.卸载系统自带 ...
- eslint+prettier 统一代码风格
1.实现效果 Eslint校验代码语法,prettier统一格式化代码,按下保存自动修复eslint错误,自动格式化代码. 2.安装vscode插件 Vetur ESLint Prettier - C ...
- Java集合框架学习(十四) Iterator接口详解
Iterator接口介绍 public interface Iterator<E> iterator 用于迭代集合类型对象,例如: HashMap, ArrayList, LinkedLi ...
- 在Windows10中安装解压版MySQL 8.X
在Windows 10中安装解压版的MySQL 8.X实现步骤: 1.下载MySQL安装包:https://dev.mysql.com/downloads/mysql/ 解压到指定目录,比如:D:\o ...
- Mybatis模糊查询无法确定参数$1的数据类型: ERROR: could not determine data type of parameter $1
Mybatis模糊查询无法确定参数$1的数据类型: 报错ERROR: could not determine data type of parameter $1 修改前: SELECT count(0 ...
- SpringBoot使用令牌桶算法+拦截器+自定义注解+自定义异常实现简单的限流
令牌桶 在高并发的情况下,限流是后端常用的手段之一,可以对系统限流.接口限流.用户限流等,本文就使用令牌桶算法+拦截器+自定义注解+自定义异常实现限流的demo. 令牌桶思想 大小固定的令牌桶可自行以 ...
- 硬件开发笔记(十四):RK3568底板电路LVDS模块、MIPI模块电路分析、LVDS硬件接口、MIPI硬件接口详解
前言 本篇继续分析底板原理图mipi/lvds屏幕电路原理图.硬件接口详解. LVDS与MIPI的区别 液晶屏有RGB TTL.LVDS.MIPI.HDMI接口,这些接口区别于信号的类型( ...
- 【MongoDB】MongoDB原理分析、集群搭建(Docker)与简单使用
一.MongoDB 简介 MongoDB是一个基于分布式文件存储的数据库,介于关系数据库和非关系数据库之间,是非关系数据库当中功能最丰富,最像关系数据库的.其目的是为WEB应用提供可扩展的高性能数据存 ...