事务的理解

事务的概念

事务是一组SQL组成的逻辑处理单元,通常有四个特性,简称ACID:

原子性(Atomic):数据库事务是不可分割的工作单位。事务中的SQL语句要么都执行成功,要么都执行失败。

一致性(Consistency):数据库事务不能破坏数据库的完整性和业务逻辑的一致性。例如银行转账业务,A给B转账,不管转账失败还是成功,A和B的总存款不能变。

隔离性(Isolation):在并发的环境中,当不同的事务操作相同的数据时,每个事务都有各自完整的数据空间。

持久性(Durability):只要事务提交成功,对数据库做的更改必须永久的保存下来。即使数据库奔溃或者数据库重启,也能恢复到事务提交后的状态。

事务的隔离性

1、我们先看看如果不考虑事务的隔离性,会发生的几种问题:

(1)脏读

  脏读是指在一个事务读取了另一个未提交的数据。

  当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户A向用户B转账100元,对应SQL命令如下

update account set money=money+100 where name=’B’;  (此时A通知B)update account set money=money - 100 where name=’A’;

  当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。

(2)不可重复读

  不可重复读是指在对于数据库中的某一行数据,一个事务范围内多次查询却返回了不同的数据值。原因是另外一个事务做了更新操作。

  例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发生了不可重复读。

  不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。

  在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……

(3)虚读(幻读)

  幻读是指一个事务内的多次查询返回的结果集不一致。原因是另外一个事务做了插入或者删除操作。

       例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

  幻读和不可重复读都是读取了另一个事务已提交的数据(这点和脏读不同),所不同的是不可重复读查询的都是同一行数据,是另外一个事务update操作导致出现的问题。而幻读针对的是一批数据整体(比如数据的个数),是另外一个事务insert或delete操作导致出现的问题。

2、现在来看看MySQL数据库为我们提供的四种隔离级别:

  ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。

  ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。

  ③ Read committed (提交读):可避免脏读的发生。

  ④ Read uncommitted (未提交读):最低级别,任何情况都无法保证。

  以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。

  注:在mysql5.6以上版本引入了MVCC,在Repeatable read隔离级别下已经不存在幻读问题了。

  在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (提交读)这两种级别,其中默认的为Read committed级别。

验证Oracle数据库的隔离级别

1、证明一个事务不会读取到另一个事务未提交的数据,即证明oracle数据库不会发生脏读

