JDBC学习笔记(7)——事务的隔离级别&批量处理
数据库事务的隔离级别
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
不可重复读: 对于两个事务 T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.
幻读: 对于两个事务 T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题.
一个事务与其他事务隔离的程度称为隔离级别. 数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱
数据库提供的 4 种事务隔离级别:
Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE. Oracle 默认的事务隔离级别为: READ COMMITED
Mysql 支持 4 中事务隔离级别. Mysql 默认的事务隔离级别为: REPEATABLE READ
具体代码实现:
/**
* ID1 给 ID2 500钱
* 关于事务:
* 1.如果多个操作,每个使用自己单独的连接,则无法保证事务 例 test1演示
* 2.具体步骤:
* 1) 事务开始前,取消Connection 的默认的自动提交 setAutoCommit(false);
* 2) 如果事务的操作都成功,那么就提交事务
* 3)否则在 try-catch块中回滚
* try {
*
* conn.setAutoCommit(false);
* ...
* conn.commit();
* }catch{
* ...
* conn.rollback();
* }
*/
@Test
public void test2(){ Connection conn = null;
try {
conn = JDBC_Tools.getConnection();
//System.out.println(conn.getAutoCommit()); // 1) 取消自动提交
conn.setAutoCommit(false); String sql = "UPDATE rent set money = "
+ "money - 500 where id = ?"; // 2) 如果事务的操作都成功,那么就提交事务
update(conn,sql, 1); //int i = 1 / 0; sql = "UPDATE rent set money = "
+ "money + 500 where id = ?";
update(conn,sql, 2);
conn.commit();
} catch (Exception e) {
e.printStackTrace(); // 3)否则在 try-catch块中回滚
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
} }finally{
JDBC_Tools.relaseSource(conn, null);
}
}
public static void update(Connection conn,String sql,Object...objs){ PreparedStatement ps =null;
try {
ps = conn.prepareStatement(sql); for(int i = 0;i<objs.length;i++){
ps.setObject(i+1, objs[i]);
}
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally{
JDBC_Tools.relaseSource(null, ps);
}
} @Test
public void test1() { String sql = "UPDATE rent set money = "
+ "money - 500 where id = ?";
DAO.update(sql, 1); int i = 1 / 0; //一旦出现异常, ID1 减了500,但是 ID2 的钱并没有增加 sql = "UPDATE rent set money = "
+ "money + 500 where id = ?";
DAO.update(sql, 2);
}设置隔离级别 public static <E> E getForValue(String sql){ //1. 得到结果集,该结果只有一行一列
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1. 获取数据库连接
conn = JDBC_Tools.getConnection();//System.out.println(conn.getTransactionIsolation());
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
//2. 获取 PreparedStatement 对象
ps = conn.prepareStatement(sql);
//2. 取得结果
rs = ps.executeQuery();
if(rs.next()){
return (E)rs.getObject(1);
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBC_Tools.relaseSource(rs,conn, ps);
}
return null;
}
在 MySql 中设置隔离级别
具体代码实现:
public static <E> E getForValue(String sql){ //1. 得到结果集,该结果只有一行一列
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1. 获取数据库连接
conn = JDBC_Tools.getConnection();//System.out.println(conn.getTransactionIsolation());
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
//2. 获取 PreparedStatement 对象
ps = conn.prepareStatement(sql);
//2. 取得结果
rs = ps.executeQuery();
if(rs.next()){
return (E)rs.getObject(1);
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBC_Tools.relaseSource(rs,conn, ps);
}
return null;
}
启动一个 mysql 程序, 就会获得一个单独的数据库连接. 每个数据库连接都有一个全局变量 @@tx_isolation, 表示当前的事务隔离级别. MySQL 默认的隔离级别为 Repeatable Read
查看当前的隔离级别: SELECT @@tx_isolation;
设置当前 mySQL 连接的隔离级别:
set transaction isolation level read committed;
设置数据库系统的全局的隔离级别:
set global transaction isolation level read committed;
JDBC批量执行
当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率
/**
* 向mysql的testJ数据表中插入100000条记录
* 测试如何插入用时最短
* 版本一:使用Statement
*/
版本一:我们使用Statement进行事务的操作
@Test
public void testBatchWithStatement(){
Connection connection=null;
Statement statement=null;
String sql;
try {
connection=JDBCTools.getConnection();
//放到一个事务里面
JDBCTools.beginTx(connection);
statement=connection.createStatement();
long begin=System.currentTimeMillis();
for(int i=0;i<100000;i++){
sql="insert into testj values("+
(i+1)+", 'name_"+ i+"', '2016-05-08')";
statement.execute(sql);
}
long end=System.currentTimeMillis();
System.out.println("Time:"+(end-begin));
JDBCTools.commit(connection);
} catch (Exception e) {
e.printStackTrace();
JDBCTools.rollback(connection);
}finally{
JDBCTools.release(null, statement, connection);
}
}
运行结果:
Time:8991
结论一:我们使用Statement插入100000条记录用时8991;
版本二:我们使用PreparedStatement进行事务的操作
@Test
public void testBatchWithPreparedStatement() {
Connection connection = null;
PreparedStatement preparedStatement = null;
String sql;
try {
connection = JDBCTools.getConnection();
// 放到一个事务里面
JDBCTools.beginTx(connection);
sql = "isnert into testJ values(?,?,?)";
preparedStatement = connection.prepareStatement(sql);
long begin = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
preparedStatement.setInt(1, i + 1);
preparedStatement.setString(2, "name_" + i);
preparedStatement.setDate(3,
new Date(new java.util.Date().getTime()));
preparedStatement.execute();
}
long end = System.currentTimeMillis();
System.out.println("Time:" + (end - begin));
JDBCTools.commit(connection);
} catch (Exception e) {
e.printStackTrace();
JDBCTools.rollback(connection);
} finally {
JDBCTools.release(null, preparedStatement, connection);
}
}
运行结果:
Time:8563
结论2:因为我这里使用的是mysql数据库进行的操作,插入大量数据的时间性能方面的影响不是很大,如果我们换成oracle数据库或其他大型的关系型数据库,事务执行用时相比版本一的1/4;
版本三:批处理插入数据
@Test
public void testBatchWithBatch() {
Connection connection = null;
PreparedStatement preparedStatement = null;
String sql=null;
try {
connection = JDBCTools.getConnection();
// 放到一个事务里面
JDBCTools.beginTx(connection);
sql = "insert into testJ values(?,?,?)";
preparedStatement = connection.prepareStatement(sql);
long begin = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
preparedStatement.setInt(1, i + 1);
preparedStatement.setString(2, "name_" + i);
preparedStatement.setDate(3,
new Date(new java.util.Date().getTime()));
//积攒SQL
preparedStatement.addBatch();
//当积攒到一定程度,就统一执行,并且清空先前积攒的SQL
if((i+1)%300==0){
//执行
preparedStatement.executeBatch();
//清空
preparedStatement.clearBatch();
}
}
//如果插入的记录数不是300的整倍数,再执行一次
if(100000%300!=0){
//执行
preparedStatement.executeBatch();
//清空
preparedStatement.clearBatch();
}
long end = System.currentTimeMillis();
System.out.println("Time:" + (end - begin));
JDBCTools.commit(connection);
} catch (Exception e) {
e.printStackTrace();
JDBCTools.rollback(connection);
} finally {
JDBCTools.release(null, preparedStatement, connection);
}
}
运行结果:4587(又提高了,但是还是不明显)
结论三:批处理事务建议采用版本三的方式,再次建议使用oracle数据库做这个插入数据事务的实验,mysql小数据还成,大量的数据也真呵呵了;
本文为博主原创文章,转载请注明出处:http://www.cnblogs.com/ysw-go/
1、本博客的原创原创文章,都是本人平时学习所做的笔记,如有错误,欢迎指正。
2、如有侵犯您的知识产权和版权问题,请通知本人,本人会即时做出处理文章。
3、本博客的目的是知识交流所用,转载自其它博客或网站,作为自己的参考资料的,感谢这些文章的原创人员
JDBC学习笔记(7)——事务的隔离级别&批量处理的更多相关文章
- 【转】JDBC学习笔记(7)——事务的隔离级别&批量处理
转自:http://www.cnblogs.com/ysw-go/ 数据库事务的隔离级别 对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发 ...
- 数据库事务的四大特性以及4种事务的隔离级别-以及对应的5种JDBC事务隔离级别
本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指事务 ...
- 数据库事务的四大特性以及事务的隔离级别(mysql)
本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指 ...
- 数据库事务的四大特性以及事务的隔离级别-与-Spring事务传播机制&隔离级别
数据库事务的四大特性以及事务的隔离级别 本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ ...
- MySQL事务的隔离级别
为什么需要隔离 当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,在介绍数据库提供的各种隔离级别之前,我们先看看如果不考虑事务的隔离性,会发生的几种 ...
- MySQL数据库事务的四大特性以及事务的隔离级别
一.事务的四大特性(ACID) 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: 1.原子性(Atomicity) 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因 ...
- JDBC 学习笔记(十一)—— JDBC 的事务支持
1. 事务 在关系型数据库中,有一个很重要的概念,叫做事务(Transaction).它具有 ACID 四个特性: A(Atomicity):原子性,一个事务是一个不可分割的工作单位,事务中包括的诸操 ...
- JDBC 学习笔记(二)—— 大数据+存储过程+批处理+事务管理
本文目录: 1.使用JDBC处理大数据 2.使用JDBC处理大文本 3.使用JDBC处理二进制数据 4.Oracle中大数据处理 5 ...
- Java -- JDBC 事务处理, 事务的隔离级别 脏读 不可重复读 等...
1. 事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功. 数据库开启事务命令 •start transaction 开启事务 •Rollback 回滚事务 •Commit ...
随机推荐
- WIN7建立网络映射磁盘
建立网络映射磁盘 如果需要经常访问网络中的同一个共享文件夹,则可以将这个共享文件夹直接映射为本地计算机中的一个虚拟驱动器.其具体操作如下. (1)双击桌面上"计算机"图标,打开&q ...
- [CF676C]Vasya and String(尺取法,原题)
题目链接:http://codeforces.com/contest/676/problem/C 原题题解链接:http://www.cnblogs.com/vincentX/p/5405468.ht ...
- [POJ1330]Nearest Common Ancestors(LCA, 离线tarjan)
题目链接:http://poj.org/problem?id=1330 题意就是求一组最近公共祖先,昨晚学了离线tarjan,今天来实现一下. 个人感觉tarjan算法是利用了dfs序和节点深度的关系 ...
- Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define
尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...
- lrj计算几何模板
整理了一下大白书上的计算几何模板. #include <cstdio> #include <algorithm> #include <cmath> #include ...
- ASP.NET中MEMCACHED
一,准备 你需要有一下软件: VS.NET(05/08) SQLSERVER memcached服务器端以及客户端类库(开源软件,下载即可)其中,客户 ...
- UVA 1660 Cable TV Network 电视网络(无向图,点连通度,最大流)
题意:给一个无向图,求其点连通度?(注意输入问题) 思路: 如果只有1个点,那么输出“1”: 如果有0条边,那么输出“0”: 其他情况:用最大流解决.下面讲如何建图: 图的连通度问题是指:在图中删去部 ...
- Spring各jar包的作用(转载)
spring.jar是包含有完整发布的单个jar 包,spring.jar中包含除了spring-mock.jar里所包含的内容外其它所有jar包的内容,因为只有在开发环境下才会用到 spring-m ...
- Xcode中使用svn时,报证书验证错误Error validating server certificate for
转:http://blog.csdn.net/yhawaii/article/details/7511141 今天使用Xcode自带的svn客户端时,总是连接不上服务器,报如下错误: Error va ...
- android学习—— context 和 getApplicationContext()
一直看到好多应用里面,随手使用getApplicationContext(),不想说也不乐意说,今天转载一篇文章区分两者的区别: 在android中常常会遇到与context有关的内容 浅论一下con ...