使用JDBC实例理解数据库的事务隔离
使用JDBC实例理解数据库的事务隔离
数据库的事务是用来处理数据的一个机制,作为一个整体,要么全部提交,要么全部回滚。
事务的4大特性(ACID):
原子性(Atomicity):事务是数据库的逻辑工作单位,它对数据库的修改要么全部执行,要么全部不执行。
一致性(Consistemcy):事务前后,数据库的状态都满足所有的完整性约束。
隔离性(Isolation):并发执行的N个事务是隔离的,一个事务不影响另一个事务,通过设置数据库的隔离级别,一个事务在没有commit之前,被修改的数据不可能被其他事务看到。
持久性(Durability):持久性意味着当系统或介质发生故障时,确保已提交事务的更新不能丢失。持久性主要在于DBMS的恢复性能。
今天重点理解事务的隔离性。
一、事务的隔离级别
事务的隔离级别是由底层的数据库实现的,通常有如下五种:
TRANSACTION_NONE:没有事务
TRANSACTION_READ_UNCOMMITTED:读取没有提交的事务
TRANSACTION_READ_COMMITTED:读取提交的事务
TRANSACTION_REPEATABLE_READ:不可重复读事务
TRANSACTION_SERIALIZABLE:序列化事务
他们都可以通过java.sql.Connection获取,对应的整数值分别为0、1、2、4、8,级别从低到高,低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
设置不同的级别会出现不同的问题:
1、 READ_UNCOMMITTED:会出现脏读、不可重复读和幻读问题;
2、READ_COMMITTED:会出现不可重复读和幻读问题;
3、REPEATABLE_READ:不会出现上面的问题,且允许事务的并发执行。
4、SERIALIZABLE:串行化,不会出现上面的问题,事务执行的时候不允许别的事务并发执行。事务串行化执行,事务只能一个接着一个地执行,而不能并发执行。一个事务在执行过程中完全看不到其他事务对数据库所做的更新。
我们以JDBC为例,设置不同的隔离级别,理解上述问题。
二、JDBC的事务处理
1、 获取事务的隔离级别
通过通过java.sql.Connection获取。
System.out.println(Connection.TRANSACTION_NONE);//0
System.out.println(Connection.TRANSACTION_READ_UNCOMMITTED);//1
System.out.println(Connection.TRANSACTION_READ_COMMITTED);//2
System.out.println(Connection.TRANSACTION_REPEATABLE_READ);//4
System.out.println(Connection.TRANSACTION_SERIALIZABLE);//8
2、 JDBC的开启事务
JDBC中默认是自动提交数据,只要把Connection的对象的setAutoCommit设为false,conn.setAutoCommit(false);由自动提交变为手动提交,就开启了事务。
3、 设置事务的隔离级别
conn.setTransactionIsolation(4);//参数为整数,不同的值代表不同的级别
4、 获取事务的隔离级别
conn.getTransactionIsolation()
用这种方法,可以获取 Orace数据库默认提供的是READ_COMMITTED隔离级别,MySQL是TRANSACTION_REPEATABLE_READ。
5、 事务处理
conn.commit();//事务提交
conn.rollback();//事务回滚
6、 关闭事务
conn.setAutoCommit(true)
三、脏读、不可重复读和幻读
1、可重复读:
A事务进行的过程中进行了一次读操作,这时B事务对此数据进行了Update修改,并commit,这时事务A再一次读取此条数据,读取到的将不是B事务修改后的值,而是原值,对原值可重复读。
2、不可重复读:
A事务进行的过程中进行了一次读操作,这时B事务对此数据进行了Update修改,并commit,这时事务A再一次读取此条数据,读取到的是B事务修改后的值,而原来的值不可以再读取到,所以叫做不可重复读。
不可重复读是指在同一个事务内,两个相同的查询返回了不同的结果,不可重复读的重点是修改,对某一行或者某一条数据进行修改,避免不可重复读需要锁行就行。
3、幻读:
事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一行新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻想。幻读的重点在于在表中新增或者删除 符合条件的整行,避免幻影读则需要锁表。
4、脏读:
脏读又称无效数据读出。一个事务读取另外一个事务还没有提交的数据叫脏读。
例如:事务T1修改了一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后的数据,之后事务T1因为某种原因Rollback了,那么事务T2读取的数据就是脏的。
解决办法:把数据库的事务隔离级别调整到READ_COMMITTED
四、JDBC实例理解事务的隔离级别
1、 脏读:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTxIsolation {
public static void main(String[] args) {
/**
* 脏读:把隔离级别设为1
* 一个A事务读取另一个B事务没有提交的数据,说明库里还没有改数据,但是A事务已经查询出该数据,没有和数据库保持一致,
*/
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connA = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "root", "root");
connA.setAutoCommit(false);// 开启了A事务
connA.setTransactionIsolation(2);// 设置事务的隔离级别为1,说明可以读取没有提交的数据
Connection connB = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "root", "root");
connB.setAutoCommit(false);// 开启了B事务
String sql = "updateJava607 set name='唐飞' whereid=1";
PreparedStatement pstmtB = connB.prepareStatement(sql);
pstmtB.executeUpdate();
// B事务没有提交
// connB.commit();
// A事务查询数据
String sqlA = "select *from Java607";
PreparedStatement pstmtA = connA.prepareStatement(sqlA);
ResultSet rs = pstmtA.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt("id") + " "
+ rs.getString("name"));
}
connB.setAutoCommit(true);// 关闭B事务
connA.setAutoCommit(true);// 关闭A事务
} catch (ClassNotFoundException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
2、 幻读
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTxIsolation2 {
public static void main(String[] args) {
/**
* 幻读:如果隔离级别设为1、2
* A事务对表进行某种条件的查询操作,这时B事务插入或者删除符合某种条件的操作,A事务对表进行再次查询同样的操作,发现前后两次的结果不一样
* 解决方案:设置隔离级别设为4、8
* 只要锁定整张表
*/
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connA = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "root", "root");
connA.setAutoCommit(false);//开启了A事务
connA.setTransactionIsolation(2);//设置事务的隔离级别为1或2,会出现幻读
//A事务查询数据
String sqlA="select * from Java607";
PreparedStatementpstmtA=connA.prepareStatement(sqlA);
ResultSet rs= pstmtA.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("id")+" "+rs.getString("name"));
}
Connection connB = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "root", "root");
connB.setAutoCommit(false);//开启了B事务
String sql="insert into Java607 values(9,'打分7')";
PreparedStatementpstmtB=connB.prepareStatement(sql);
pstmtB.executeUpdate();
//B事务提交
connB.commit();
connB.setAutoCommit(true);//关闭B事务
//A事务再次查询数据
String sqlA2="select * from Java607";
PreparedStatementpstmtA2=connA.prepareStatement(sqlA2);
ResultSet rs2= pstmtA2.executeQuery();
System.out.println("=======");
while(rs2.next()){
System.out.println(rs2.getInt("id")+" "+rs2.getString("name"));
}
connB.setAutoCommit(true);//关闭B事务
connA.setAutoCommit(true);//关闭A事务
} catch (ClassNotFoundException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
3、 不可重复读
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTxIsolation3 {
public static void main(String[] args) {
/**
*不可重复读隔离级别=1,2
*A事务查询某条记录的某个值,然后B事务修改这个值,A事务查询再一次查询,发现的得到的值已经不是以前那个值,所以叫不可重复读
*解决方案:设置隔离级别设为4。8
*只要锁定操作的一条记录
*/
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connA = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "root", "root");
connA.setAutoCommit(false);//开启了A事务
connA.setTransactionIsolation(8);//设置事务的隔离级别为1,
//A事务查询数据
String sqlA="select name from java607 where id=1";
PreparedStatementpstmtA=connA.prepareStatement(sqlA);
ResultSet rs= pstmtA.executeQuery();
while(rs.next()){
System.out.println(rs.getString("name"));
}
Connection connB = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "root", "root");
connB.setAutoCommit(false);//开启了B事务
String sql="update Java607 set name='new3' where id=1";
PreparedStatementpstmtB=connB.prepareStatement(sql);
pstmtB.executeUpdate();
//B事务提交
connB.commit();
//connB.close();
connB.setAutoCommit(true);//关闭B事务
//A事务查询数据
String sqlA2="select name from java607 where id=1";
PreparedStatementpstmtA2=connA.prepareStatement(sqlA2);
ResultSet rs2= pstmtA2.executeQuery();
while(rs2.next()){
System.out.println(rs2.getString("name"));
}
connB.setAutoCommit(true);//关闭A事务
connA.setAutoCommit(true);//关闭A事务
} catch (ClassNotFoundException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
使用JDBC实例理解数据库的事务隔离相关推荐
- 【数据库】事务隔离级别
事务隔离级别 为了更好地说明事务隔离级别,请先移步快速理解脏读.不可重复读.幻读 有四种隔离级别,分别是读未提交(Read uncommitted),读已提交(Read committed),可重复读 ...
- 数据库的事务隔离技术 之 MVCC
在mysql中,提供了两种事务隔离技术,第一个是mvcc,第二个是next-key技术. 这个在使用不同的语句的时候可以动态选择.不加lock in share mode之类的就使用mvcc.否则使用 ...
- 数据库的事务隔离级别
ANSI/ISO SQL92标准定义了一些数据库操作的隔离级别: l 未提交读(read uncommitted) l 提交读(read committed) l 重复读(repeatable rea ...
- 【数据库】Oracle数据库查看事务隔离级别
查看Oracle数据库事务的隔离级别. --Oracle 查看事务隔离级别 SELECT * From dual for update;SELECT s.sid, s.serial#, case bi ...
- 数据库的事务,隔离级别和3大范式
*数据库事务的想关操作 1.事务开始:开始是一个事物,作为回滚的标记 2,回滚 rollback :回滚到上一个事务开始的地方, 或者回滚到某个存档点,期间没被 commit ; 操作都会被撤回 3. ...
- spring的事务隔离_再深一点:面试工作两不误,源码级理解Spring事务
原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. Spring有5种隔离级别,7种传播行为.这是面试常问的内容,也是代码中经常碰到的知识点.这些知识枯燥而且乏味,其中有些非 ...
- 2.4.4 案例理解4种事务的隔离级别
2.4.4 通过案例理解4种事务的隔离级别 MySQL数据库管理·实战案例7 需求 1 分析当前数据库的事务隔离级别 2 对四种事务隔离级别进行切换,并对比其效果,最终使用哪种隔离级别. # 设置隔离 ...
- 数据库事务的四大特性及事务隔离级别
概要: 事务的四个特性:原子性.一致性.隔离性.持久性 事务不隔离带来的问题:更新丢失.脏读.不可重复读.虚读(幻读).其中更新丢失就是并发写,这是一定不允许的,因此一定要解决更新丢失问题. 事务隔离 ...
- 数据库 事务隔离级别之可重复读
通过下面的sql语句,在sql客户端查询可以获取数据库的事务隔离级别: show variables like '%isolation%'; 查看全局事务隔离级别和session事务隔离级别(mysq ...
最新文章
- 一键修改分辨率bat_求使用批处理BAT设置分辨率的方法介绍?
- BGP 路由属性 公认必遵 ORIGIN
- Mysql 添加字段 修改字段 删除字段
- linux 文件理解,对linux中文件系统的理解
- jQuery实现表格隔行换颜色:
- 过滤器如何配置(javax.servlet.Filter)?
- 网管人员必备的常用命
- java如何让cpu过负荷_服务器开发过载问题如何解决
- 微信小程序学习日记---模板(template)全解析
- 杰理AD14N/AD15N---串口中断问题
- lmdb数据库的读取与转换(一) —— 基本操作
- 一文看懂YOLO v3
- 完全用计算机制作的三维动画,通过四个步骤告诉你三维动画怎么制作
- 手机兼职赚钱,分享2个手机可操作的项目给你!
- Java cipher加密与解密
- 原子物理与原子核物理知识结构(含链接)
- php模板引擎循环start,smarty模板引擎foreach和section循环操作详解
- Linux下实现文件实时同步(rsync命令+rsync作为服务+xinetd托管rsync)
- 【EM(electron migration)】
- ChatGPT当中的“GPT”是什么意思?