「原创」浅谈java事务及隔离级别(jpa事务隔离级别)
mhr18 2024-09-18 20:23 22 浏览 0 评论
目录
- 一:事务的定义及作用
- 二:事务的四个特性(ACID)
- 三:JDBC事务
- 四:隔离级别
- 五、总结
一:事务的定义及作用
事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务一般由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。那么,在平时的应用中,为什么要使用事务呢?这里笔者想通过一个简单的例子来说明事务的重要性。支付宝是生活中经常使用的转账手段,假如账户A要通过支付宝将自己账户上的100元转到B账户,那么对于A账户来说余额就要减去100元,然后在B账户里增加100元,此时算是转账成功。假如就在A账户减去100元时,不巧出现了网络故障,B账户里还未来得及增加100元,那么整个转账业务就会出现问题。所以,为了保证业务的完整性,就需要通过事务来控制,将A减少100元和B增加100元放入同一个事务中,则该事务要么执行成功,要么执行失败后全部撤销,以此来保证数据的安全。
二:事务的四个特性(ACID)
事务的四个特性包括原子性(atomicity),一致性(consistency),隔离性(isolation)和持久性(durability)。笔者将通过上文的例子来帮助读者理解事务的这四个特性。1.原子性:事务是数据库的逻辑工作单位,不可再分。当我们把“A减少100和B增加100”加入一个事务时,这个将会成为数据库工作的最小单位,对于A和B数据的修改,要么全部成功,要么全部失败,不会出现某一个成功另一个失败的情况。2.一致性:在事务处理执行前后,数据库是一致的(数据库数据完整性约束)。假设A原来有100元,B原来有0元,那么最初A账户和B账户一共有100元;当事务结束时,即转账成功后,最终A账户和B账户一共有100元,与最初的值保持不变,是数据达到一致。3.隔离性:每个事务都是独立的,一个事务的执行不能被其他事务所影响。例如A给B转账100元,C给A转账100元,那么“A减少100元,B增加100元”与“C减少100元,A增加100元”属于两个不同的事务,并且两个事务相对独立。4.持久性:事务处理的结果能够被永久保存在数据库中。
三:JDBC事务
在JDBC中处理事务,都是通过Connection完成的。同一事务中所有的操作,都在使用同一个Connection对象。JDBC事务默认是开启的,并且是默认提交。下面是事务在Java中的最基本操作: connection.setAutoCommit(boolean);//设置是否为自动提交事务,如果true(默认值为true)表示自动提交,如果设置为false,需要手动提交事务。 connection.commit();//提交事务。 connection.rollback();//回滚事务。下面通过示例代码展示一下:
package cn.itcast.jdbc; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Savepoint; import java.sql.Statement; /** * 事务测试 */ public class test { public static void main(String[] args) throws SQLException { testTransaction(); } static void testTransaction() throws SQLException { Connection conn = null; Statement st = null; ResultSet rs = null; Savepoint sp = null; try { conn = JdbcUtils.getConnection(); //将事务设置成手动提交 conn.setAutoCommit(false); st = conn.createStatement(); //id为1的人的Money减100 String sql = "update user set money=money-100 where id=1"; st.executeUpdate(sql); //设置回滚点(savepoint) sp = conn.setSavepoint(); //id为2的人的Money减100 sql = "update user set money=money-100 where id=2"; st.executeUpdate(sql); sql = "select money from user where id=2"; rs = st.executeQuery(sql); float money = 0.0f; if (rs.next()) { money = rs.getFloat("money"); } if (money > 300){ throw new RuntimeException("已经超过最大值!"); } //id为2的人的Money加100 sql = "update user set money=money+100 where id=2"; st.executeUpdate(sql); //提交事务 conn.commit(); } catch (RuntimeException e) { if (conn != null && sp != null) { //回滚事务,注意里面的参数sp即为我们上面设置的savePoint,如果回滚的话只能回滚到savePoint以下的部分 //上面的部分不会得到回滚 conn.rollback(sp); conn.commit(); } throw e; } catch (SQLException e) { if (conn != null) conn.rollback(); throw e; } finally { //释放资源 JdbcUtils.free(rs, st, conn); } } }
四:隔离级别
为了应对多线程并发读取数据时出现的问题,事务有了“隔离级别”特性,多线程并发读取数据一般会引发如下三个问题:
- 脏读(dirtyreads):指一个事务读取了另外一个事务未提交的数据。假设A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据。 2.不可重复读(non-repeatablereads):一个事务重新读取前面读取过的数据, 发现该数据已经被另一个已提交的事务修改过。假如事务A在执行读取操作,由整个事务A比较大,前后读取同一条数据需要经历很长的时间 。而在事务A第一次读取数据,比如此时读取了小明的年龄为20岁,事务B执行更改操作,将小明的年龄更改为30岁,此时事务A第二次读取到小明的年龄时,发现其年龄是30岁,和之前的数据不一样了,也就是数据不重复了,系统不可以读取到重复的数据,称为不可重复读。3.幻读(phantomread):是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。假设事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,称为成为幻读。会发现,幻读和不可重复读是十分相似的,以致于很多人很难分辨它们,你只需要知道,它们最大的区别是:不可重复读读取到的是更新(update)数据,而幻读读取到的是插入(insert)数据。为了处理上面的读数据问题,java事务提供了4种隔离级别。
- 可串行化(Serializable):可避免脏读、不可重复读、虚读情况的发生。
- 可重复读(Repeatableread):可避免脏读、不可重复读情况的发生。不可以避免虚读。3.读已提交(Readcommitted):可避免脏读情况发生。4.读未提交(Read uncommitted):最低级别,以上情况均无法保证。
1表示有,0表示无
隔离级别脏读不可重复读幻读读未提交(Read uncommitted)111读已提交(Readcommitted)011可重复读(Repeatableread)001可串行化(Serializable)000
隔离级别由高到低排列:可串行化>可重复读>读已提交>读未提交。通常情况下,数据库都有自己的默认隔离级别,我们使用spring框架可以指定隔离级别,但是如果指定了数据库不支持的隔离级别,数据库就会使用自己默认的。在Oracle数据库中,默认隔离级别是Read committed,而另一个常用数据库MySQL中,默认隔离级别是Repeatable read。下面,我们用mysql的例子说明各个隔离级别的情况:开启两个命令行客户端分别为A,B;不断改变A的隔离级别,在B端修改数据。实际步骤同序号。
1.读未提交(最低的隔离级别):
- 读已提交:
- 可重复读
值得一提的是,如果在客户端A中接着执行update num= num + 1 where id = 1,num没有变成1+1=2,而是步骤(2)中更新过后的num=10来算的,所以是10 + 1 = 11,数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。
4.串行化
mysql中事务隔离级别为serializable时会锁表,若一个事务来查询同一份数据就必须等待,直到前一个事务完成并解除锁定为止,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。
五、总结
事务控制是构建J2EE应用不可缺少的一部分,合理选择应用何种事务对整个应用系统来说至关重要。一般说来,在单个JDBC 连接连接的情况下可以选择JDBC事务,在跨多个连接或者数据库情况下,需要选择使用JTA事务,如果用到了EJB,则可以考虑使用EJB容器事务,有兴趣的朋友可以关注一下。对于隔离级别来说,读未提交、读已提交和可重复读这三种隔离级别隔离的是行数据,他们的不同只是对应读、写之间的锁定关系不同而已,读未提交,事务进行写操作时并没有锁定禁止读的动作;读已提交在进行事务在进行写操作时锁定了行数据,禁止在写期间读数据;而可重复读则是在读期间禁止数据的写;串行化即锁定整个表的读写。希望读者能够合理选择并使用它们。
相关推荐
- 甲骨文签署多项大型云协议,其一未来可贡献超300亿美元年收入
-
IT之家7月1日消息,根据甲骨文Oracle当地时间6月30日向美国证券交易委员会(SEC)递交的FORM8-K文件,该企业在始于2025年6月1日的202...
- 甲骨文获TEMU巨额合同,后者大部分基础设施将迁移至Oracle云
-
IT之家6月23日消息,Oracle甲骨文创始人、董事长兼首席技术官LarryEllison(拉里埃里森)在本月早些时候的2025财年第四财季和全财年财报电话会议上表示,Oracle...
- Spring Boot 自定义数据源设置,这些坑你踩过吗?
-
你在使用SpringBoot进行后端开发的过程中,是不是也遇到过这样的问题:项目上线后,数据库连接总是不稳定,偶尔还会出现数据读取缓慢的情况,严重影响了用户体验。经过排查,发现很大一部分原因竟然...
- 一个开箱即用的代码生成器(一个开箱即用的代码生成器是什么)
-
今天给大家推荐一个好用的代码生成器,名为renren-generator,该项目附带前端页面,可以很方便的选择我们所需要生成代码的表。首先我们通过git工具克隆下来代码(地址见文末),导入idea。...
- 低代码建模平台-数据挖掘平台(低代码平台的实现方式)
-
现在来看一下数据连接。·这里是管理数据连接的空间,点击这里可以新增一个数据连接。·输入连接名称,然后输入url,是通过gdbc的方式去连接的数据库,目前是支持mysql、oracle以及国产数据库达梦...
- navicat 17.2.7连接oracle数据库提示加载oracle库失败
-
系统:macOS15.5navicat版本:navicatpremiumlite17.2.7连接oracle测试报错:加载oracle库失败【解决办法】:放达里面找到程序,显示简介里面勾选“使...
- 开源“Windows”ReactOS更新:支持全屏应用
-
IT之家6月17日消息,ReactOS团队昨日(6月16日)在X平台发布系列推文,公布了该系统的最新进展,包括升级Explorer组件,支持全屏应用,从Wine项目引入了...
- SSL 推出采用全模拟内置混音技术的模拟调音台Oracle
-
英国调音台传奇品牌SolidStateLogic宣布推出Oracle——一款采用全模拟内置混音技术的调音台,在紧凑的AWS尺寸机箱内集成了大型调音台的功能。该调音台提供24输入和...
- 47道网络工程师常见面试题,看看有没有你不会的!
-
你们好,我的网工朋友。网络工程师面试的时候,都会被问到什么?这个问题其实很泛,一般来说,你肯定要先看明白岗位需求写的是什么。基本上都是围绕公司需要的业务去问的。但不可否认的是,那些最基础的概念,多少也...
- 汉得信息:发布EBS系统安装启用JWS的高效解决方案
-
e公司讯,从汉得信息获悉,近日,微软官方宣布InternetExplorer桌面应用程序将于2022年6月15日正式停用。目前大部分客户都是使用IE浏览器打开EBS的Form界面,IE停用后,只能使...
- 36.9K star ! 推荐一个酷炫低代码开发平台!功能太强!
-
前言最近在逛github,看看能不能搜罗到一些对自己有帮助的开源软件。不经意间看到一个高star的java开源项目:jeecg-boot。进入在线演示版一看,感叹实在是太牛了!此开源项目不管是给来学习...
- Linux新手入门系列:Linux下jdk安装配置
-
本系列文章是把作者刚接触和学习Linux时候的实操记录分享出来,内容主要包括Linux入门的一些理论概念知识、Web程序、mysql数据库的简单安装部署,希望能够帮到一些初学者,少走一些弯路。注意:L...
- 手把手教你在嵌入式设备中使用SQLite3
-
摘要:数据库是用来存储和管理数据的专用软件,使得管理数据更加安全,方便和高效。数据库对数据的管理的基本单位是表(table),在嵌入式linux中有时候它也需要用到数据库,听起来好难,其实就是几个函数...
- JAVA语言基础(java语言基础知识)
-
一、计算机的基本概念什么是计算机?计算机(Computer)全称:电子计算机,俗称电脑。是一种能够按照程序运行、自动高速处理海量数据的现代化智能电子设备。由硬件和软件组成、没有安装过任何软件的计算机称...
- 再见 Navicat!一款开源的 Web 数据库管理工具!
-
大家好,我是Java陈序员。在日常的开发工作中,常常需要与各种数据库打交道。而为了提高工作效率,常常会使用一些可视化工具进行操作数据库。今天,给大家介绍一款开源的数据库管理工具,无需下载安装软件,基...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- 甲骨文签署多项大型云协议,其一未来可贡献超300亿美元年收入
- 甲骨文获TEMU巨额合同,后者大部分基础设施将迁移至Oracle云
- Spring Boot 自定义数据源设置,这些坑你踩过吗?
- 一个开箱即用的代码生成器(一个开箱即用的代码生成器是什么)
- 低代码建模平台-数据挖掘平台(低代码平台的实现方式)
- navicat 17.2.7连接oracle数据库提示加载oracle库失败
- 开源“Windows”ReactOS更新:支持全屏应用
- SSL 推出采用全模拟内置混音技术的模拟调音台Oracle
- 47道网络工程师常见面试题,看看有没有你不会的!
- 汉得信息:发布EBS系统安装启用JWS的高效解决方案
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle 空为0 (51)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)