【转】JDBC学习笔记(7)——事务的隔离级别&批量处理
转自:http://www.cnblogs.com/ysw-go/
数据库事务的隔离级别
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
脏读: 对于两个事务 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
具体代码实现:

1 /** 2 * ID1 给 ID2 500钱 3 * 关于事务: 4 * 1.如果多个操作,每个使用自己单独的连接,则无法保证事务 例 test1演示 5 * 2.具体步骤: 6 * 1) 事务开始前,取消Connection 的默认的自动提交 setAutoCommit(false); 7 * 2) 如果事务的操作都成功,那么就提交事务 8 * 3)否则在 try-catch块中回滚 9 * try { 10 * 11 * conn.setAutoCommit(false); 12 * ... 13 * conn.commit(); 14 * }catch{ 15 * ... 16 * conn.rollback(); 17 * } 18 */ 19 @Test 20 public void test2(){ 21 22 Connection conn = null; 23 try { 24 conn = JDBC_Tools.getConnection(); 25 //System.out.println(conn.getAutoCommit()); 26 27 // 1) 取消自动提交 28 conn.setAutoCommit(false); 29 30 String sql = "UPDATE rent set money = " 31 + "money - 500 where id = ?"; 32 33 // 2) 如果事务的操作都成功,那么就提交事务 34 update(conn,sql, 1); 35 36 //int i = 1 / 0; 37 38 sql = "UPDATE rent set money = " 39 + "money + 500 where id = ?"; 40 update(conn,sql, 2); 41 conn.commit(); 42 } catch (Exception e) { 43 e.printStackTrace(); 44 45 // 3)否则在 try-catch块中回滚 46 try { 47 conn.rollback(); 48 } catch (SQLException e1) { 49 e1.printStackTrace(); 50 } 51 52 }finally{ 53 JDBC_Tools.relaseSource(conn, null); 54 } 55 } 56 public static void update(Connection conn,String sql,Object...objs){ 57 58 PreparedStatement ps =null; 59 try { 60 ps = conn.prepareStatement(sql); 61 62 for(int i = 0;i<objs.length;i++){ 63 ps.setObject(i+1, objs[i]); 64 } 65 ps.executeUpdate(); 66 } catch (Exception e) { 67 e.printStackTrace(); 68 }finally{ 69 JDBC_Tools.relaseSource(null, ps); 70 } 71 } 72 73 @Test 74 public void test1() { 75 76 String sql = "UPDATE rent set money = " 77 + "money - 500 where id = ?"; 78 DAO.update(sql, 1); 79 80 int i = 1 / 0; //一旦出现异常, ID1 减了500,但是 ID2 的钱并没有增加 81 82 sql = "UPDATE rent set money = " 83 + "money + 500 where id = ?"; 84 DAO.update(sql, 2); 85 }设置隔离级别 86 87 public static <E> E getForValue(String sql){ 88 89 //1. 得到结果集,该结果只有一行一列 90 Connection conn = null; 91 PreparedStatement ps = null; 92 ResultSet rs = null; 93 try { 94 //1. 获取数据库连接 95 conn = JDBC_Tools.getConnection();//System.out.println(conn.getTransactionIsolation()); 96 conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); 97 //2. 获取 PreparedStatement 对象 98 ps = conn.prepareStatement(sql); 99 //2. 取得结果 100 rs = ps.executeQuery(); 101 if(rs.next()){ 102 return (E)rs.getObject(1); 103 } 104 }catch(Exception e){ 105 e.printStackTrace(); 106 }finally{ 107 JDBC_Tools.relaseSource(rs,conn, ps); 108 } 109 return null; 110 }

在 MySql 中设置隔离级别
具体代码实现:

1 public static <E> E getForValue(String sql){ 2 3 //1. 得到结果集,该结果只有一行一列 4 Connection conn = null; 5 PreparedStatement ps = null; 6 ResultSet rs = null; 7 try { 8 //1. 获取数据库连接 9 conn = JDBC_Tools.getConnection();//System.out.println(conn.getTransactionIsolation()); 10 conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); 11 //2. 获取 PreparedStatement 对象 12 ps = conn.prepareStatement(sql); 13 //2. 取得结果 14 rs = ps.executeQuery(); 15 if(rs.next()){ 16 return (E)rs.getObject(1); 17 } 18 }catch(Exception e){ 19 e.printStackTrace(); 20 }finally{ 21 JDBC_Tools.relaseSource(rs,conn, ps); 22 } 23 return null; 24 }

启动一个 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进行事务的操作

1 @Test 2 public void testBatchWithStatement(){ 3 Connection connection=null; 4 Statement statement=null; 5 String sql; 6 try { 7 connection=JDBCTools.getConnection(); 8 //放到一个事务里面 9 JDBCTools.beginTx(connection); 10 statement=connection.createStatement(); 11 long begin=System.currentTimeMillis(); 12 for(int i=0;i<100000;i++){ 13 sql="insert into testj values("+ 14 (i+1)+", 'name_"+ i+"', '2016-05-08')"; 15 statement.execute(sql); 16 } 17 long end=System.currentTimeMillis(); 18 System.out.println("Time:"+(end-begin)); 19 JDBCTools.commit(connection); 20 } catch (Exception e) { 21 e.printStackTrace(); 22 JDBCTools.rollback(connection); 23 }finally{ 24 JDBCTools.release(null, statement, connection); 25 } 26 }

运行结果:
Time:8991
结论一:我们使用Statement插入100000条记录用时8991;
版本二:我们使用PreparedStatement进行事务的操作

1 @Test 2 public void testBatchWithPreparedStatement() { 3 Connection connection = null; 4 PreparedStatement preparedStatement = null; 5 String sql; 6 try { 7 connection = JDBCTools.getConnection(); 8 // 放到一个事务里面 9 JDBCTools.beginTx(connection); 10 sql = "isnert into testJ values(?,?,?)"; 11 preparedStatement = connection.prepareStatement(sql); 12 long begin = System.currentTimeMillis(); 13 for (int i = 0; i < 100000; i++) { 14 preparedStatement.setInt(1, i + 1); 15 preparedStatement.setString(2, "name_" + i); 16 preparedStatement.setDate(3, 17 new Date(new java.util.Date().getTime())); 18 preparedStatement.execute(); 19 } 20 long end = System.currentTimeMillis(); 21 System.out.println("Time:" + (end - begin)); 22 JDBCTools.commit(connection); 23 } catch (Exception e) { 24 e.printStackTrace(); 25 JDBCTools.rollback(connection); 26 } finally { 27 JDBCTools.release(null, preparedStatement, connection); 28 } 29 }

运行结果:
Time:8563
结论2:因为我这里使用的是mysql数据库进行的操作,插入大量数据的时间性能方面的影响不是很大,如果我们换成oracle数据库或其他大型的关系型数据库,事务执行用时相比版本一的1/4;
版本三:批处理插入数据

1 @Test 2 public void testBatchWithBatch() { 3 Connection connection = null; 4 PreparedStatement preparedStatement = null; 5 String sql=null; 6 try { 7 connection = JDBCTools.getConnection(); 8 // 放到一个事务里面 9 JDBCTools.beginTx(connection); 10 sql = "insert into testJ values(?,?,?)"; 11 preparedStatement = connection.prepareStatement(sql); 12 long begin = System.currentTimeMillis(); 13 for (int i = 0; i < 100000; i++) { 14 preparedStatement.setInt(1, i + 1); 15 preparedStatement.setString(2, "name_" + i); 16 preparedStatement.setDate(3, 17 new Date(new java.util.Date().getTime())); 18 //积攒SQL 19 preparedStatement.addBatch(); 20 //当积攒到一定程度,就统一执行,并且清空先前积攒的SQL 21 if((i+1)%300==0){ 22 //执行 23 preparedStatement.executeBatch(); 24 //清空 25 preparedStatement.clearBatch(); 26 } 27 } 28 //如果插入的记录数不是300的整倍数,再执行一次 29 if(100000%300!=0){ 30 //执行 31 preparedStatement.executeBatch(); 32 //清空 33 preparedStatement.clearBatch(); 34 } 35 long end = System.currentTimeMillis(); 36 System.out.println("Time:" + (end - begin)); 37 JDBCTools.commit(connection); 38 } catch (Exception e) { 39 e.printStackTrace(); 40 JDBCTools.rollback(connection); 41 } finally { 42 JDBCTools.release(null, preparedStatement, connection); 43 } 44 }

运行结果:4587(又提高了,但是还是不明显)
结论三:批处理事务建议采用版本三的方式,再次建议使用oracle数据库做这个插入数据事务的实验,mysql小数据还成,大量的数据也真呵呵了;
【转】JDBC学习笔记(7)——事务的隔离级别&批量处理的更多相关文章
- JDBC学习笔记(7)——事务的隔离级别&批量处理
数据库事务的隔离级别 对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 ...
- 数据库事务的四大特性以及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 ...
- JDBC学习笔记一
JDBC学习笔记一 JDBC全称 Java Database Connectivity,即数据库连接,它是一种可以执行SQL语句的Java API. ODBC全称 Open Database Conn ...
随机推荐
- 使用ocupload和POI一键上传Excel并解析导入数据库
使用的工具如下: JQuery ocupload jquery.ocupload-1.1.2.js Apache POI poi-3.9.jar 如果是Maven项目添加依赖如下: <depe ...
- 关于label和input对齐的那些事
input文本和label对齐 默认状态下,也就是下面这样, 文字和input是居中的. <div> <label>我是中国人</label> <input ...
- 20155304 2016-2017-2 《Java程序设计》第三周学习总结
20155304 2016-2017-2 <Java程序设计>第三周学习总结 教材学习内容总结 第四章 类与对象 定义: 对象(Object):存在的具体实体,具有明确的状态和行为. 类( ...
- 3450: Tyvj1952 Easy
3450: Tyvj1952 Easy Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 269 Solved: 198[Submit][Status] ...
- Servlet 学习简介
一.Servlet简介 Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的 ...
- Spring+SpringMVC+MyBatis+easyUI整合基础篇(十二)阶段总结
不知不觉,已经到了基础篇的收尾阶段了,看着前面的十几篇文章,真的有点不敢相信,自己竟然真的坚持了下来,虽然过程中也有过懒散和焦虑,不过结果还是自己所希望的,克服了很多的问题,将自己的作品展现出来,也发 ...
- linux版powershell安装教程(.net core版)
powershell 传教士 原创文章 始于2016-12-20,2017-03-15改.文章版本目前博客园为最新版. 允许转载,但必须保留名字和出处,否则追究法律责任 问:powershell二进制 ...
- docker工作流程
Docker提供一种方法在容器中运行安全隔离的应用程序,应用程序与所有依赖项和库一起打包在容器中.因为你的应用程序总是可以使用它在构建镜像中期望的环境运行,测试和部署比以往任何时候都更简单,因为你的构 ...
- 时间相关库<ctime>解析
原创作品,转载请注明来源:http://www.cnblogs.com/shrimp-can/p/5649487.html 一.定义的类型 1.clock_t:时钟类型 2.size_t:unsign ...
- Jmeter新建用例图示
添加线程组 添加HTTP请求 编辑HTTP请求 添加HTTP信息头 编辑HTTP信息头 添加断言 添加查看结果树 添加聚合报告 添加响应时间 添加TPS 批量运行命令: ...