вставить строку и получить сгенерированный идентификатор

Я пытаюсь использовать класс Spring JdbcTemplate, чтобы вставить строку в таблицу MySQL с именем transaction и получить сгенерированный идентификатор. Соответствующий код:

public Transaction insertTransaction(final Transaction tran) {

    // Will hold the ID of the row created by the insert
    KeyHolder keyHolder = new GeneratedKeyHolder();

    getJdbcTemplate().update(new PreparedStatementCreator() {
        public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {

            PreparedStatement ps = connection.prepareStatement(INSERT_TRAN_SQL);
            ps.setString(1, tran.getTransactionType().toString());

            Date sqlDate = new Date(tran.getDate().getTime());
            ps.setDate(2, sqlDate);
            ps.setString(3, tran.getDescription());

            return ps;
        }
    }, keyHolder);

    tran.setId(keyHolder.getKey().longValue());
    return tran;
}

Но следующее исключение вызывается вызовом getJdbcTemplate().update

java.sql.SQLException: сгенерированные ключи не запрошены. Вам нужно указать Statement.RETURN_GENERATED_KEYS в Statement.executeUpdate() или Connection.prepareStatement().

Могу ли я вставить строку и получить сгенерированный идентификатор, не отказываясь от JdbcTemplate? Я использую Spring 2.5, MySQL 5.5.27 и MySQL Connector 5.1.26.


person Dónal    schedule 30.09.2013    source источник
comment
Я думаю, что с MySQL вам нужно будет вызвать last_insert_id(). См. здесь.   -  person Sotirios Delimanolis    schedule 30.09.2013


Ответы (3)


Просто подготовьте Statement следующим образом.

PreparedStatement ps = connection.prepareStatement(
                           INSERT_TRAN_SQL, Statement.RETURN_GENERATED_KEYS);

Базовый драйвер JDBC (используемый косвенно через Spring JdbcTemplate здесь) требует подсказки, что вы хотели бы получить сгенерированные ключи. Это можно сделать либо при подготовке PreparedStatement как

connection.prepareStatement(strSQL, Statement.RETURN_GENERATED_KEYS);

или во время выполнения Statement as

statement.executeUpdate(strSQL, Statement.RETURN_GENERATED_KEYS);

На это же указывает и ваш java.sql.SQLException.

person Ravi K Thapliyal    schedule 30.09.2013
comment
Привет, просто вопрос, если запрос выполнен успешно, он возвращает сгенерированный идентификатор, но что он возвращает, если запрос не выполняется, чтобы я мог изящно обработать ошибку в своем коде? - person Sajib Acharya; 24.03.2016

Есть более простой способ получить такое поведение:

protected JdbcTemplate            jdbcTemplate;
private SimpleJdbcInsert          insert;

    this.jdbcTemplate = new JdbcTemplate(this.databaseSetup.getDataSource());
    this.insert = new SimpleJdbcInsert(this.jdbcTemplate).withTableName(this.tableName).usingGeneratedKeyColumns(this.pkColumn);

Затем вы создаете карту, называемую параметрами, которая содержит значения для каждого имени столбца в вашей таблице, и вставляете такую ​​запись:

    final Map<String, Object> parameters = new HashMap<>();
    parameters.put("empName", employee.getName()); // store the String name of employee in the column empName
    parameters.put("dept", employee.getDepartment()); // store the int (as Integer) of the employee in the column dept
    final Number key = this.insert.executeAndReturnKey(parameters);
    final long pk = key.longValue();
person GerritCap    schedule 30.09.2013
comment
Было бы здорово, если бы вы привели пример сопоставленных значений в своем ответе. Из текущего ответа не очевидно использовать Map‹String, Object› без дальнейшего изучения внешней документации и того, что представлено ключом и значением. Это заслуживало бы одобрения, если бы эта информация была доступна. - person Hazok; 14.01.2015
comment
Я думал, что совершенно очевидно, что если я упомяну параметры карты, содержащие значения для каждого имени столбца, поскольку я упомянул имя столбца, должно было быть очевидно, что ключи являются строками, а значения, поскольку неопределенные, могут быть любым сопоставлением объекта с типом sql. Кстати: никогда не помешает проверить документацию, никогда не доверять какому-либо конкретному ответу и не проверять его дважды. - person GerritCap; 14.01.2015
comment
Это очевидно, чтобы проверить документацию и не доверять конкретному ответу. Также очевидно, что хороший вопрос на Stackoverflow предоставляет все необходимые детали и не оставляет ничего двусмысленного. Также очевидно, что кто-то, кто впервые использует стек Java JDBC, не увидит такие вещи как очевидные;) - person Hazok; 14.01.2015

Вы можете получить следующий порядковый номер, как на шаге 1, затем его можно передать в операторе вставки, как на шаге 2:

1-

Integer nextSeq = (Integer) getJdbcTemplate().queryForObject(
        "select SEQ_CUSTOMER_ID.nextVal from dual", new Object[] {}, Integer.class);

2-

getJdbcTemplate().update(
        "INSERT INTO customer "
        + "(CUST_ID, NAME, UPDATED) VALUES (?, ?, ?)",
        new Object[] { nextSeq ,customer.getName(),
                customer.getUpdated() });
person Eddy Joseph    schedule 03.09.2014