我使用Spring的NamedParameterJdbcTemplate来执行对表的插入。该表在序列上使用NEXTVAL来获取主键。然后,我希望将生成的ID传回给我。我正在使用Spring的KeyHolder实现:
KeyHolder key = new GeneratedKeyHolder();
jdbcTemplate.update(Constants.INSERT_ORDER_STATEMENT, params, key);
然而,当我运行这个陈述时,我得到了:
org.springframework.dao.DataRetrievalFailureException: The generated key is not of a supported numeric type. Unable to cast [oracle.sql.ROWID] to [java.lang.Number]
at org.springframework.jdbc.support.GeneratedKeyHolder.getKey(GeneratedKeyHolder.java:73)
我缺少什么想法?
答案 0 :(得分:18)
刚刚解决了类似问题 - 使用Oracle需要使用其他方法(来自NamedParameterJdbcOperations
) -
int update(String sql,
SqlParameterSource paramSource,
KeyHolder generatedKeyHolder,
String[] keyColumnNames)
throws DataAccessException
keyColumnNames包含自动生成的列,在我的例子中只是[“Id”]。否则你得到的只是ROWID。有关详细信息,请参阅Spring doc。
答案 1 :(得分:2)
您必须执行JdbcTemplate.update(PreparedStatementCreator p, KeyHolder k)
。
从数据库返回的密钥将被注入KeyHolder
参数对象。
一个例子:
final String INSERT_ORDER_STATEMENT
= "insert into order (product_id, quantity) values(?, ?)";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(
Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement(
INSERT_ORDER_STATEMENT, new String[] { "id" });
ps.setInt(1, order.getProductId());
ps.setInt(2, order.getQuantity());
return ps;
}
}, keyHolder);
参考文档中可以找到更多信息here。
答案 2 :(得分:0)
没有详细说明@konstantin回答:这是一个完整的例子: 假设数据库是Oracle,并且存储生成的Id的列名是“GENERATED_ID”(可以是任何名称)。 注意:我使用了NamedParameterJdbcTemplate.update(....)在这个例子中没有Spring的JdbcTemplate类。
public Integer insertRecordReturnGeneratedId(final MyObject obj)
{
final String INSERT_QUERY = "INSERT INTO MY_TABLE VALUES(GENERATED_ID_SEQ.NEXTVAL, :param1, :param2)";
try
{
MapSqlParameterSource parameters = new MapSqlParameterSource().addValue( "param1", obj.getField1() ).addValue( "param2", obj.getField1() ) ;
final KeyHolder holder = new GeneratedKeyHolder();
this.namedParameterJdbcTemplate.update( INSERT_QUERY, parameters, holder, new String[] {"GENERATED_ID" } );
Number generatedId = holder.getKey();
// Note: USING holder.getKey("GENERATED_ID") IS ok TOO.
return generatedId.intValue();
}
catch( DataAccessException dataAccessException )
{
}
}
答案 3 :(得分:0)
使用MySQL
CREATE TABLE `vets` (
`id` int(4) unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(30) DEFAULT NULL,
`last_name` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `last_name` (`last_name`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
public @Data class Vet {
private int id;
private String firstname;
private String lastname;
}
@Repository
public class VetDaoImpl implements VetDao {
/** Logger. */
private static final Logger LOGGER = LoggerFactory.getLogger(VetDaoImpl.class);
private static final String INSERT_VET = "INSERT INTO vets (first_name, last_name) VALUES (:first_name, :last_name)";
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Override
public Number insertVet(final Vet vet) {
MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValue("first_name", vet.getFirstname());
paramSource.addValue("last_name", vet.getLastname());
KeyHolder keyHolder = new GeneratedKeyHolder();
int nbRecord = namedParameterJdbcTemplate.update(INSERT_VET, paramSource, keyHolder, new String[] {"id" });
LOGGER.info("insertVet: id ["+keyHolder.getKey()+"]");
return nbRecord;
}
}
答案 4 :(得分:-3)
我认为你在JdbcTemplate
上使用了错误的方法。 {/ 1}}方法中唯一似乎与您的代码片段匹配的方法是
update
如果是这样,您将int update(String sql, Object... args)
和params
作为双元素vargs数组传递,key
将JdbcTemplate
视为正常绑定参数,并且错误 - 解释它。
key
上update
的唯一公开JdbcTemplate
方法是<{1}}
KeyHolder
因此,您需要重新编写代码才能使用它。