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

一、批处理部分

首先我们新建一个表:

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、混合多种语句的批量处理,可同时执行增删改:

@Test
public void test1(){
String sql1="insert into t3(name) values('aa1')";
String sql2="insert into t3(name) values('aa2')";
String sql3="insert into t3(name) values('aa3')";
String sql4="insert into t3(name) values('aa4')";
String sql5="insert into t3(name) values('aa5')";
String sql6="delete from t3 where name='aa1'";
String sql7="update t3 set name='bb1' where name='aa2'";
Connection conn=null;
Statement stmt=null;
try {
conn=JdbcUtil.getConnection();
stmt=conn.createStatement();
stmt.addBatch(sql1);
stmt.addBatch(sql2);
stmt.addBatch(sql3);
stmt.addBatch(sql4);
stmt.addBatch(sql5);
stmt.addBatch(sql6);
stmt.addBatch(sql7);
int[] ii=stmt.executeBatch();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JdbcUtil.release(null, stmt, conn);
}
}

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

//批量插入100条记录,数据迁移项目
@Test
public void test1(){
String sql="insert into t3(name) values(?)";
Connection conn=null;
PreparedStatement stmt=null; try {
conn=JdbcUtil.getConnection();
stmt=conn.prepareStatement(sql);
for(int i=0;i<100;i++){
stmt.setString(1, "aa"+(i+1));
stmt.addBatch();
}
int[] ii=stmt.executeBatch(); } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JdbcUtil.release(null, stmt, conn);
}
}

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

//批量插入100000条记录,数据迁移项目
@Test
public void test1(){
String sql="insert into t3(name) values(?)";
Connection conn=null;
PreparedStatement stmt=null;
try {
conn=JdbcUtil.getConnection();
stmt=conn.prepareStatement(sql);
for(int i=0;i<100000;i++){
stmt.setString(1, "aa"+(i+1));
stmt.addBatch();
//每一百次清理一次
if(i%100==0){
stmt.executeBatch();
stmt.clearBatch();
}
}
int[] ii=stmt.executeBatch();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JdbcUtil.release(null, stmt, conn);
}
}

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

public class BatchDemo3 {
public void test() throws Exception {
Connection conn = null;
PreparedStatement stmt = null;
try {
conn = JdbcUtil.getConnection();
String sql = "insert into t3(name) values (?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "ccc");
pstmt.addBatch(); // 添加一次预定义参数//添加一次静态sql
pstmt.addBatch("update t3 set name = 'aa5' where name='aa4'");// 批量执行预定义
pstmt.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.release(null, stmt, conn);
}
}
}

二、事务的处理部分

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()数据回滚。

@Test
public void test1(){
Connection conn=null;
PreparedStatement stmt=null;
try {
conn=JdbcUtil.getConnection();
//设置隔离级别
conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
conn.setAutoCommit(false); //相当于start transaction | begin 开启事务 String sql1="update account set money=money-100 where name='a'";
String sql2="update account set money=money+100 where name='c'";
stmt=conn.prepareStatement(sql1);
stmt.executeUpdate();
stmt=conn.prepareStatement(sql2);
stmt.executeUpdate();
conn.commit();
} catch (SQLException e) {
if(conn!=null){
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtil.release(null, stmt, conn);
}

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

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

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

public class JdbcUtil {
private static String driverClass;
private static String url;
private static String user;
private static String password;
static{
ResourceBundle rb = ResourceBundle.getBundle("dbinfo");
driverClass = rb.getString("driverClass");
url = rb.getString("url");
user = rb.getString("user");
password = rb.getString("password");
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws Exception{
Connection conn = DriverManager.getConnection(url,user,password);
return conn;
}
public static void release(ResultSet rs,Statement stmt,Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}

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

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

  );

             //  读取文本文件,即把文件存放到数据库中
public void testWrite(){
Connection con=null;
PreparedStatement pstmt=null; try{
con=JdbcUtil.getConnection();
String sql="insert into t1(content) values(?)";
pstmt=con.prepareStatement(sql); File file=new File("src/demo1.txt");
Reader reader=new FileReader(file); pstmt.setCharacterStream(1, reader, (int)file.length());
pstmt.executeUpdate(); }catch(Exception e){
e.printStackTrace();
}finally{
JdbcUtil.release(null, pstmt, con);
}
} <span style="white-space:pre"> </span>//将文件文件从数据库中读取出来,
@Test
public void testReader(){
Connection con=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try{
con=JdbcUtil.getConnection();
String sql="select *from t1 where id=1" ;
pstmt=con.prepareStatement(sql);
rs=pstmt.executeQuery();
if(rs.next()){
Reader r=rs.getCharacterStream("content"); Writer w=new FileWriter("d:/1.txt");
char buf[] =new char[1024];
int len=-1;
while((len=r.read(buf))!=-1){
w.write(buf,0,len);
}
r.close();
w.close();
} }catch(Exception e){
e.printStackTrace();
}finally{
JdbcUtil.release(null, pstmt, con);
}
}
//将图片信息存放到数据库中,以二进制流的方式读取写入等
@Test
public void testWrite2(){
Connection con=null;
PreparedStatement pstmt=null; try{
con=JdbcUtil.getConnection();
String sql="insert into t2(content) values(?)";
pstmt=con.prepareStatement(sql); InputStream in=new FileInputStream("src/1.jpg"); pstmt.setBinaryStream(1, in, in.available());
pstmt.executeUpdate(); }catch(Exception e){
e.printStackTrace();
}finally{
JdbcUtil.release(null, pstmt, con);
}
} //将图片从数据库中读出来
@Test
public void testReader2(){
Connection con=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try{
con=JdbcUtil.getConnection();
String sql="select *from t2 where id=1" ;
pstmt=con.prepareStatement(sql);
rs=pstmt.executeQuery();
if(rs.next()){
InputStream in=rs.getBinaryStream("content");
OutputStream out=new FileOutputStream("d:/1.jpg");
byte buf[] =new byte[1024];
int len=-1;
while((len=in.read(buf))!=-1){
out.write(buf,0,len);
}
in.close();
out.close();
} }catch(Exception e){
e.printStackTrace();
}finally{
JdbcUtil.release(null, pstmt, con);
}
}

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. C#之Message(转)

    一.消息概述 Windows下应用程序的执行是通过消息驱动的.消息是整个应用程序的工作引擎,我们需要理解掌握我们使用的编程语言是如何封装消息的原理. 什么是消息(Message) 消息就是通知和命令. ...

  2. AutoCAD常用操作命令

    前言 最近工作需要使用AutoCAD画图,在这里记一下用到的一些常用操作,都是一些很基础的操作,希望对大家有帮助. 修剪 如果两条直线相交,你需要剪掉多余的部分,可以用修剪命令TR. 我们先画两条相交 ...

  3. drupal8主题安装

    一.在网站上下载一个主题包 在 https://www.drupal.org/project/bootstrap 下下载的bootstrop主题 二.下载之后,解压放在d8game/themes目录下 ...

  4. 2018年Java后端面试经历

    楼主16年毕业,16年三月份进入上一家公司到今年3月底,所以这是一份两年工作经验面经分享. 都说金三银四,往些年都是听着过没啥特别的感觉.今年自己倒是确确实实体验了一把银四,从3月26裸辞到4月17号 ...

  5. [NOI 2010]能量采集

    Description 题库链接 给你一个 \(n\times m\) 的坐标轴.对于坐标轴的每一个正整数整点 \((x,y)\) 其对答案产生的贡献为 \(2k+1\) ,其中 \(k\) 表示这个 ...

  6. hihocoder 1035 : 自驾旅行 III

    描述 给定一棵含有 n 个结点的树,结点从 1 标号.你从 1 号结点驾车出发,希望遍历一些关键结点(访问到就好,不需要按照这些关键结点的输入顺序).每条边有两个权值,c0, c1 分别表示步行和驾车 ...

  7. 【Toll!Revisited(uva 10537)】

    题目来源:蓝皮书P331 ·这道题使得我们更加深刻的去理解Dijkstra!       在做惯了if(dis[u]+w<dis[v])的普通最短路后,这道选择路径方案不是简单的比大小的题横在了 ...

  8. SqlServer 跨网段跨服务器复制

    注意:被同步的表必须有主键,否则无法同步.对数据库进行操作时需要登录服务器,在服务器本地进行操作,远程对数据库进行操作不能完成所有的步骤 准备工作: 1.将发布数据库完整备份到订阅服务器上,并在订阅服 ...

  9. css坑了我一下下之line-height

    文字上下有间隙该怎么解决 一次很搞笑的真实经历. 我:文字上下有间隙该怎么解决? 大佬A:什么意思? 大佬B:字体的原因吧. 大佬B:MD 谁看那么细. 我:跟别的图片对不齐. 真·大佬:这个我知道. ...

  10. PTA 邻接矩阵存储图的深度优先遍历

    6-1 邻接矩阵存储图的深度优先遍历(20 分) 试实现邻接矩阵存储图的深度优先遍历. 函数接口定义: void DFS( MGraph Graph, Vertex V, void (*Visit)( ...