今天学spring3的jdbc,写了这么段代码
public Hello createHello(final Hello hello) {
final String sql = "insert into crud_hello(name,age,money,at_work,icon,introduce,create_date)"
+ " values (?,?,?,?,?,?,now())";
//Caused by: java.io.NotSerializableException: smartcrud.spring.models.crud.HelloDaoJdbcImpl$1
//at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
//at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
//at com.mysql.jdbc.PreparedStatement.setSerializableObject(PreparedStatement.java:4267)
// KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(sql, new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException {
PreparedStatement ps = con.prepareStatement(sql);
int z = 0;
ps.setString(++z, hello.getName());
ps.setInt(++z, hello.getAge());
ps.setDouble(++z, hello.getMoney());
ps.setBoolean(++z, hello.isAtWork());
ps.setBytes(++z, hello.getIcon());
ps.setString(++z, hello.getIntroduce());
return ps;
}
}/*, keyHolder*/);
// hello.setId(keyHolder.getKey().longValue());
/*
jdbcTemplate.update(sql, new PreparedStatementSetter(){
@Override
public void setValues(PreparedStatement ps) throws SQLException {
int z = 0;
ps.setString(++z, hello.getName());
ps.setInt(++z, hello.getAge());
ps.setDouble(++z, hello.getMoney());
ps.setBoolean(++z, hello.isAtWork());
ps.setBytes(++z, hello.getIcon());
ps.setString(++z, hello.getIntroduce());
}});*/
return hello;
}
结果运行时出现如下错误
org.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [insert into crud_hello(name,age,money,at_work,icon,introduce,create_date) values (?,?,?,?,?,?,now())]; Invalid argument value: java.io.NotSerializableException; nested exception is java.sql.SQLException: Invalid argument value: java.io.NotSerializableException
org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:107)
org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:603)
org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:812)
org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:868)
org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:876)
smartcrud.spring.models.crud.HelloDaoJdbcImpl.createHello(HelloDaoJdbcImpl.java:32)
为啥用PreparedStatementCreator就不可以,用下面的PreparedStatementSetter就没有问题。
看起来是XX没有序列化,可是我的实体Hello绝对是实现了Serializable接口的,各种搜索无果,今天爬起来,决定要跟踪一下到底哪儿出问题了。
在log4j.properties加入如下配置:
log4j.logger.org.springframework.jdbc=TRACE
观察到
[09-29 10:33:16 DEBUG] Executing prepared SQL update
[09-29 10:33:16 DEBUG] Executing prepared SQL statement [insert into crud_hello(name,age,money,at_work,icon,introduce,create_date) values (?,?,?,?,?,?,now())]
[09-29 10:33:17 DEBUG] Fetching JDBC Connection from DataSource
[09-29 10:33:17 TRACE] Setting SQL statement parameter value: column index 1, parameter value [smartcrud.spring.models.crud.HelloDaoJdbcImpl$1@12000a5], value class [smartcrud.spring.models.crud.HelloDaoJdbcImpl$1], SQL type unknown
[09-29 10:33:17 DEBUG] Returning JDBC Connection to DataSource
说的是第一个?占位符的value设置成了smartcrud.spring.models.crud.HelloDaoJdbcImpl$1,类型不识别。。可是我明明设置的
ps.setString(++z, hello.getName());
是个String类型的,怎么会不识别呢。乍一看去没有道理,从编译的后的class文件中找到了smartcrud.spring.models.crud.HelloDaoJdbcImpl$1这个东西,
class 1
implements PreparedStatementCreator,
OH,才恍然大悟,我的API用错了。
我用的是jdbcTemplate.update(sql,new PreparedStatementCreator()),
第二个参数PreparedStatementCreator默认成了sql的第1个占位符的值,正确的写法是
jdbcTemplate.update(new PreparedStatementCreator())
修正后的代码如下:
@Repository
public class HelloDaoJdbcImpl implements HelloDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public Hello createHello(final Hello hello) {
final String sql = "insert into crud_hello(name,age,money,at_work,icon,introduce,create_date)"
+ " values (?,?,?,?,?,?,now())";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(/*sql, */new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con)
throws SQLException {
PreparedStatement ps = con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
int z = 0;
ps.setString(++z, hello.getName());
ps.setInt(++z, hello.getAge());
ps.setDouble(++z, hello.getMoney());
ps.setBoolean(++z, hello.isAtWork());
ps.setBytes(++z, hello.getIcon());
ps.setString(++z, hello.getIntroduce());
return ps;
}
}, keyHolder);
hello.setId(keyHolder.getKey().longValue());
return hello;
}
}