今天我想要分享的是关于数据库的批处理与事务的控制。批处理对于项目的实际应用有非常大的具体意义。

一、批处理部分

首先我们新建一个表:

create table t3(

id int primary key auto_increment,

name varchar(100)

);

注意:auto_increment只适用于mysql中,对于oracle需要用的是创建一个序列来实现自动增长:create squences seq_t3_id
 start with 1 increment by 1;这里以mysql为例,对于oracle方法类似,请自行脑补

同时请注意:JDBC的批处理不能加入select语句,否则会抛异常:

java.sql.BatchUpdateException: Can not issue SELECT viaexecuteUpdate().

atcom.mysql.jdbc.StatementImpl.executeBatch(StatementImpl.java:1007)

只能作用于增删改。

SQL批处理是JDBC性能优化的重要武器,批处理的用法有三种。

1、混合多种语句的批量处理,可同时执行增删改:

  1. @Test
  2. public void test1(){
  3. String sql1="insert into t3(name) values('aa1')";
  4. String sql2="insert into t3(name) values('aa2')";
  5. String sql3="insert into t3(name) values('aa3')";
  6. String sql4="insert into t3(name) values('aa4')";
  7. String sql5="insert into t3(name) values('aa5')";
  8. String sql6="delete from t3 where name='aa1'";
  9. String sql7="update t3 set name='bb1' where name='aa2'";
  10. Connection conn=null;
  11. Statement stmt=null;
  12. try {
  13. conn=JdbcUtil.getConnection();
  14. stmt=conn.createStatement();
  15. stmt.addBatch(sql1);
  16. stmt.addBatch(sql2);
  17. stmt.addBatch(sql3);
  18. stmt.addBatch(sql4);
  19. stmt.addBatch(sql5);
  20. stmt.addBatch(sql6);
  21. stmt.addBatch(sql7);
  22. int[] ii=stmt.executeBatch();
  23. } catch (Exception e) {
  24. // TODO Auto-generated catch block
  25. e.printStackTrace();
  26. }finally{
  27. JdbcUtil.release(null, stmt, conn);
  28. }
  29. }

2、批量插入少量数据,例如进行数据迁移的时候

  1. //批量插入100条记录,数据迁移项目
  2. @Test
  3. public void test1(){
  4. String sql="insert into t3(name) values(?)";
  5. Connection conn=null;
  6. PreparedStatement stmt=null;
  7.  
  8. try {
  9. conn=JdbcUtil.getConnection();
  10. stmt=conn.prepareStatement(sql);
  11. for(int i=0;i<100;i++){
  12. stmt.setString(1, "aa"+(i+1));
  13. stmt.addBatch();
  14. }
  15. int[] ii=stmt.executeBatch();
  16.  
  17. } catch (Exception e) {
  18. // TODO Auto-generated catch block
  19. e.printStackTrace();
  20. }finally{
  21. JdbcUtil.release(null, stmt, conn);
  22. }
  23. }

批量插入大量数据,例如插入几万或者几十万的时候,这个时候因为数据量大,如果我们直接插入的话速度是非常非常慢的,因为这样插入的时候executeBatch();会占用内存,数据量大自然占的内存也就对了,这对我们的机器是非常不好的,所以我们要对这些数据进行一些处理。

  1. //批量插入100000条记录,数据迁移项目
  2. @Test
  3. public void test1(){
  4. String sql="insert into t3(name) values(?)";
  5. Connection conn=null;
  6. PreparedStatement stmt=null;
  7. try {
  8. conn=JdbcUtil.getConnection();
  9. stmt=conn.prepareStatement(sql);
  10. for(int i=0;i<100000;i++){
  11. stmt.setString(1, "aa"+(i+1));
  12. stmt.addBatch();
  13. //每一百次清理一次
  14. if(i%100==0){
  15. stmt.executeBatch();
  16. stmt.clearBatch();
  17. }
  18. }
  19. int[] ii=stmt.executeBatch();
  20. } catch (Exception e) {
  21. // TODO Auto-generated catch block
  22. e.printStackTrace();
  23. }finally{
  24. JdbcUtil.release(null, stmt, conn);
  25. }
  26. }

4、同时执行带参的和无参的

  1. public class BatchDemo3 {
  2. public void test() throws Exception {
  3. Connection conn = null;
  4. PreparedStatement stmt = null;
  5. try {
  6. conn = JdbcUtil.getConnection();
  7. String sql = "insert into t3(name) values (?)";
  8. PreparedStatement pstmt = conn.prepareStatement(sql);
  9. pstmt.setString(1, "ccc");
  10. pstmt.addBatch(); // 添加一次预定义参数//添加一次静态sql
  11. pstmt.addBatch("update t3 set name = 'aa5' where name='aa4'");// 批量执行预定义
  12. pstmt.executeBatch();
  13. } catch (SQLException e) {
  14. e.printStackTrace();
  15. } finally {
  16. JdbcUtil.release(null, stmt, conn);
  17. }
  18. }
  19. }
  1.  

