16

I got a very common question when I was using Spring JDBCTemplate, I want to get the ID value after I inserted a new data record into database, this ID value will be referred to another related table. I tried the following way to insert it, but I always return 1 rather than its real unique ID. (I use MySQL as the database)

public int insert(BasicModel entity) {
    String insertIntoSql = QueryUtil.getInsertIntoSqlStatement(entity);

    log.info("SQL Statement for inserting into: " + insertIntoSql);

    return this.jdbcTemplate.update(insertIntoSql);
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Brady Zhu
  • 1,305
  • 5
  • 21
  • 43

3 Answers3

15

JdbcTemplate.update() returns:

the number of rows affected

Which is always 1 for INSERT statement. Different databases support generated key extraction in different ways, but most JDBC drivers abstract this and JdbcTemplate supports this. Quoting 12.2.8 Retrieving auto-generated keys

An update() convenience method supports the retrieval of primary keys generated by the database. This support is part of the JDBC 3.0 standard; see Chapter 13.6 of the specification for details.

Basically you need this much more verbose statement:

final String insertIntoSql = QueryUtil.getInsertIntoSqlStatement(entity);
KeyHolder keyHolder = new GeneratedKeyHolder();

jdbcTemplate.update(
  new PreparedStatementCreator() {
    public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
      return connection.prepareStatement(insertIntoSql, new String[] {"id"});
    }
  }, keyHolder);

return keyHolder.getKey().intValue();
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 1
    Hi Tomasz, I try your method, but didnt work in my place. I work on it on long time but cant get the solution. Kindly advise http://stackoverflow.com/questions/24567633/get-back-the-primary-key-value-after-insertion-to-db2-table-by-keyholder – Panadol Chong Jul 04 '14 at 09:14
  • How can we do the same in Batch update? – PAA Feb 14 '22 at 12:17
5

@panadol-chong, a small modification was necessary for @tomasz-nurkiewicz's code to work here.

final String SQL = "INSERT INTO ... RETUNING id";

KeyHolder keyHolder = new GeneratedKeyHolder();

jdbcTemplate.update(connection -> {
    PreparedStatement ps = connection.prepareStatement(SQL, 
                           Statement.RETURN_GENERATED_KEYS);

    return ps;
}, keyHolder);

return keyHolder.getKey().intValue();

The main difference is the Statement.RETURN_GENERATED_KEYS.

5

You can use @Tomasz Nurkiewicz answer and it works for sure, but you don't need to : Spring offers SimpleJdbcInsert which "provides meta-data processing to simplify the code needed to construct a basic insert statement".

@Repository
public class UserDao {

    private JdbcTemplate jdbcTemplate;
    private SimpleJdbcInsert insertIntoUser;

    @Autowired
    public UserDao(DataSource datasource) {
        jdbcTemplate = new JdbcTemplate(datasource);
        insertIntoUser = new SimpleJdbcInsert(jdbcTemplate).withTableName("user").usingGeneratedKeyColumns("id_user");
    }

    public Number insertUser(User u) {
        final Map<String, Object> parameters = new HashMap<>();
        parameters.put("name", u.getName());

        return insertIntoUser.executeAndReturnKey(parameters);
    }
}

The "Number" returned by insertUser is the id_user generated for the user insertion.

David Tonhofer
  • 14,559
  • 5
  • 55
  • 51
Tristan
  • 8,733
  • 7
  • 48
  • 96