在使用Groovy SQL的 withBatch 方法时,是否有人检索过数据库插入的自动生成的密钥?我有以下代码
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对象,而不是groovy的对象。有什么想法吗?
答案 0 :(得分:0)
我把Groovy SQL的东西拿出来看看我是否可以得到一些工作,我想确保DB2 for 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)可防止创建可返回自动生成密钥的语句。
答案 1 :(得分:0)
为了确保我没有疯狂,我再次尝试了'getGeneratedKeys'方法,并且声明我知道有效并且没有结果(见下文)。我不得不递归地遍历结果以找到IBM类。所以...不是我最喜欢的代码,它非常脆弱,但它很实用。现在我只需要看看我是否还能以某种方式使用 withBatch 方法,我显然需要覆盖一些东西。
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]]
答案 2 :(得分: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)
}
}