package org.cc;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;public class JDBCDemo {public static void main(String[] args) throws InterruptedException {Thread updateThread = new Thread(new UpdateAndAdd());//修改和插入数据后,1分钟后再提交数据Thread readData = new Thread(new ReadData());//读取数据,看看能否读取到上面事务未提交的数据updateThread.start();Thread.sleep(2000);//停顿2秒,保证前一个事务已经操作了数据库readData.start();}private static  Connection getConn() throws ClassNotFoundException, SQLException{Class.forName("oracle.jdbc.driver.OracleDriver");return DriverManager.getConnection("jdbc:oracle:thin:@//127.0.0.1:1521/orcl", "scott", "tigger");}static class UpdateAndAdd implements Runnable {@Overridepublic void run() {Connection conn = null;Statement state = null;try {conn = getConn();conn.setAutoCommit(false);state = conn.createStatement();System.out.println("即将操作数据库!");state.executeUpdate("update emp set comm=1000 where ENAME='SMITH'");state.executeUpdate("insert into emp values('6666','lipiao','CLERK','7902',to_date('20200725','yyyymmdd'),800,1000,'20')");Thread.sleep(10000);//一分钟后再提交事务,另外一个线程看能够读取到这些数据conn.commit();} catch (SQLException | ClassNotFoundException | InterruptedException e) {e.printStackTrace();} finally {try {if (state != null) {state.close();}if (conn != null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}}}static class ReadData implements Runnable{@Overridepublic void run() {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = getConn();ps = conn.prepareStatement("select * from emp where ename in(?,?)");ps.setString(1, "SMITH");ps.setString(2, "lipiao");System.out.println("读取数据");rs = ps.executeQuery();while(rs.next()){System.out.println("读取到了一行数据:comm:"+rs.getDouble("comm"));}} catch (SQLException | ClassNotFoundException e) {e.printStackTrace();} finally {try {if(rs!=null){rs.close();}if (ps != null) {ps.close();}if (conn != null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}}}
}

2 证明会发生不可重复度和幻读,意思说当前事务两次读取同一行记录数据不一致(不可重复度,其他事务做了修改,并且提交了事务),当前事务第一次和第二次读取的记录数不一致(幻读,其他事务有新增记录,并且提交了事务)

package org.cc;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;public class JDBCDemo2 {public static void main(String[] args) throws InterruptedException {Thread updateThread = new Thread(new UpdateAndAdd());//修改和插入数据Thread readData = new Thread(new ReadData());//两次读取数据readData.start();Thread.sleep(3000);updateThread.start();}private static  Connection getConn() throws ClassNotFoundException, SQLException{Class.forName("oracle.jdbc.driver.OracleDriver");return DriverManager.getConnection("jdbc:oracle:thin:@//127.0.0.1:1521/orcl", "scott", "tigger");}static class UpdateAndAdd implements Runnable {@Overridepublic void run() {Connection conn = null;Statement state = null;try {conn = getConn();state = conn.createStatement();System.out.println("即将操作数据库!");state.executeUpdate("update emp set comm=2000 where ENAME='SMITH'");state.executeUpdate("insert into emp values('6667','cc','CLERK','7902',to_date('20200725','yyyymmdd'),800,1000,'20')");} catch (SQLException | ClassNotFoundException e) {e.printStackTrace();} finally {try {if (state != null) {state.close();}if (conn != null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}}}static class ReadData implements Runnable{@Overridepublic void run() {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = getConn();ps = conn.prepareStatement("select * from emp where ename in(?,?)");ps.setString(1, "SMITH");ps.setString(2, "cc");System.out.println("第一次读取数据");rs = ps.executeQuery();//先查询while(rs.next()){System.out.println("读取到了一行数据:ename:"+rs.getString("ename")+",comm:"+rs.getDouble("comm"));}Thread.sleep(10000);//等另外一个事务提交System.out.println("另外一个事务提交后读取数据");rs.close();rs = ps.executeQuery();//先查询while(rs.next()){System.out.println("读取到了一行数据:ename:"+rs.getString("ename")+",comm:"+rs.getDouble("comm"));}} catch (SQLException | ClassNotFoundException | InterruptedException e) {e.printStackTrace();} finally {try {if(rs!=null){rs.close();}if (ps != null) {ps.close();}if (conn != null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}}}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/530388.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode设置templates_在VScode中创建你的代码模板的方法

使用VScode的用户代码片段功能,来生成自己习惯的代码模板,提升开发效率1.选择菜单里的 文件 > 首选项 > 用户代码片段2.选择你需要自定义模板的文件,以vue为例3. 配置对应文件json把代码片段写在json里。每个代码段都是在一个代码片段名…

【Java中级篇】动态代理机制

要想搞明白动态代理之前,我们先来了解一下代理是什么意思,先来谈谈设计模式中的代理模式。 什么是代理模式(Proxy) 定义:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用。 在代理模式中&…

二维分类教案_幼儿园中班数学教案中班数学教案二维排序——师乐汇幼儿教师教育网...

中班数学教案:二维排序一、活动目标:1. 在分类的基础上初步运用二维排列表进行物品放置。2. 通过场景设置、温故知新由易到难的课程安排,幼儿能积极参与大胆表达并且根据表格来进行物品放置。3.在生活化的情境中体验学习数学活动的…

【JAVA基础篇】String类详解

昨天参加了一场机试&#xff0c;发现自己居然对String类的api不熟了&#xff0c;所以今天来总结一下&#xff08;基于JDK1.8&#xff09;。 1、父类和实现的接口 没有父类&#xff0c;或者说父类是Object 接口&#xff1a;Serializable、Comparable<String>、CharSequ…

python精确计时_PYTHON在WINDOWS下高精度计时的体会

2011-02-23 14:51:19其实也是WINDOWS下的通用办法啦&#xff0c;只不过我用PYTHON表达。用win32api.GetSystemTime()不是太精确&#xff0c;值15毫秒才变一下&#xff0c;最好用time.clock()&#xff0c;这个能到毫秒级&#xff0c;最精确的办法是用QueryPerformanceFrequency(…

什么叫大数据人物画像_大数据时代,如何构建精准用户画像,直击精细化运营...

移动互联网时代&#xff0c;精细化运营逐渐成为企业发展的重要竞争力&#xff0c;“用户画像”的概念也应运而生。用户画像是指&#xff0c;在大数据时代&#xff0c;企业通过对海量数据信息进行清洗、聚类、分析&#xff0c;将数据抽象成标签&#xff0c;再利用这些标签将用户…

【Java中级篇】使用itextpdf生成PDF

我们可以发现很多求职网站都会将我们录入的信息来生成一个PDF简历文件。所以我这里提供了用itextpdf生成的PDF的代码。 一、步骤 1.1、使用Adobe Acrobat Pro工具编辑PDF模板 1.2、根据PDF模板文件路径创建一个PDFReader对象 1.3、创建一个输出流对象&#xff0c;用于存放生…

adb bugreport保存位置_adb 常用命令---日常提升效率

做为 Android 开发&#xff0c;怎么能不懂点 adb 命令呢&#xff1f;速看~adb 重置、断连的状况这里不说了&#xff0c;先来说一些直观的命令吧1、adb devices查看当前连接的设备如果当前正在连接着设备&#xff0c;那么就可以进行后续的操作了&#xff0c;如果没有&#xff0c…

【Java基础篇】你真的懂switch语句吗?

switch语句语法 switch (expression) {case value://语句break;//可选//可以有任意个case语句default://可选//语句} 注意点 switch的语句中表达式expression返回类型只能是byte、char、short、int和枚举类型&#xff0c;java1.7开始支持String类型&#xff1b; case语句值的…

jsp springmvc 视图解析器_Java面试题整理——SpringMVC

SpringMVC1、什么是SpringMVCSpring MVC是一个MVC的开源框架&#xff0c;Spring MVC Struts2spring&#xff0c;Spring MVC就相当于是Struts2加上Spring的整合&#xff0c;但是这里有一疑惑是Spring MVC和Spring是什么样的关系呢。Spring MVC是Spring的一个后续产品&#xff0…

【Java基础篇】Unicode、进制转换

一、unicode 先说一下unicode是什么&#xff1f; 最开始美国人搞出了ASCII这个东西&#xff0c;什么意思呢&#xff1f; 首先一个字节&#xff0c;我们都知道是8个bit位&#xff0c;总共能表示256种状态&#xff0c;然后我们就把这256种状态每种状态都对应一个字符。这种对应…

采集标签_分流器(二):灵活分流能力,数据采集无忧

数据采集分析难怎么办&#xff1f;昨天和大家分享了数据采集分析的最佳助手——分流器的一些基础知识&#xff0c;回顾链接&#xff0c;今天继续和您分享第二篇&#xff0c;带您更深入地了解分流器的强大功能。业务难点在网络安全和数据可视化趋势推动下&#xff0c;企业安全分…

【计算机原理篇】原码、反码和补码

注意&#xff1a;计算机实际上是按照补码进行存储的&#xff0c;对计算机来说没有原码和反码这种东西&#xff0c;原码和反码只是为了方便我们理解而定义的一种概念。 一、原码 正数的原码就是它本身&#xff0c;负数的原码最高位为1。 如果用一个字节来存储整数&#xff0c…

用友邮件撤回怎么操作_用户体验原则——“操作可控”

对于用户的误操作&#xff0c;提供二次确认或者撤销的功能&#xff0c;这样可提高用户的操作可控性。好设计应该是值得信任&#xff0c;也容易被相信的。在要求用户执行某一动作时&#xff0c;尽量帮他们理解为什么这个操作是必要的。每一步都需要借助诚实和清晰的表述来建立信…

蛋白结构建模与优化_最终幻想: 无中生有的蛋白质从头设计

作者简介: 刘源 北京大学化学与分子工程学院/力文所零.导读近几年&#xff0c;蛋白质结构预测领域连续取得重大突破。首先是【AlphaFold】&#xff0c;在可以充分利用共进化信息结合深度神经网络生成空间约束条件并降低相空间的搜索&#xff0c;极大地帮助了蛋白质的结构建模&a…

【JAVA基础篇】彻底搞懂拆箱装箱

什么是装箱拆箱&#xff1f; Java有8种基本数据类型&#xff0c;并且为这8种类型提供了包装器类型。比如说int类型的包装器类型是Integer。 装箱是指将基本数据类型转换成对应的包装器类型。拆箱是指将包装器类型转换基本数据类型。 Integer i 10; //自动装箱 int n i; …

gcn在图像上的应用_每日摘要|基于CNN 特征的图像卷积网络识别杂草和作物

文章信息标题&#xff1a;CNN feature based graph convolutional network for weed and crop recognition in smart farming期刊&#xff1a;《 Computers and Electronics in Agriculture》第一单位&#xff1a;山东农业大学在线日期&#xff1a;2020-05-13Highlights1.提出了…

安卓超过两行就加省略号_基础标点符号使用规则详解—8.省略号

省略号省略号&#xff0c;是标点符号家族中的比较特殊的一个符号&#xff0c;它是由六个小圆点组成。省略号的用法不止省略文字的作用。它还有以下几种用法。1用法一(一)表示重复词语或列举的省略。例&#xff1a;1、果园里有桃树、梨树、杏树、枇杷树……真的是种类齐全。2、那…

【Java基础篇】你真的了解构造器吗?

构造器是方法名和类名相同&#xff0c;并且没有返回值的特殊方法&#xff0c;可以使用的关键字有public, protected & private&#xff0c;或者省略&#xff08;表示default&#xff09; public class Constructor {//构造方法public Constructor(){}//实例方法public void…

【JAVA中级篇】线程池

上一篇文章已经介绍了线程的基本概念以及线程相关的API&#xff0c;下面来看一下线程池 一、线程池框架 1、线程池的优点 重用线程池中的线程&#xff0c;避免因为线程的创建和销毁所带来的性能开销。 能有效控制线程池的最大并发数&#xff0c;避免大量线程之间因互相抢夺系…