能不能在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语句的几种方法,供大家参考.对于脚本输出的 ...
随机推荐
- centos 下使用vscode 调试egg.js 注意事项
这两天在centos下,直接用vscode运行egg.js的例子.遇到个问题就是当安装了vscode-egg插件,会遇到一个现象.就是同样的代码,Windows下调试可以顺利进行,但是centos有时 ...
- NC 部署问题
1.was环境部署日志 IBM/WEBSPHERE/APPSERVER/PRORFILES/APPSRV01/LOGS/SERVER1/
- CAS SSO单点登录实例
1.因为是本地模拟sso环境,而sso的环境测试需要域名,所以需要虚拟几个域名出来,步骤如下: 2.进入目录C:\Windows\System32\drivers\etc 3.修改hosts文件 12 ...
- python3 安装 basemap 包(windows10)
下载 pyproj 和 basemap 的安装包 basemap 是具有专业标准的地图绘制工具,可以与 matplotlib 的一般绘图功能结合,在地图上绘制数据. basemap 文档:https: ...
- core的微服务相关
网关是ocelot consul 服务发现 配置中心apollo
- clientdataset新增append新增多条记录的时候报错 key valation
在前面加上两句 adsDetail.Active := False; adsDetail.CreateDataSet;
- 文件操作命令(replace)
Replace 命令: // 描述: 替换文件. // 语法: REPLACE [drive1:][path1]filename [drive2:][path2] [/A] [/P] [/R] [/W ...
- 关于Hbuild引用mui常用代码块以及部分控件.
MUI-最接近原生APP体验的高性能前端框架, 追求性能体验,是我们开始启动MUI项目的首要目标,轻量必然是重要特征: MUI不依赖任何第三方JS库,压缩后的JS和CSS文件仅有100+K和60+K, ...
- dubbo入门学习 二 RPC框架
rpc框架解释 谁能用通俗的语言解释一下什么是 RPC 框架? - 远程过程调用协议RPC(Remote Procedure Call Protocol) 首先了解什么叫RPC,为什么要RPC,RPC ...
- jmeter本身的一个bug记录
1.使用jmeter测http接口 2.断言接口返回的内容是否包含某串文本 3.结果:总是返回断言失败,即使接口返回的内容包含了该文本 接口返回的值为: {"code":" ...