百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

「原创」浅谈java事务及隔离级别(jpa事务隔离级别)

mhr18 2024-09-18 20:23 14 浏览 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);
 }
 }
}

四:隔离级别

为了应对多线程并发读取数据时出现的问题,事务有了“隔离级别”特性,多线程并发读取数据一般会引发如下三个问题:

  1. 脏读(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种隔离级别。
  2. 可串行化(Serializable):可避免脏读、不可重复读、虚读情况的发生。
  3. 可重复读(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.读未提交(最低的隔离级别):

  1. 读已提交:



  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容器事务,有兴趣的朋友可以关注一下。对于隔离级别来说,读未提交、读已提交和可重复读这三种隔离级别隔离的是行数据,他们的不同只是对应读、写之间的锁定关系不同而已,读未提交,事务进行写操作时并没有锁定禁止读的动作;读已提交在进行事务在进行写操作时锁定了行数据,禁止在写期间读数据;而可重复读则是在读期间禁止数据的写;串行化即锁定整个表的读写。希望读者能够合理选择并使用它们。

相关推荐

Redis合集-使用benchmark性能测试

采用开源Redis的redis-benchmark工具进行压测,它是Redis官方的性能测试工具,可以有效地测试Redis服务的性能。本次测试使用Redis官方最新的代码进行编译,详情请参见Redis...

Java简历总被已读不回?面试挂到怀疑人生?这几点你可能真没做好

最近看了几十份简历,发现大部分人不是技术差,而是不会“卖自己”——一、简历死穴:你写的不是经验,是岗位说明书!反面教材:ד使用SpringBoot开发项目”ד负责用户模块功能实现”救命写法:...

redission YYDS(redission官网)

每天分享一个架构知识Redission是一个基于Redis的分布式Java锁框架,它提供了各种锁实现,包括可重入锁、公平锁、读写锁等。使用Redission可以方便地实现分布式锁。red...

从数据库行锁到分布式事务:电商库存防超卖的九重劫难与破局之道

2023年6月18日我们维护的电商平台在零点刚过3秒就遭遇了严重事故。监控大屏显示某爆款手机SKU_IPHONE13_PRO_MAX在库存仅剩500台时,订单系统却产生了1200笔有效订单。事故复盘发...

SpringBoot系列——实战11:接口幂等性的形而上思...

欢迎关注、点赞、收藏。幂等性不仅是一种技术需求,更是数字文明对确定性追求的体现。在充满不确定性的网络世界中,它为我们建立起可依赖的存在秩序,这或许正是技术哲学最深刻的价值所在。幂等性的本质困境在支付系...

如何优化系统架构设计缓解流量压力提升并发性能?Java实战分享

如何优化系统架构设计缓解流量压力提升并发性能?Java实战分享在高流量场景下。首先,我需要回忆一下常见的优化策略,比如负载均衡、缓存、数据库优化、微服务拆分这些。不过,可能还需要考虑用户的具体情况,比...

Java面试题: 项目开发中的有哪些成长?该如何回答

在Java面试中,当被问到“项目中的成长点”时,面试官不仅想了解你的技术能力,更希望看到你的问题解决能力、学习迭代意识以及对项目的深度思考。以下是回答的策略和示例,帮助你清晰、有说服力地展示成长点:一...

互联网大厂后端必看!Spring Boot 如何实现高并发抢券逻辑?

你有没有遇到过这样的情况?在电商大促时,系统上线了抢券活动,结果活动刚一开始,服务器就不堪重负,出现超卖、系统崩溃等问题。又或者用户疯狂点击抢券按钮,最后却被告知无券可抢,体验极差。作为互联网大厂的后...

每日一题 |10W QPS高并发限流方案设计(含真实代码)

面试场景还原面试官:“如果系统要承载10WQPS的高并发流量,你会如何设计限流方案?”你:“(稳住,我要从限流算法到分布式架构全盘分析)…”一、为什么需要限流?核心矛盾:系统资源(CPU/内存/数据...

Java面试题:服务雪崩如何解决?90%人栽了

服务雪崩是指微服务架构中,由于某个服务出现故障,导致故障在服务之间不断传递和扩散,最终造成整个系统崩溃的现象。以下是一些解决服务雪崩问题的常见方法:限流限制请求速率:通过限流算法(如令牌桶算法、漏桶算...

面试题官:高并发经验有吗,并发量多少,如何回复?

一、有实际高并发经验(建议结构)直接量化"在XX项目中,系统日活用户约XX万,核心接口峰值QPS达到XX,TPS处理能力为XX/秒。通过压力测试验证过XX并发线程下的稳定性。"技术方案...

瞬时流量高并发“保命指南”:这样做系统稳如泰山,老板跪求加薪

“系统崩了,用户骂了,年终奖飞了!”——这是多少程序员在瞬时大流量下的真实噩梦?双11秒杀、春运抢票、直播带货……每秒百万请求的冲击,你的代码扛得住吗?2025年了,为什么你的系统一遇高并发就“躺平”...

其实很多Java工程师不是能力不够,是没找到展示自己的正确姿势。

其实很多Java工程师不是能力不够,是没找到展示自己的正确姿势。比如上周有个小伙伴找我,五年经验但简历全是'参与系统设计''优化接口性能'这种空话。我就问他:你做的秒杀...

PHP技能评测(php等级考试)

公司出了一些自我评测的PHP题目,现将题目和答案记录于此,以方便记忆。1.魔术函数有哪些,分别在什么时候调用?__construct(),类的构造函数__destruct(),类的析构函数__cal...

你的简历在HR眼里是青铜还是王者?

你的简历在HR眼里是青铜还是王者?兄弟,简历投了100份没反应?面试总在第三轮被刷?别急着怀疑人生,你可能只是踩了这些"隐形求职雷"。帮3630+程序员改简历+面试指导和处理空窗期时间...

取消回复欢迎 发表评论: