文档章节

SQL批处理与事务控制

sdksdk0
 sdksdk0
发布于 2016/06/14 13:15
字数 2041
阅读 2
收藏 0
点赞 0
评论 0

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

一、批处理部分

首先我们新建一个表:

 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);
		}
	}


本文转载自:http://blog.csdn.net/sdksdk0/article/details/51246550

共有 人打赏支持
sdksdk0
粉丝 1
博文 105
码字总数 73456
作品 0
衡阳
程序员
JDBC 大数据集分页 ,大数据读写及事务的隔离级别

一、大数据集的分页 1、内存分页:将数据全部取出来放到List中,然后再进行分页。(不可取的) 2、数据库层分页:按照页码从数据查询。 MySQL:Select from table limit M,N M:开始记录的索...

长平狐
2012/09/03
238
0
java基础(jdbc下)

1.批处理 如果插入2000条记录,但现在使用sql缓存区,一次发送多条sql到数据库服务器执行。这种做法就叫 做批处理。 jdbc的批处理: Statement批处理: voidaddBatch(String sql) 添加sql到缓...

给我妖刀
2017/06/15
0
0
无法获得数据库'model'上的排他锁 解决办法

今天在编写建库工具的时候遇到排他锁问题,数据库建立失败,从百度中看到了,想与大家分享. 解决方法: 在查询分析器中运行如下代码即可: declare @sql varchar(100) while 1=1 begin select t...

Himma
2013/01/02
0
0
需要我们了解的SQL Server阻塞原因与解决方法 - sym_cn

这里通过连接在sysprocesses里字段值的组合来分析阻塞源头,可以把阻塞分为以下5种常见的类型(见表)。waittype,open_tran,status,都是sysprocesses里的值,“自我修复?”列的意思,就是指阻...

鱼煎
2016/05/07
43
0
JDBC中的事务管理------Transaction

数据库的事务就是将任意多个SQL语句看做一个整体,只有这些SQL语句都成功执行,DBMS才会保存这些SQL语句对数据库的修改(事务提交)。否则,数据库将恢复到执行SQL语句之前的状态(事务回滚)...

一别经年
2014/04/23
0
0
Mybatis3.3.x技术内幕(四):五鼠闹东京之执行器Executor设计原本

在上一篇博文中,已经分析了Mybatis事务相关的内容,而今天的这篇博文,很多内容都是在方法method内部,与事务无关,所以,建议暂时忘记事务概念,避免搅扰。 Mybatis对数据库的操作,都将委...

祖大俊
2016/04/27
1K
2
Statement和PreparedStatement批量更新

优势:1.节省传递时间。 2.并发处理。 PreparedStatement: 1) addBatch()将一组参数添加到PreparedStatement对象内部。 2) executeBatch()将一批参数提交给数据库来执行,如果全部命令执行...

Zero零_度
2015/09/11
105
0
3.Spark Streaming:与Storm的对比分析

Spark Streaming与Storm的优劣分析 事实上,Spark Streaming绝对谈不上比Storm优秀。这两个框架在实时计算领域中,都很优秀,只是擅长的细分场景并不相同。 Spark Streaming仅仅在吞吐量上比...

weixin_32265569
2017/11/14
0
0
JDBC操作批处理,也不报错,就是执行失败,该怎么找错呢?

我要进行大数据量的批处理插入操作 今天使用的是JDBC的批处理和事务 使用的是prepareStatement.executeBatch()的操作 我加入了5条sql,上面方法执行的结果是个int数组,但是我打印的结果数组...

蜡笔小新_
2014/04/12
221
2
转载 Bulk Insert命令详细

BULK INSERT以用户指定的格式复制一个数据文件至数据库表或视图中。 语法: BULK INSERT [ [ 'database_name'.][ 'owner' ].]{ 'table_name' FROM 'data_file' } WITH ( [ BATCHSIZE [ = bat......

sincoder
2012/12/12
0
2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Weblogic问题解决记录

问题:点击登录,页面刷新但是不进去管理界面。解决:删除cookies再登录。

wffger
25分钟前
0
0
RxJava2的错误处理方案

最近使用retrofit2 + rxKotlin2写接口访问,想尽量平铺代码,于是就想到当借口返回的状态码为「不成功」时(比如:code != 200),就连同网络错误一起,统一在onError方法中处理。想法总是好的...

猴亮屏
33分钟前
0
0
程序的调试信息

调试二进制程序时,经常要借助GDB工具,跟踪程序的执行流程,获取程序执行时变量的值,以发现问题所在。GDB能得到这些信息,是因为编译程序时,编译器保存了相应的信息。Linux下的可执行程序...

qlee
56分钟前
0
0
应用级缓存

缓存命中率 从缓存中读取数据的次数与总读取次数的比例,命中率越高越好 java缓存类型 堆缓存 guavaCache Ehcache3.x 没有序列化和反序列化 堆外缓存ehcache3.x 磁盘缓存 存储在磁盘上 分布式...

writeademo
今天
0
0
python爬虫日志(3)find(),find_all()函数

1.一般来说,为了找到BeautifulSoup对象内任何第一个标签入口,使用find()方法。 以上代码是一个生态金字塔的简单展示,为了找到第一生产者,第一消费者或第二消费者,可以使用Beautiful Sou...

茫羽行
今天
0
0
java:thread:顺序执行多条线程

实现方案: 1.调用线程的join方法:阻塞主线程 2.线程池 package com.java.thread.test;public class MyThread01 implements Runnable {@Overridepublic void run() {Syste...

人觉非常君
今天
0
0
ElasticSearch 重写IK分词器源码设置mysql热词更新词库

常用热词词库的配置方式 1.采用IK 内置词库 优点:部署方便,不用额外指定其他词库位置 缺点:分词单一化,不能指定想分词的词条 2.IK 外置静态词库 优点:部署相对方便,可以通过编辑指定文...

键走偏锋
今天
19
0
Git 2.18版本发布:支持Git协议v2,提升性能

Git 2.18版本发布:支持Git协议v2,提升性能Git 2.18版本发布:支持Git协议v2,提升性能 新版本协议的主要驱动力是使 Git 服务端能够对各种 ref(分支与 tag)进行过滤操作。 这就意味着,G...

linux-tao
今天
0
0
python浏览器自动化测试库【2018/7/22-更新】

64位py2.7版本 更新 document_GetResources 枚举页面资源 document_GetresourceText 获取指定url的内容 包括页面图片 下载地址下载地址 密码:upr47x...

开飞色
今天
44
0
关于DCL双重锁失效及解决方案

关于DCL双重锁失效及解决方案 Double Check Lock (DCL)实现单例 DCL 方式实现单例的优点是既能够在需要时才初始化单例,又能够保证线程安全,且单例对象初始化后调用getInstance方法不进行...

DannyCoder
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部