利用 JdbcTemplate 自动返回 MS SQL SERVER 2005 自增主键值

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)

你可能感兴趣的:(技术文章)