SQL批处理与事务控制
今天我想要分享的是关于数据库的批处理与事务的控制。批处理对于项目的实际应用有非常大的具体意义。
一、批处理部分
首先我们新建一个表:
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批处理与事务控制的更多相关文章
- SQL语言 之 事务控制
一.概述 事务是一些数据库操作的集合,这些操作由一组相关的SQL语句组成(只能是 DML 语句),它们是一个有机的整体,要么全部成功执行,要么全部不执行.事务时数据库并发控制和恢复技术的基本单位. 事 ...
- 事务控制及try catch
一.事务控制 BEGIN TRY BEGIN TRAN; DECLARE @aaa NVARCHAR(MAX); SET @aaa = 9 / 0; COMMIT TRAN;END TRYBEGIN ...
- PL/SQL批处理语句(二)FORALL
PL/SQL批处理语句(二)FORALL 我们知道PL/SQL程序中运行SQL语句是存在开销的,因为SQL语句是要提交给SQL引擎处理,这种在PL/SQL引擎和SQL引擎之间的控制转移叫做上下文却换, ...
- SQL Server提高事务复制效率优化(一)总体概述
随着公司业务的发展,数据量增长迅速,在解决Scale Out的同时,还要考虑到主从的复制延迟问题,尽量降到1s以内满足线上业务,如果不调整,SQL Server默认的配置可能平均要3s左右.生产的 ...
- PHP mysqli 扩展库(面向对象/数据库操作封装/事务控制/预编译)
1.和mysql扩展库的区别: (1 安全性.稳定性更高 (2 提供了面向对象和面向过程两种风格 2.php.ini 中的 extension=php_mysqli.dll 解除封印 3.面 ...
- SQL SERVER 分布式事务(DTC)
BEGIN DISTRIBUTED TRANSACTION指定一个由 Microsoft 分布式事务处理协调器 (MS DTC) 管理的 Transact-SQL 分布式事务的起始. 语法BEGIN ...
- oracle-SQL语言基础-事务控制命令命令
事务控制命令命令 COMMITROLLBACKSAVEPOINTSET TRANSACTION 当第一条可执行的SQL语句开始执行,数据库事务就开始.随着下面任一事件发生,数据库事务结束:执行COMM ...
- DATASNAP多表提交之事务控制之通用方法
ERP系统的单据,总是些主从表结构,有一个主表,N个子表,子表又有子表,形成N层,单据数据提交时,主从表数据都要提交,为了保证数据的完整性,必须提供事务控制,要么都提交成功,有一个提交失败所有的提交都 ...
- JDBC事务控制管理
1.事务 (1)事务的概念 事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功. 例如:A——B转帐,对应于如下两条sql语句 update account set mone ...
随机推荐
- iOS10 越狱, openSSH
iOS 10 已经可以越狱, 不过比较蛋疼的是非完美越狱,每次重启都要从新越狱. 感兴趣的同学可以尝试一下,本人使用同步推上的教程,亲测可用. 越狱完后想安装OpenSSH, 在Cydia上搜索安装, ...
- javascript 错误处理和堆栈追踪浅析
合理地处理堆栈信息能使你清除无用的数据, 而只专注于有用的数据. 同时, 当更好地理解 Errors 对象及其相关属性之后, 能有助于你更充分地利用 Errors. (函数的)调用栈是怎么工作的 在谈 ...
- java工厂设计模式初步
没有利用反射机制定义的简单工厂类 interface Fruit{ public void eat(); } class Apple implements Fruit{ public void eat ...
- [LeetCode] Remove Comments 移除注释
Given a C++ program, remove comments from it. The program source is an array where source[i] is the ...
- Python 爬取猫眼电影最受期待榜
主要爬取猫眼电影最受期待榜的电影排名.图片链接.名称.主演.上映时间. 思路:1.定义一个获取网页源代码的函数: 2.定义一个解析网页源代码的函数: 3.定义一个将解析的数据保存为本地文件的函数: ...
- ●POJ 1509 Glass Beads
题链: http://poj.org/problem?id=1509 题解: 给出一个字符串,有一个操作:把首字符放到末尾,形成新的串.求任意次操作后,字典序最小的串的首字母在原串中的位置.(这就是最 ...
- bzoj 4974: 字符串大师
Description 一个串T是S的循环节,当且仅当存在正整数k,使得S是T^k(即T重复k次)的前缀,比如abcd是abcdabcdab的循环节 .给定一个长度为n的仅由小写字符构成的字符串S,请 ...
- poj 2886 线段树+反素数
Who Gets the Most Candies? Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 12744 Acc ...
- C# 导入excel报错 :不是预期外部表
错误原因:由于Excel 97-2003的连接格式与Excel 2010 的 不同造成. 解决方案1: 很多人换了2010后,问的最多的问题之一是2003里最经典的ADO中的“provider=Mic ...
- 使用PowerPoint
制作PPT在我们的学习生活中非常常见,PPT也就是演示文稿,平时我们在别人演示和讲解一些内容时都需要用到PPT.PPT可以在电脑上进行放映,看上去就好像一张一张的图片,但与图片不同的是它可以进行编辑. ...