能不能在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语句的几种方法,供大家参考.对于脚本输出的 ...
随机推荐
- 十七、Java中数组常见的几种排序方法!
转载自:https://www.cnblogs.com/bekeyuan123/p/6891875.html 数组的定义: // 3种定义方式 int[] arr = new int[5]; int[ ...
- 网址导航18C
[名站] 百度 网易 腾讯 新华 中新 凤凰 [新闻] 联合早报 南方周末 澎湃新闻 [系统] 宋永志 蒲公英 技术员 装机网 系统之家 [软件] 星愿浏览器 微PE [分享] zd423 殁飘遥 ...
- 512MB内存VPS服务器安装宝塔WEB客户端建站 - 环境部署篇
原本以为我们很多网友用VPS搭建网站不会用WEB面板,而采用一键包或者自己部署编译环境,但是最后发现其实目前我们使用WEB面板的还是挺多的,无论是免费还是付费的都有不少人使用.比如当初一直免费的AMH ...
- jquery取每个li元素下的第三个a元素
$('li').find('a:eq(2)');
- jquery瀑布流排列样式代码
<!DOCTYPE html><html><head lang="en"> <meta charset="gb2312" ...
- hibernate中怎样配置两个联合属性为唯一约束(非联合主键)
Annotation中配置: @Table元素包括了一个schema和一个catalog属性,如果需要可以指定相应的值. 结合使用@UniqueConstraint注解可以定义表的唯一约束(uniqu ...
- nginx简介与配置
nginx简介 nginx(发音同engine x)是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like协议下发行. nginx由俄罗斯的程序 ...
- 《Miracle-House团队》项目需求分析改进
(一)团队项目需求分析改进 一.<西小餐项目需求规格说明书>的不足 通过老师和其他同学的指正和建议,我们发现上次的需求规格说明书存在以下不足: 1.需求规格文档不够完整和规范: 2.系统设 ...
- 【Selenium】【BugList11】启动selenium server报错:Unsupported major.minor version 52.0
[环境信息] python:3.6.5 平台:win7 selenium:3.11.0 selenium server:selenium-server-standalone-3.11.0.jar jd ...
- AlphaGo原理浅析
一.PolicyNetwork(走棋网络) 首先来讲一下走棋网络.我们都知道,围棋的棋盘上有19条纵横交错的线总共构成361个交叉点,状态空间非常大,是不可能用暴力穷举的方式来模拟下棋的.但是我们可以 ...