|-- Statement
-- PreparedStatement 子接口,建议使用,会对sql语句先进行编译再给数据库
PreparedStatement对象不仅包含了SQL语句,而且大多数情况下这个语句已经被预编译过,因而当其执行时,只需DBMS运行SQL语句,而不必先编译。
当你需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,当然也加快了访问数据库的速度。
批处理相关方法
void addBatch(String sql) 添加批处理
void clearBatch() 清空批处理
int[] executeBatch() 执行批处理
事务提交
con.setAutoCommit(false); 默认自动提交,在这里需要设置为false,手动提交
con.commit();
con.rollback();
3.常见问题
批量处理无法生效
1、rewriteBatchedStatements=true
10万条数据,耗时15秒
private String url = "jdbc:mysql://localhost:3306/test01";
private String user = "root";
private String password = "123456";
@Test
public void Test(){
Connection conn = null;
PreparedStatement pstm =null;
ResultSet rt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, user, password);
String sql = "INSERT INTO myTable values(?,?)";
pstm = conn.prepareStatement(sql);
Long startTime = System.currentTimeMillis();
for (int i = 1; i <= 100000; i++) {
pstm.setInt(1, i);
pstm.setInt(2, i);
pstm.executeUpdate();
}
Long endTime = System.currentTimeMillis();
System.out.println("用时:" + (endTime - startTime));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}finally{
if(pstm!=null){
try {
pstm.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
}
注意更改url = “jdbc:mysql://localhost:3306/test01?rewriteBatchedStatements=true”;
pstm.addBatch();代替pstm.executeUpdate();
最后批量操作pstm.executeBatch();
10万条数据,耗时4秒
private String url = "jdbc:mysql://localhost:3306/test01?rewriteBatchedStatements=true";
private String user = "root";
private String password = "123456";
@Test
public void Test() {
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, user, password);
String sql = "INSERT INTO myTable values(?,?)";
pstm = conn.prepareStatement(sql);
Long startTime = System.currentTimeMillis();
conn.setAutoCommit(false);
for (int i = 1; i <= 100000; i++) {
pstm.setInt(1, i);
pstm.setInt(2, i);
//1w提交一次
pstat.addBatch();
if (i % 10000 == 0) {
pstat.executeBatch();
pstat.clearBatch();
}
}
//提交余下部分
pstat.executeBatch(); //执行批处理
pstat.clearBatch(); //清空批处理
con.commit();
Long endTime = System.currentTimeMillis();
System.out.println("用时:" + (endTime - startTime));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
if (pstm != null) {
try {
pstm.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
}
insert into student ( )
values
(null,#{item.name},#{item.sex},#{item.address},#{item.telephone},#{item.tId})
参数解释:
collection:指定要遍历的集合;
表示传入过来的参数的数据类型。该参数为必选。要做 foreach 的对象,作为入参时,List 对象默认用 list 代替作为键,数组对象有 array 代替作为键,Map 对象没有默认的键
item:将当前遍历出的元素赋值给指定的变量,然后用#{变量名},就能取出变量的值,也就是当前遍历出的元素
separator:每个元素之间的分隔符, select * from Emp where id in(1,2,3)相当于1,2,3之间的","
Index:索引,遍历list的时候index就是索引,遍历map的时候index表示的就是map的key,item就是map的值.
特别注意:mysql默认接受sql的大小是1048576(1M),即第三种方式若数据量超过1M会报如下异常:(可通过调整MySQL安装目录下的my.ini文件中[mysqld]段的"max_allowed_packet = 1M")
Mybatis内置的ExecutorType有3种,默认的是simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;而batch模式重复使用已经预处理的语句,并且批量执行所有更新语句,显然batch性能将更优; 但batch模式也有自己的问题,比如在Insert操作时,在事务没有提交之前,是没有办法获取到自增的id,这在某型情形下是不符合业务要求的。