能不能在FOR循环中执行SQL?
JDBC最基础的For循环处理SQL的方式 以及执行时间
package javaee.net.cn.jdbc;
import java.sql.*;
public class TestTransaction { public static void main(String[] args) {
Long startTime = System.currentTimeMillis();
Connection conn = null;
PreparedStatement stmt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager
.getConnection("jdbc:mysql://192.168.1.105:3306/sunkun?user=root&password=********");
String sql = "insert into user (name) values (?)";
stmt = conn.prepareStatement(sql);
for(int i=0;i<1000;i++){
stmt.setString(1,"test"+i);
stmt.execute();
}
stmt.executeBatch();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch(SQLException e) {
e.printStackTrace();
try {
if(conn != null)
{
conn.rollback();
conn.setAutoCommit(true);
}
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
try {
if(stmt != null)
stmt.close();
if(conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
Long endTime = System.currentTimeMillis();
Long time = endTime-startTime;
System.err.println("一千条数据所需要的时间"+time);//一千条数据所需要的时间48262
} }
for循环一千条SQL时间是48262ms
设置setAutoCommit(false) FOR循环执行
package javaee.net.cn.jdbc;
import java.sql.*;
public class TestTransaction { public static void main(String[] args) {
Long startTime = System.currentTimeMillis();
Connection conn = null;
PreparedStatement stmt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager
.getConnection("jdbc:mysql://192.168.1.105:3306/sunkun?user=root&password=*******");
String sql = "insert into user (name) values (?)";
stmt = conn.prepareStatement(sql);
conn.setAutoCommit(false);
for(int i=0;i<1000;i++){
stmt.setString(1,"test"+i);
stmt.execute();
}
conn.commit();
conn.setAutoCommit(true);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch(SQLException e) {
e.printStackTrace();
try {
if(conn != null)
{
conn.rollback();
conn.setAutoCommit(true);
}
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
try {
if(stmt != null)
stmt.close();
if(conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
Long endTime = System.currentTimeMillis();
Long time = endTime-startTime;
System.err.println("一千条数据所需要的时间"+time);//一千条数据所需要的时间578
} }
578ms 厉害吧 同样是for循环执行SQL 效率提高了百倍
setAutoCommit介绍
void setAutoCommit(boolean autoCommit)
throws SQLException
- 将此连接的自动提交模式设置为给定状态。如果连接处于自动提交模式下,则它的所有 SQL 语句将被执行并作为单个事务提交。否则,它的 SQL 语句将聚集到事务中,直到调用
commit方法或rollback方法为止。默认情况下,新连接处于自动提交模式。提交发生在语句完成时。语句完成的时间取决于 SQL 语句的类型:
- 对于 DML 语句(比如 Insert、Update 或 Delete)和 DDL 语句,语句在执行完毕时完成。
- 对于 Select 语句,语句在关联结果集关闭时完成。
- 对于
CallableStatement对象或者返回多个结果的语句,语句在所有关联结果集关闭并且已获得所有更新计数和输出参数时完成。
注:如果在事务和自动提交模式更改期间调用此方法,则提交该事务。如果调用
setAutoCommit而自动提交模式未更改,则该调用无操作(no-op)。 -
-
- 参数:
autoCommit- 为true表示启用自动提交模式;为false表示禁用自动提交模式- 抛出:
SQLException- 如果发生数据库访问错误,在参与分布式事务的同时调用 setAutoCommit(true),或者在关闭的连接上调用此方法- 另请参见:
getAutoCommit()
测试批处理一千条数据的时间
package javaee.net.cn.jdbc;
import java.sql.*;
public class TestTransaction { public static void main(String[] args) {
Long startTime = System.currentTimeMillis();
Connection conn = null;
PreparedStatement stmt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager
.getConnection("jdbc:mysql://192.168.1.105:3306/sunkun?user=root&password=******");
String sql = "insert into user (name) values (?)";
stmt = conn.prepareStatement(sql);
conn.setAutoCommit(false);
for(int i=0;i<1000;i++){
stmt.setString(1,"test"+i);
stmt.addBatch();
}
stmt.executeBatch();
conn.commit();
conn.setAutoCommit(true);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch(SQLException e) {
e.printStackTrace();
try {
if(conn != null)
{
conn.rollback();
conn.setAutoCommit(true);
}
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
try {
if(stmt != null)
stmt.close();
if(conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
Long endTime = System.currentTimeMillis();
Long time = endTime-startTime;
System.err.println("一千条数据所需要的时间"+time);//一千条数据所需要的时间502
} }看到如果设置了批处理502 比for循环执行一千条SQL578快了一点(和网络延迟 GC有关 其实只要不让事物自动提交 for循环处理SQL和批处理的效率差不多)
实验Mybatis
不管什么dao框架 底层都是jdbc
工作中用的最多的是Mybatis
下面对Mybatis做一下For循环处理SQL的实验
@Test
public void testForDao(){
//获取配置在Spring中的SqlSessionFactory实例
SqlSessionFactory sqlSessionFactory =SpringContextHolder.getBean(SqlSessionFactory.class);
//
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
Long startTime = System.currentTimeMillis();
for(int i=0;i<1000;i++){
ClientClassify classify = new ClientClassify();
String name = "testFor_"+i;
classify.setClientClassify(name);
classify.setOwnerId(2154L);
classify.setCreateBy("kk6");
classify.setLastUpdateBy("kk6");
classify.setCreateDate(new Date());
classify.setLastUpdateDate(new Date());
classify.setClientType(ClientType.customer);
classify.setIsDel(false);
classify.setVersion(1);
classify.setDelDate(new Date());
sqlSession.insert("com.ydcfo.common.model.crm.ClientClassifyMapper.insert",classify);
}
sqlSession.flushStatements();
sqlSession.commit();
sqlSessionFactory.openSession(true);
Long endTime = System.currentTimeMillis();
System.err.println("1000条数据时间"+(endTime-startTime));
}下面直接说结论
sqlSessionFactory.openSession(ExecutorType.BATCH,false); 时间:47010
sqlSessionFactory.openSession(ExecutorType.SIMPLE,false); 时间:50357
sqlSessionFactory.openSession(ExecutorType.REUSE,false); 时间:50398
sqlSessionFactory.openSession(ExecutorType.BATCH,true); 时间:49178
在Mybatis中,我试图和JDBC一样 通过设置 不让事物自动提交,发现效率并没有提高
/**
* @author Clinton Begin
*/
public enum ExecutorType {
SIMPLE, REUSE, BATCH
}用 Mybatis BATCH的ExecutorType执行器,FOR循环执行SQL的效率一样很低
总结,在原始的JDBC中,我们可以通过设置AutoCommit来提高FOR循环中执行SQL的效率
但是在Mybatis中 这样行不通,至于原因,还未知(我估计是Mybatis内部优化不好)。
所以在工作中 Mybatis不能FOR循环执行SQL 一定要拼装成一个SQL(通过字符串拼接SQL)然后在执行(也就是Mybatis的批处理)
这是一篇介绍事物的文章 我觉得核心的一句话是where条件中用到的num 会收到其他未commit事物的影响 这也是乐观锁为什么可以防止并发的原因
补充:
经过测试发现, SqlSession openSession(ExecutorType execType, boolean autoCommit);
当第一个参数是ExecutorType.BATCH的时候 第二个参数是true还是false 每循环一次都不会落地到数据库
当第一个参数不是ExecutorType.BATCH的时候 第二个参数是true还是false 每循环一次都会落地到数据库 即使 还没有 sqlSession.commit() 我个人认为这是Mybatis的bug
不过这个细节不会影响我们日常的开发,因为事物都交给了Spring去处理。
能不能在FOR循环中执行SQL?的更多相关文章
- C#和Java中执行SQL文件脚本的代码(非常有用)
原文:C#和Java中执行SQL文件脚本的代码(非常有用) 我们在做程序的时候有事后会涉及到利用sql文件 直接执行,可是在sql文件中有很多注释,我们要一句一句的执行首先必须的得把sql文件解析 去 ...
- EF中执行sql语句,以及事务
EF to sql string sql = "select T_Task.BSID,T_Task.CloseDate,T_Task.CompleteDate,T_Task.CloseUse ...
- [转]在EntityFramework6中执行SQL语句
本文转自:http://www.cnblogs.com/wujingtao/p/5412329.html 在上一节中我介绍了如何使用EF6对数据库实现CRDU以及事务,我们没有写一句SQL就完成了所有 ...
- 在EntityFramework6中执行SQL语句
在EntityFramework6中执行SQL语句 在上一节中我介绍了如何使用EF6对数据库实现CRDU以及事务,我们没有写一句SQL就完成了所有操作.这一节我来介绍一下如何使用在EF6中执行SQL语 ...
- 在phpmyadmin中执行sql语句出现的错误:Unknown storage engine 'InnoDB'
在phpmyadmin中执行sql语句出现的错误:Unknown storage engine 'InnoDB' 解决方法:解决方法: 1.关闭MySQL数据库 2 ...
- SSIS中执行SQL任务组件参数传递的问题
原文:SSIS中执行SQL任务组件参数传递的问题 症状: 执行SQL任务,传递参数到子查询中,执行报错. 错误: 失败,错误如下:"无法从使用 sub-select 查询的 SQL 语句中派 ...
- .net(C#)在Access数据库中执行sql脚本
自己写的一个工具类,主要是业务场景的需要. 主要有两个功能: ①执行包含sql语句的字符串 ②执行包含sql语句的文件 调用方式 /// <summary> /// 执行sql语句 /// ...
- 在EF中执行SQL语句(转载)
在EF中执行SQL语句 你可能要问,我用EF不就为了避免写SQL吗?如果要写SQL我不如直接用ADO.NET得了.话虽然这么说没错,可有些时候使用EF操作数据还是有一些不方便,例如让你根据条件删除 ...
- Shell脚本中执行sql语句操作mysql的5种方法【转】
对于自动化运维,诸如备份恢复之类的,DBA经常需要将SQL语句封装到shell脚本.本文描述了在Linux环境下mysql数据库中,shell脚本下调用sql语句的几种方法,供大家参考.对于脚本输出的 ...
随机推荐
- SQL Server 2008 通过C# CLR 使用正则表达式
参考文章 MSSQLSERVER接入c#clr程序集,使c#函数变sql函数 正则表达式30分钟入门教程 SQL中采用Newtonsoft.Json处理json字符串 操作步骤 1.新建项目-> ...
- 十四、new Comparator<T>实现多重排序结果
1.编写实现类 package com.abcd; public class Person{ private String name; private int age; private int sal ...
- How to use BMW 35080 adapter with Yanhua Mini ACDP
I have a question about Yanhua Mini ACDP + module 4 BMW 35080 read and write: Can the 35080 adapter ...
- 《笨方法学Python》加分题16
基础部分 # 载入 sys.argv 模块,以获取脚本运行参数. from sys import argv # 将 argv 解包,并将脚本名赋值给变量 script :将参数赋值给变量 filena ...
- 博客七----tensorflow-gpu安装满满填坑
具体内容见我的开源中国教程:https://my.oschina.net/u/3770644/blog/3043073 因为编写习惯原因,我的大多数详细教程在开源中国中.有兴趣的大家打开连接就好 强调 ...
- Sqlite3数据库查看工具
SQLiteSpy 小巧便捷,免安装,占空间小. 推荐 http://www.softpedia.com/get/Internet/Servers/Database-Utils/SQLiteS ...
- Ubuntu16.04 安装Tensorflow1.7过程记录二:安装CUDA及Tensorflow
参考 How to install Tensorflow 1.7.0 using official pip package 其中的CUDNN应该改为7.05for CUDA9.0 后面安装的spyde ...
- 一些简单的ajax的特点,方法、属性。以及ajax的创建 请求
1.ajax的特点,基本原理,属性. ajax:页面的局部刷新 Asynchronous JavaScript And Xml JavaScript:更新局部的页面 XML:一般用于请求数据和响应数据 ...
- OvO
OvO 知乎 网易云 图书馆 B站 小众软件 360极速浏览器下载 开源下载工具 下载地址1 下载地址2 下载地址3
- ELK的文档搭建
一.安装elasticsearch 官网:https://www.elastic.co/guide/index.html https://www.elastic.co/guide/en/elastic ...