2010-09-14 40 views
1

我有一个像下面这样的查询,并想知道通过批处理PreparedStatement产生了什么样的SQL。在Java中,PreparedStatement如何为以下查询工作

INSERT INTO table1 (id, version, data) 
    VALUES (?, ?, ?) 
    ON DUPLICATE KEY UPDATE 
    table1.data = IF(table1.version > table2.version, table1.data, table2.data), 
    table1.version = IF(table1.version > table2.version, table1.version, table2.version) 

的问题是,将它解析这在批这整个SQL字符串的每一行的副本还是会做这样的事情:

INSERT INTO table1 (id, version, data) 
    VALUES (a1, b1, c1), (a2, b2, c2), (a3, b3, c3), ... 
    ON DUPLICATE KEY UPDATE 
    table1.data = IF(table1.version > table2.version, table1.data, table2.data), 
    table1.version = IF(table1.version > table2.version, table1.version, table2.version) 

如果不是,有什么表现这意味着什么,我如何编写它,以便我可以使用PreparedStatement对许多INSERT..UPDATE语句进行批处理,而不会导致性能损失?

回答

2

准备好的语句只是将放入的位置值插入到重复语句中,这样每次都不需要进行分析。所以你的第二种形式只需要N * 3个参数,并且不会给你任何准备好的语句提高速度。对于要使用addTobatch的重复语句。基本上你要准备好声明(例如“UPDATE ...???”,然后一次添加3个参数,并且一次全部执行批处理。)

我以前用这种东西作为工具来包装所以你只需要做点像

SQLBatchHandler h = new SQLBatchHandler(conn, "UPDATE ... WHERE ? ? ? ... "); 
    h.addToBatch(x, y,z); 
    h.addToBatch(x2,y2,z2); 
    ... 
    h.flush(); 



public class SQLBatchHandler { 
    public static int   MAX_BATCH_SIZE = 500; 
    public String   query; 
    private Connection  conn; 
    private PreparedStatement ps; 
    private int    batch_ct; 

    public SQLBatchHandler(Connection c, String query) throws SQLException 
     { 
     conn = c; 
     this.query = query; 
     ps = conn.prepareStatement(query); 
    } 

    /** 
    * add this row to the batch and handle the commit if the batch size 
    * exceeds {@link #MAX_BATCH_SIZE} 
    * 
    * @param values row values 
    * @throws SQLException 
    */ 
    public void addToBatch(Object ... values) throws SQLException 
    { 
     int i = 0; 
     for (Object value: values) 
     { 
      ps.setObject((++i), value); 
     } 
     add(); 
    } 

    private void add() throws SQLException 
    { 
     ps.addBatch(); 
     if ((++batch_ct) > MAX_BATCH_SIZE) 
     { 
      ps.executeBatch(); 
      batch_ct = 0; 
     } 
    } 

    /** 
    * Commit any remaining objects and close. 
    * 
    * @throws SQLException On statement close error. 
    */ 
    public void flush() throws SQLException 
    { 
     if (batch_ct == 0) { return; } 
     try 
     { 
      ps.executeBatch(); 
     } 
     catch (SQLException e) 
     { 
      throw e; 
     } 
     finally 
     { 
      if (ps != null) 
      { 
       ps.close(); 
      } 
     } 
    } 
}