代码之家  ›  专栏  ›  技术社区  ›  sma

使用以编程方式生成的主键的Spring的键槽

  •  7
  • sma  · 技术社区  · 14 年前

    我正在使用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)
    

    你知道我缺少什么吗?

    5 回复  |  直到 6 年前
        1
  •  -3
  •   skaffman    14 年前

    我觉得你用的方法不对 JdbcTemplate . 唯一的一个 update 似乎与代码片段匹配的方法是

    int update(String sql, Object... args)
    

    如果是的话,你就路过了 params key 作为两个元素的vargs数组,和 使用 正在治疗 钥匙 作为一个普通的绑定参数,并对其进行了错误的解释。

    唯一的公众 更新 方法对 使用 那需要一个 KeyHolder

    int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)
    

    所以您需要重新措辞您的代码才能使用它。

        2
  •  17
  •   Community Romance    9 年前

    刚刚解决了一个类似的问题-使用Oracle,您需要使用另一种方法(从 NamedParameterJdbcOperations -

    int update(String sql,
               SqlParameterSource paramSource,
               KeyHolder generatedKeyHolder,
               String[] keyColumnNames)
               throws DataAccessException
    

    其中keycolumnnames包含自动生成的列,在我的例子中只有[“id”]。否则你只会得到罗伊德。见 Spring doc 详情。

        3
  •  2
  •   Espen    14 年前

    你必须执行 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 在参考文件中。

        4
  •  0
  •   supernova    8 年前

    关于@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 )
                    {
            }
            }
    
        5
  •  0
  •   cdesmetz    6 年前

    用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;
    }
    }