I'm trying to use Spring's JdbcTemplate
class to insert a row into a MySQL table named transaction
and get the generated ID. The relevant code is:
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;
}
But the following exception is thrown by the call to getJdbcTemplate().update
java.sql.SQLException: Generated keys not requested.
You need to specify Statement.RETURN_GENERATED_KEYS to
Statement.executeUpdate() or Connection.prepareStatement().
Can I insert the row and get the generated ID, without abandoning JdbcTemplate
? I'm using Spring 2.5, MySQL 5.5.27 and MySQL Connector 5.1.26.
Just prepare your Statement
as follows
PreparedStatement ps = connection.prepareStatement(
INSERT_TRAN_SQL, Statement.RETURN_GENERATED_KEYS);
The underlying JDBC driver (used indirectly through the Spring's JdbcTemplate
here) requires a hint that you would like to retrieve the generated keys. This can be done either while preparing a PreparedStatement
as
connection.prepareStatement(strSQL, Statement.RETURN_GENERATED_KEYS);
or, at the time of executing a Statement
as
statement.executeUpdate(strSQL, Statement.RETURN_GENERATED_KEYS);
This is what your java.sql.SQLException
is pointing at as well.
There is an easier way to get that behaviour:
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);
Then you create a Map called parameters which conmtains the values for each column name in your table and insert a record like this:
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();
You can retrieve the next sequence number like in step 1, then it can passed in the insert statement as in the step 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() });