二、事务的处理部分

MySQL引擎:InnoDB(支持事务的)

MySQL默认自动提交事务的。每条语句都处在单独的事务之中。而oracle是也好手动提交事务的。

手工控制事务

开启事务:starttransaction|begin

提交事务:commit

回滚事务:rollback

对于事务,最经典的就数转账的操作ill,要么同时成功,要么同时失败,不存在中间态。

首先我们可以新来建一个账号表:

create table account(id int primary key auto_increment,name varchar(40),money
float )character set utf8 collate utf8_general_ci;

然后可以插入几条数据insert into account(name,money) values('a',1000);insert into account(name,money)
values('b',1000);insert into account(name,money) values('c',1000);

接下来编写代码,因为事务的特性,所以我们主要是加了这两段代码:setAutoCommit(false)和commit(),当发生问题的时候就需要rollback()数据回滚。

  1. @Test
  2. public void test1(){
  3. Connection conn=null;
  4. PreparedStatement stmt=null;
  5. try {
  6. conn=JdbcUtil.getConnection();
  7. //设置隔离级别
  8. conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
  9. conn.setAutoCommit(false); //相当于start transaction | begin 开启事务
  10.  
  11. String sql1="update account set money=money-100 where name='a'";
  12. String sql2="update account set money=money+100 where name='c'";
  13. stmt=conn.prepareStatement(sql1);
  14. stmt.executeUpdate();
  15. stmt=conn.prepareStatement(sql2);
  16. stmt.executeUpdate();
  17. conn.commit();
  18. } catch (SQLException e) {
  19. if(conn!=null){
  20. try {
  21. conn.rollback();
  22. } catch (SQLException e1) {
  23. e1.printStackTrace();
  24. }
  25. }
  26. e.printStackTrace();
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }finally{
  30. JdbcUtil.release(null, stmt, conn);
  31. }

记得在代码中需要添加两个stmt.executeUpdate()哦!

执行完之后再到数据库中查询就可以清晰的看到结果啦!

对了,我抽取的这个基类的代码是:

  1. public class JdbcUtil {
  2. private static String driverClass;
  3. private static String url;
  4. private static String user;
  5. private static String password;
  6. static{
  7. ResourceBundle rb = ResourceBundle.getBundle("dbinfo");
  8. driverClass = rb.getString("driverClass");
  9. url = rb.getString("url");
  10. user = rb.getString("user");
  11. password = rb.getString("password");
  12. try {
  13. Class.forName(driverClass);
  14. } catch (ClassNotFoundException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. public static Connection getConnection() throws Exception{
  19. Connection conn = DriverManager.getConnection(url,user,password);
  20. return conn;
  21. }
  22. public static void release(ResultSet rs,Statement stmt,Connection conn){
  23. if(rs!=null){
  24. try {
  25. rs.close();
  26. } catch (SQLException e) {
  27. e.printStackTrace();
  28. }
  29. rs = null;
  30. }
  31. if(stmt!=null){
  32. try {
  33. stmt.close();
  34. } catch (SQLException e) {
  35. e.printStackTrace();
  36. }
  37. stmt = null;
  38. }
  39. if(conn!=null){
  40. try {
  41. conn.close();
  42. } catch (SQLException e) {
  43. e.printStackTrace();
  44. }
  45. conn = null;
  46. }
  47. }
  48. }

最后来回顾一下事务的特性吧!

l  A:原子性:是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

l  C:一致性:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。举例:转账,a账户1000块,b账户1000块,a给b转账后加起来应该是2000块。

l  I:隔离性:多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

l  D:持久性:一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

三、事务的隔离

不考虑事务的隔离级别,会出现什么情况:

l  脏读(Dirty Read):一个线程中的事务读到了另外一个线程中事务中未提交的数据。

l  不可重复读(UnRepeatable Read):一个线程中的事务读到了另外一个线程中提交的事务的数据(UPDATE数据)。

l  虚读:一个线程中的事务读到了另外一个线程事务中INSERT的数据。

数据库通过设置事务的隔离级别防止以上情况的发生的:

l  1:READUNCOMMITTED:脏读、不可重复读、虚读都有可能发生。

l  2:READCOMMITTED:避免脏读,不可重复读、虚读都有可能发生。(Oracle默认的)

l  4:REPEATABLEREAD:避免脏读、不可重复读,虚读有可能发生。(MySQL默认)

l  8:SERIALIZABLE:避免脏读、不可重复读、虚读的发生。

级别越高,性能越低,数据越安全。

MySQL:(必须用在事务之中)

设置隔离级别必须在开启事务之前。

查看当前事务的隔离级别:SELECT@@TX_ISOLATION;

更改当前事务的隔离级别:SETTRANSACTION ISOLATION LEVEL 四个级别之一;

最后再提一下这个数据库中存放和读取文件和图片吧!

我们可以新建两个表:主要是文件的存放和图片存放读取操作使用的

create table t1(

  id int primary key auto_increment,

  content longtext

  );

 

create table t2(

id int primary key auto_increment,

  content longblob

  );

  1. // 读取文本文件,即把文件存放到数据库中
  2. public void testWrite(){
  3. Connection con=null;
  4. PreparedStatement pstmt=null;
  5.  
  6. try{
  7. con=JdbcUtil.getConnection();
  8. String sql="insert into t1(content) values(?)";
  9. pstmt=con.prepareStatement(sql);
  10.  
  11. File file=new File("src/demo1.txt");
  12. Reader reader=new FileReader(file);
  13.  
  14. pstmt.setCharacterStream(1, reader, (int)file.length());
  15. pstmt.executeUpdate();
  16.  
  17. }catch(Exception e){
  18. e.printStackTrace();
  19. }finally{
  20. JdbcUtil.release(null, pstmt, con);
  21. }
  22. }
  23.  
  24. <span style="white-space:pre"> </span>//将文件文件从数据库中读取出来,
  25. @Test
  26. public void testReader(){
  27. Connection con=null;
  28. PreparedStatement pstmt=null;
  29. ResultSet rs=null;
  30. try{
  31. con=JdbcUtil.getConnection();
  32. String sql="select *from t1 where id=1" ;
  33. pstmt=con.prepareStatement(sql);
  34. rs=pstmt.executeQuery();
  35. if(rs.next()){
  36. Reader r=rs.getCharacterStream("content");
  37.  
  38. Writer w=new FileWriter("d:/1.txt");
  39. char buf[] =new char[1024];
  40. int len=-1;
  41. while((len=r.read(buf))!=-1){
  42. w.write(buf,0,len);
  43. }
  44. r.close();
  45. w.close();
  46. }
  47.  
  48. }catch(Exception e){
  49. e.printStackTrace();
  50. }finally{
  51. JdbcUtil.release(null, pstmt, con);
  52. }
  53. }
  54. //将图片信息存放到数据库中,以二进制流的方式读取写入等
  55. @Test
  56. public void testWrite2(){
  57. Connection con=null;
  58. PreparedStatement pstmt=null;
  59.  
  60. try{
  61. con=JdbcUtil.getConnection();
  62. String sql="insert into t2(content) values(?)";
  63. pstmt=con.prepareStatement(sql);
  64.  
  65. InputStream in=new FileInputStream("src/1.jpg");
  66.  
  67. pstmt.setBinaryStream(1, in, in.available());
  68. pstmt.executeUpdate();
  69.  
  70. }catch(Exception e){
  71. e.printStackTrace();
  72. }finally{
  73. JdbcUtil.release(null, pstmt, con);
  74. }
  75. }
  76.  
  77. //将图片从数据库中读出来
  78. @Test
  79. public void testReader2(){
  80. Connection con=null;
  81. PreparedStatement pstmt=null;
  82. ResultSet rs=null;
  83. try{
  84. con=JdbcUtil.getConnection();
  85. String sql="select *from t2 where id=1" ;
  86. pstmt=con.prepareStatement(sql);
  87. rs=pstmt.executeQuery();
  88. if(rs.next()){
  89. InputStream in=rs.getBinaryStream("content");
  90. OutputStream out=new FileOutputStream("d:/1.jpg");
  91. byte buf[] =new byte[1024];
  92. int len=-1;
  93. while((len=in.read(buf))!=-1){
  94. out.write(buf,0,len);
  95. }
  96. in.close();
  97. out.close();
  98. }
  99.  
  100. }catch(Exception e){
  101. e.printStackTrace();
  102. }finally{
  103. JdbcUtil.release(null, pstmt, con);
  104. }
  105. }

SQL批处理与事务控制的更多相关文章

  1. SQL语言 之 事务控制

    一.概述 事务是一些数据库操作的集合,这些操作由一组相关的SQL语句组成(只能是 DML 语句),它们是一个有机的整体,要么全部成功执行,要么全部不执行.事务时数据库并发控制和恢复技术的基本单位. 事 ...

  2. 事务控制及try catch

    一.事务控制 BEGIN TRY BEGIN TRAN; DECLARE @aaa NVARCHAR(MAX); SET @aaa = 9 / 0; COMMIT TRAN;END TRYBEGIN ...

  3. PL/SQL批处理语句(二)FORALL

    PL/SQL批处理语句(二)FORALL 我们知道PL/SQL程序中运行SQL语句是存在开销的,因为SQL语句是要提交给SQL引擎处理,这种在PL/SQL引擎和SQL引擎之间的控制转移叫做上下文却换, ...

  4. SQL Server提高事务复制效率优化(一)总体概述

      随着公司业务的发展,数据量增长迅速,在解决Scale Out的同时,还要考虑到主从的复制延迟问题,尽量降到1s以内满足线上业务,如果不调整,SQL Server默认的配置可能平均要3s左右.生产的 ...

  5. PHP mysqli 扩展库(面向对象/数据库操作封装/事务控制/预编译)

    1.和mysql扩展库的区别: (1   安全性.稳定性更高 (2  提供了面向对象和面向过程两种风格 2.php.ini  中的  extension=php_mysqli.dll 解除封印 3.面 ...

  6. SQL SERVER 分布式事务(DTC)

    BEGIN DISTRIBUTED TRANSACTION指定一个由 Microsoft 分布式事务处理协调器 (MS DTC) 管理的 Transact-SQL 分布式事务的起始. 语法BEGIN ...

  7. oracle-SQL语言基础-事务控制命令命令

    事务控制命令命令 COMMITROLLBACKSAVEPOINTSET TRANSACTION 当第一条可执行的SQL语句开始执行,数据库事务就开始.随着下面任一事件发生,数据库事务结束:执行COMM ...

  8. DATASNAP多表提交之事务控制之通用方法

    ERP系统的单据,总是些主从表结构,有一个主表,N个子表,子表又有子表,形成N层,单据数据提交时,主从表数据都要提交,为了保证数据的完整性,必须提供事务控制,要么都提交成功,有一个提交失败所有的提交都 ...

  9. JDBC事务控制管理

    1.事务 (1)事务的概念 事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功. 例如:A——B转帐,对应于如下两条sql语句 update account set mone ...

随机推荐

  1. iOS10 越狱, openSSH

    iOS 10 已经可以越狱, 不过比较蛋疼的是非完美越狱,每次重启都要从新越狱. 感兴趣的同学可以尝试一下,本人使用同步推上的教程,亲测可用. 越狱完后想安装OpenSSH, 在Cydia上搜索安装, ...

  2. javascript 错误处理和堆栈追踪浅析

    合理地处理堆栈信息能使你清除无用的数据, 而只专注于有用的数据. 同时, 当更好地理解 Errors 对象及其相关属性之后, 能有助于你更充分地利用 Errors. (函数的)调用栈是怎么工作的 在谈 ...

  3. java工厂设计模式初步

    没有利用反射机制定义的简单工厂类 interface Fruit{ public void eat(); } class Apple implements Fruit{ public void eat ...

  4. [LeetCode] Remove Comments 移除注释

    Given a C++ program, remove comments from it. The program source is an array where source[i] is the ...

  5. Python 爬取猫眼电影最受期待榜

     主要爬取猫眼电影最受期待榜的电影排名.图片链接.名称.主演.上映时间. 思路:1.定义一个获取网页源代码的函数: 2.定义一个解析网页源代码的函数: 3.定义一个将解析的数据保存为本地文件的函数: ...

  6. ●POJ 1509 Glass Beads

    题链: http://poj.org/problem?id=1509 题解: 给出一个字符串,有一个操作:把首字符放到末尾,形成新的串.求任意次操作后,字典序最小的串的首字母在原串中的位置.(这就是最 ...

  7. bzoj 4974: 字符串大师

    Description 一个串T是S的循环节,当且仅当存在正整数k,使得S是T^k(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节 .给定一个长度为n的仅由小写字符构成的字符串S,请 ...

  8. poj 2886 线段树+反素数

    Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 12744   Acc ...

  9. C# 导入excel报错 :不是预期外部表

    错误原因:由于Excel 97-2003的连接格式与Excel 2010 的 不同造成. 解决方案1: 很多人换了2010后,问的最多的问题之一是2003里最经典的ADO中的“provider=Mic ...

  10. 使用PowerPoint

    制作PPT在我们的学习生活中非常常见,PPT也就是演示文稿,平时我们在别人演示和讲解一些内容时都需要用到PPT.PPT可以在电脑上进行放映,看上去就好像一张一张的图片,但与图片不同的是它可以进行编辑. ...