1. 程式人生 > >jdbc批處理原理分析

jdbc批處理原理分析

 需要向資料庫傳送多條sql語句時, 為了提升執行效率, 可以考慮採用JDBC的批處理機制.

JDBC的批處理機制主要涉及Statement或PreparedStatement物件的以下方法:

|--addBatch(String sql) :Statement類的方法, 多次呼叫該方法可以將多條sql語句新增到Statement物件的命令列表中.

執行批處理時將一次性的把這些sql語句發送給資料庫進行處理.

|--addBatch(): PreparedStatement類的方法, 多次呼叫該方法可以將多條預編譯的sql語句新增到PreparedStatement物件的命令列表中.

執行批處理時將一次性的把這些sql語句

傳送給資料庫進行處理.

|--executeBatch():把Statement物件或PreparedStatement物件命令列表中的所有sql語句傳送給資料庫進行處理.

|--clearBatch():  清空當前sql命令列表.

/*
 * create table batch_test(id int primary key auto_increment, name varchar(40), age int);
 */
public class BatchTest {
	@Test
	public void statementBatch() {
		Connection conn = null;
		Statement st = null;
		String sql_1 = "insert into batch_test(name, age) values('coolxing', 24)";
		String sql_2 = "insert into batch_test(name, age) values('coolmin', 22)";
		String sql_3 = "insert into batch_test(name, age) values('yong', 21)";
		String sql_4 = "update batch_test set name='java' where id=1";

		try {
			conn = JdbcUtils.getConnection();
			st = conn.createStatement();
			st.addBatch(sql_1);
			st.addBatch(sql_2);
			st.addBatch(sql_3);
			st.addBatch(sql_4);
			st.executeBatch();
			st.clearBatch();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(null, st, conn);
		}
	}

	@Test
	public void preparedStatementBatch() {
		Connection conn = null;
		PreparedStatement st = null;
		String sql = "insert into batch_test(name, age) values(?, ?)";

		try {
			conn = JdbcUtils.getConnection();
			//通過只打開一個連線
			st = conn.prepareStatement(sql);
			for (int i = 0; i < 10002; i++) {
				st.setString(1, "coolxing_" + i);
				st.setInt(2, i);
				st.addBatch();
				// 需要防止Preparedstatement物件中的命令列表包含過多的待處理sql語句, 而造成outOfMemory錯誤
				if (i % 500 == 0) {
					st.executeBatch();
					st.clearBatch();
				}
			}
			// 將剩下的未處理命令傳送給資料庫
			st.executeBatch();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(null, st, conn);
		}
	}
}

總結: 採用Statement.addBatch(sql)方式實現批處理可以向資料庫傳送不同型別的sql語句, 但是這些sql語句沒有進行預編譯, 執行效率不高. 且需要列出每一個sql語句. 而PreparedStatement.addBatch()只能應用在型別相同引數不同的sql語句中, 此種形式的批處理經常用於在同一個表中批量插入資料, 或批量更新表的資料.

注意不要一次性向命令列表中新增數量過多的sql語句, 防止出現outOfMemory錯誤.

原理分析:

前期的程式碼在與資料庫進行通訊時,都是先建立連線,建立連線花費的成本是最高的,然後發一個SQL語句,執行完後就關閉了連線。還有一個問題是傳送的SQL語句都是通過網路傳送的,比起本地呼叫來說,網路傳輸的成本也是高很多的。如果要插入或者更新一批資料進資料庫,還是採用前期的方法,花費的時間會很多,給使用者的感受會很慢。但是如果採用批處理,則在兩個方便都會節約大部分成本,速度會更快。下面是批處理的示例程式碼:
      static void createBatch() throws SQLException {
          Connection conn = null;
          PreparedStatement ps = null;
          ResultSet rs = null;
          try {
              conn = JdbcUtils.getConnection();
              String sql = "insert into user(name,birthday, money) values (?, ?, ?) ";
              ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
              for (int i = 0; i < 100; i++) {
                  ps.setString(1, "batch name" + i);
                  ps.setDate(2, new Date(System.currentTimeMillis()));
                  ps.setFloat(3, 100f + i);
 
                  ps.addBatch();
              }
              int[] is = ps.executeBatch();
          } finally {
              JdbcUtils.free(rs, ps, conn);
          }
      }
    如果不用批處理語句打包,則需要呼叫以前的create方法一百次,完成一百次資料庫的連線和網路通訊。用批處理的方式,可以將100次插入打成一個包,然後一次性發給資料庫,資料庫執行完畢,返回結果。如果在兩種方法呼叫上加上時間,就能夠區分兩者的速度差距了。但是並不是說用了批處理就一定比不用批處理要快,這根資料的版本、驅動的版本等都有很大關係。所以實際要用的時候,應該在環境上先測試一下兩者的效果。