2

我有一个自动生成的时间戳,每次在 mysql 表中插入或更新记录时都会创建该时间戳。有没有办法以类似于我如何使用密钥持有者返回新创建的 ID 的方式返回此时间戳?

KeyHolder keyHolder = new GeneratedKeyHolder();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

//Insert Contact
jdbcTemplate.update(new PreparedStatementCreator() {
    @Override
    public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
        PreparedStatement preparedStatement = connection.prepareStatement(SQL_ADD, Statement.RETURN_GENERATED_KEYS);
        preparedStatement.setString(1, contact.getFirstName());
        preparedStatement.setString(2, contact.getLastName());
        preparedStatement.setInt(3, contact.getOrganizationId());
        preparedStatement.setString(4, contact.getType());
        preparedStatement.setInt(5, contact.getUserId());
        return preparedStatement;
        }   
}, keyHolder);
//Use keyholder to obtain newly created id
contact.setId(keyHolder.getKey().intValue());

有什么方法可以返回新的时间戳而不必重新查询表?我一直在寻找将它与 id 一起作为密钥持有者中的密钥返回的方法,但它似乎没有作为密钥返回?

4

5 回答 5

1

不是很令人满意,但我认为“不”是您问题的答案。我不知道任何 Spring 的东西,但我认为这是由于它包装的基本 JDBC。请参阅http://docs.oracle.com/javase/6/docs/api/java/sql/Statement.html#getGeneratedKeys%28%29

您唯一的选择是在 MySQL 上创建一个具有 out 参数的存储过程并调用它。请参阅http://dev.mysql.com/doc/refman/5.0/en/call.html

于 2012-11-02T11:59:32.730 回答
0

在 MySQL 数据库服务器端解决此问题的选项很少。TRIGGER您可以从在桌子上创建一个开始。由于TRIGGER有限制且无法返回数据,您可以将TIMESTAMP值设置为变量:

DEMILITER //
CREATE TRIGGER ai_tbl_name AFTER INSERT ON tbl_name
FOR EACH ROW
BEGIN

SET @TimeStamp = NEW.timestamp_column;

END;//
DELIMITER ;

要检索此时间戳值,请运行以下命令:

SELECT @TimeStamp;

由于变量存储在内存中,因此无需再次打开任何表。

你走得更远。您可以在 MySQL 中创建一个STORED PROCEDURE来自动执行上述所有操作(示例代码,因为我不知道您的表的详细信息):

DELIMITER //
DROP PROCEDURE IF EXISTS sp_procedure_name //
CREATE PROCEDURE sp_procedure_name (IN col1_val VARCHAR(25),
                                    IN col2_val VARCHAR(25),
                                    IN col3_val INT)
BEGIN
    INSERT INTO tbl_name (col1, col2, col3)
    VALUES (col1_val, col2_val, col3_val);

    SELECT @TimeStamp;
END; //
DELIMITER ;

您可以使用以下代码运行此过程:

CALL sp_procedure_name(col1_val, col2_val, col3_val);

由于我不熟悉 Java,因此您需要使用自己的代码来完成它。

于 2012-11-06T14:48:51.010 回答
0

GeneratedKeyHolder也有两种方法:getKeyList()即返回Map<String,Object>生成的字段;并getKeyList()为所有受影响的行生成生成键的列表。

请参阅GeneratedKeyHolder的 java 文档和自动生成密钥的 Spring 教程

此外,Spring 的 SimpleJdbcInsert 具有生成密钥检索的方法。另见方法SimpleJdbcInsert#usingGeneratedKeyColumns

于 2012-10-31T22:11:43.783 回答
0

该变量似乎contact是新插入记录的实例。由于它包含新生成的id(主键)字段值,因此您可以执行新查询以返回timestamp此新的所需字段值id

查询可能如下所示:

select timestamp_field from my_table where id=?

用于PreparedStatement输入新id值并执行它以获取所需timestamp的字段值。

于 2012-10-28T16:23:17.047 回答
0

类中有 2 种方法java.sql.Connection导致 PreparedStatement 执行返回选定的键列:

PreparedStatement prepareStatement(String sql,
                                   int[] columnIndexes)
                                throws SQLException

PreparedStatement prepareStatement(String sql,
                                   String[] columnNames)
                                   throws SQLException

您不需要使用 Spring KeyHolder 和 JDBCTemplate 来执行此操作。
给希望您可以编号/命名您的时间戳列。但是 javadoc 不要求或不建议任何 JDBC 实现都可以返回非键列,因此您对这种方法不走运:

创建一个默认的 PreparedStatement 对象,该对象能够返回给定数组指定的自动生成的键。此数组包含目标表中包含应返回的自动生成键的列的名称。


  • 正如另一个答案中所建议的那样,可以切换到完全符合您要求的存储过程(CallableStatement 实际上是执行存储过程的 PreparedStatement - 即子类)。

  • 可以通过 new 填充准备好的语句中的时间戳列Timestamp(new Date())- 但您应该有一种机制来在各种服务器之间同步时间(通常在 windows 和 *nix 环境中使用)。仅当尚未提供值时,您的触发器才能设置时间戳。

作为您的应用程序和数据库设计的一部分,您需要遵循特定操作发生位置的理念。如果数据库派生所需的数据,应用程序需要刷新数据 - 您必须支付单独的查询执行或插入和检索的组合存储过程的代价。

于 2012-11-06T07:01:36.690 回答