JDBC3 中可以直接获取当前插入记录的 ID 值,具体的调用方式如下:
Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO authors (first_name, last_name) values
(′George′, ′Orwell′)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();
if ( rs.next() ) ...{
int key = rs.getInt();
}
由于实际与数据库交互采用的是 JdbcTemplate,因而需要找到它对这种方式的支持。经过实际的查看 Spring 的 API 发现其本身提供相应的方法支持,经过多次的实验后得到如下的实现方法:
private void insert(final Profile profile)...{
final String _save = "insert into Newsletter_Profile (user_id, publication_id, last_update) values (?, ?, getdate())";
JdbcTemplate template = this.getJdbcTemplate();
KeyHolder keyHolder = new GeneratedKeyHolder();
template.update(new PreparedStatementCreator() ...{
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException ...{
int i = 0;
PreparedStatement ps = con.prepareStatement(_save,
Statement.RETURN_GENERATED_KEYS);
ps.setInt(++i, profile.getCustomerId().intValue());
ps.setInt(++i, profile.getPublication().getId());
return ps;
}
}, keyHolder);
profile.setId(keyHolder.getKey().intValue());
}
特别需要注意的地方是
Statement.RETURN_GENERATED_KEYS,在使用MS SQL Server 2005 提供的 JDBC Driver 中上面的部分是必须的。之所以这么说是因为 google 出来的所有资料都是没有该部分的,甚至 Spring 自身的 document 中也是没有该参数的。我现在不知道那些代码是否能够真正的获取到 Key,但是现在我 suppose 它们是可以 run 的。
如果没有加入
Statement.RETURN_GENERATED_KEYS ,在实际进行数据库操作时会出现如下的异常:
PreparedStatementCallback; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; The statement must be executed before any results can be obtained.; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: The statement must be executed before any results can be obtained.
caused by : com.microsoft.sqlserver.jdbc.SQLServerException: The statement must be executed before any results can be obtained.
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; The statement must be executed before any results can be obtained.; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: The statement must be executed before any results can be obtained. Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The statement must be executed before any results can be obtained.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getGeneratedKeys(Unknown Source)
at weblogic.jdbc.wrapper.PreparedStatement_com_microsoft_sqlserver_jdbc_SQLServerPreparedStatement.getGeneratedKeys(Unknown Source)
at org.springframework.jdbc.core.JdbcTemplate$3.doInPreparedStatement(JdbcTemplate.java:772)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:527)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:767)
at com.fdc.reports20.dao.NewsletterDAO.insert(NewsletterDAO.java:179)
at com.fdc.reports20.dao.NewsletterDAO.save(NewsletterDAO.java:153)
at com.fdc.reports20.dao.NewsletterDAO.update(NewsletterDAO.java:138)
at com.fdc.reports20.business.service.user.AlertServiceImpl.updateNewsletter(AlertServiceImpl.java:146)
at com.fdc.reports20.business.service.user.AlertServiceImpl$$FastClassByCGLIB$$52b80fbc.invoke()
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:674)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:154)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:53)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:107)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:615)
at com.fdc.reports20.business.service.user.AlertServiceImpl$$EnhancerByCGLIB$$a12ee5d8.updateNewsletter()
at com.fdc.reports20.web.delegate.AlertBD.updateNewsletter(AlertBD.java:78)
at com.fdc.reports20.web.jpf.um.workbench.WorkBenchController.editPublicationEmails(WorkBenchController.java:149)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)