jdbc知識介紹
|-- 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
代碼演示
1普通插入方式
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);
}
}
}
}
2使用batch
注意更改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);
}
}
}
}
Mybatis方式
<insert id="insertBatch" >
insert into student ( <include refid="Base_Column_List" /> )
values
<foreach collection="list" item="item" index="index" separator=",">
(null,#{item.name},#{item.sex},#{item.address},#{item.telephone},#{item.tId})
</foreach>
</insert>
參數解釋:
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.BATCH
Mybatis內置的ExecutorType有3種,默認的是simple,該模式下它爲每個語句的執行創建一個新的預處理語句,單條提交sql;而batch模式重複使用已經預處理的語句,並且批量執行所有更新語句,顯然batch性能將更優; 但batch模式也有自己的問題,比如在Insert操作時,在事務沒有提交之前,是沒有辦法獲取到自增的id,這在某型情形下是不符合業務要求的。