2015-10-06 82 views
2

有沒有人檢索過使用Groovy SQL的和批處理方法的數據庫插入的自動生成的鍵?我有Groovy addBatch/executeBatch with autoGenerated keys

def Sql target = ...//database connection 
target.withBatch { ps -> 
    insertableStuff.each { ps.addBatch (it) } 

    ps.executeBatch() 

    def results = ps.getGeneratedKeys() //what do I do with this? 
} 

我們正在使用的DB2下面的代碼,我已經成功地測試了的getGeneratedKeys方法用一個語句/結果集,但一旦我在批量包裝的過程中,我不知道我正在處理什麼對象。

根據IBM,可以得到結果,但它們的示例使用標準的JDBC對象,而不是常規的對象。有任何想法嗎?

+0

當您打印'results'時出現什麼? –

+0

所以我認爲在這裏有一些與我有關的事情.1)我們使用Apache的DBCP庫來管理我們的連接,並將準備好的語句包裝在DelegatingPreparedStatement類中。 2)'withBatch'中的SQL類不會創建具有所需額外參數的語句(http://docs.oracle.com/javase/7/docs/api/java/sql/Connection.html#prepareStatement(java) .lang.String,%20int [])),它將告訴JDBC返回生成的值。 –

+0

它只是打印出類的名稱(DelegatingResultSet)。 –

回答

0

好吧,讓它工作。我有我的方式入侵到Groovy的SQL類,有一些事情,我不能這樣做,因爲在Groovy類的方法是私有的,所以這個實現不支持cachedStatements,該isWithinBatch方法將無法工作正確地在閉包中,並且無法訪問更新的行數。

很高興在基本Groovy代碼中看到這種變化,或許有一個擴展點放在自己的處理程序中(因爲您不想在基本Groovy代碼中使用IBM特定的東西) ,但至少我現在有一個可行的解決方案。

public class SqlWithGeneratedKeys extends Sql { 
    public SqlWithGeneratedKeys(Sql parent) { 
     super(parent); 
    } 
    public List<GroovyRowResult> withBatch(String pSql, String [] keys, Closure closure) throws SQLException { 
     return this.withBatch(0, pSql, keys, closure); 
    } 

    public List<GroovyRowResult> withBatch(int batchSize, String pSql, String [] keys, Closure closure) throws SQLException { 
     final Connection connection = this.createConnection(); 
     List<Tuple> indexPropList = null; 

     final SqlWithParams preCheck = this.buildSqlWithIndexedProps(pSql); 
     BatchingPreparedStatementWrapper psWrapper = null; 

     String sql = pSql; 
     if (preCheck != null) { 
      indexPropList = new ArrayList<Tuple>(); 
      for (final Object next : preCheck.getParams()) { 
       indexPropList.add((Tuple) next); 
      } 
      sql = preCheck.getSql(); 
     } 

     PreparedStatement statement = null; 
     try { 
      statement = connection.prepareStatement(sql, keys); 
      this.configure(statement); 
      psWrapper = new BatchingPreparedStatementWrapper(statement, indexPropList, batchSize, LOG, this); 
      closure.call(psWrapper); 
      psWrapper.executeBatch(); 

      return this.getGeneratedKeys(statement); 
     } catch (final SQLException e) { 
      LOG.warning("Error during batch execution of '" + sql + "' with message: " + e.getMessage()); 
      throw e; 
     } finally { 
      BaseDBServices.closeDBElements(connection, statement, null); 
     } 
    } 

    protected List<GroovyRowResult> getGeneratedKeys(Statement statement) throws SQLException { 
     if (statement instanceof DelegatingStatement) { 
      return this.getGeneratedKeys(DelegatingStatement.class.cast(statement).getDelegate()); 

     } else if (statement instanceof DB2PreparedStatement) { 
      final ResultSet[] resultSets = DB2PreparedStatement.class.cast(statement).getDBGeneratedKeys(); 

      final List<GroovyRowResult> keys = new ArrayList<GroovyRowResult>(); 
      for (final ResultSet results : resultSets) { 
       while (results.next()) { 
        keys.add(SqlGroovyMethods.toRowResult(results)); 
       } 
      } 
      return keys; 
     } 
     return Arrays.asList(SqlGroovyMethods.toRowResult(statement.getGeneratedKeys())); 
    } 
} 

調用它很好,很乾淨。

println new SqlWithGeneratedKeys(target).withBatch(statement, ['ISN'] as String[]) { ps -> 
    rows.each { 
     ps.addBatch(it) 
    } 
} 
0

我把Groovy的SQL的東西出來的圖片,看看我能得到的東西的工作,我想確保DB2 z/OS的實際支持的功能,並能得到生成的值。我使用的是IBM's example,但是我不得不添加一些額外的代碼來處理IBM示例正在使用的投射。

SQL target = ...//get database connection 
def preparedStatement = target.connection.prepareStatement(statement, ['ISN'] as String[]) 
ResultSet[] resultSets = ((DB2PreparedStatement) (ps.getDelegate().getDelegate())).getDBGeneratedKeys() 
resultSets.each { ResultSet results -> 
    while(results.next()) { 
     println results.getInt(1) 
    } 
} 

所以...這有點笨重,但它的功能。不幸的是,通過自己控制語句,我失去了Groovy通常爲我所做的所有參數映射。

我正在瀏覽groovy的Sql源代碼,可以看到他們在哪裏明確告訴數據庫連接不處理參數,所以我想我會添加一個新的方法到Sql.metaClass,可以通過自動生成的列名稱列表或其他內容以使其更可口。

我也想看看是否有辦法讓getGeneratedKeys方法工作,這樣我就不必完成所有的這種轉換。至少,一種實用的方法來安全地處理我的鑄件。

try { 
    withinBatch = true; 
    PreparedStatement statement = (PreparedStatement) getAbstractStatement(new CreatePreparedStatementCommand(0), connection, sql); 
    configure(statement); 
    psWrapper = new BatchingPreparedStatementWrapper(statement, indexPropList, batchSize, LOG, this); 
    closure.call(psWrapper); 
    return psWrapper.executeBatch(); 
} catch (SQLException e) { 

createNewPreparedStatement(0)防止可能返回自動生成的鍵聲明的創建。

0

只是爲了確保我是不是瘋了,我再次,我知道作品的一份聲明再次嘗試「的getGeneratedKeys」的方法,我得到任何結果(見下文)。我不得不循環遍歷結果來查找IBM類。所以...不是我最喜歡的代碼,它非常脆弱,但它的功能。現在我只需要看看我是否仍然可以使用和批處理方法,我顯然需要重寫一些內容。

println 'print using getGeneratedKeys' 
def results = preparedStatement.getGeneratedKeys() 
while (results.next()) { 
    println SqlGroovyMethods.toRowResult(results) 
} 

println 'print using delegate processing' 
println getGeneratedKeys(preparedStatement) 

private List getGeneratedKeys(PreparedStatement statement) { 
    switch (statement) { 
     case DelegatingStatement: 
      return getGeneratedKeys(DelegatingStatement.cast(statement).getDelegate()) 

     case DB2PreparedStatement: 
      ResultSet[] resultSets = DB2PreparedStatement.cast(statement).getDBGeneratedKeys() 

      List keys = [] 
      resultSets.each { ResultSet results -> 
       while (results.next()) { 
        keys << SqlGroovyMethods.toRowResult(results) 
       } 
      } 
      return keys 

     default: 
      return [SqlGroovyMethods.toRowResult(statement.getGeneratedKeys())] 
    } 
} 

---- Console Output ---- 
print using getGeneratedKeys 
print using delegate processing 
[[KEY:7391], [KEY:7392]]