我在mysql中有一个表,其中一个数据类型为timestamp作为列之一,在插入时获取默认值CURRENT_TIME。我有另一个时间戳列,更新时默认值为CURRENT_TIME。我有这些,以便时间戳列将在插入和更新时自动更新(工作正常)。
现在我正在使用cxf,hibernate / jpa,mysql,jackson来构建一个Web服务。 我只是创建一个新记录并立即检索它,如下面的代码所示。
Session session = getSession(); // sessionFactory.getCurrentSession();
String accountId = (String)session.save(account);
Account newAccount = (Account)session.load(Account.class, accountId);
logger.info("created timestamp=" + newAccount.getCreatedTimestamp());
运行上面的代码之后,我可以看到在mysql中创建了新记录,并为createdTimestamp创建了正确的时间戳。但是,上面的logger.info()行会抛出异常,因为newAccount.getCreatedTimestamp()返回null。如果我删除logger.info()行,我可以看到newAccount对象填充了正确的值,除了createdTimestamp为null。
更奇怪的是,在运行上面的代码(这是HTTP POST操作的一部分)之后,我调用了一个HTTP GET服务,它只是通过执行
来获取我刚刚插入的记录session.get(Account.class, accountId);
并正确显示时间戳!
我试图在session.load()或session.get()之前睡觉,认为插入时间戳可能有延迟,但这并没有做太多。 hibernate会话管理有什么特别之处,它不能检索mysql生成的列吗?我在这里失踪了什么?请帮忙。
答案 0 :(得分:2)
在刷新会话之前,您的实际保存不会被提交。在刷新或关闭会话之前,Hibernate实际上没有向数据库提交任何内容,因此如果抛出异常,回滚实际上不必触及物理数据库,则不会发送更改。但是,如果Hibernate检测到查询将接收过时数据,它将在运行该查询之前自动刷新。
例如,您将记录添加到数据库并立即调用SELECT COUNT(*)
查询。 Hibernate将刷新会话(在进程中提交记录),然后在现在清理的会话上执行SELECT COUNT(*)
查询,确保您获得正确的数据。 Hibernate在你的情况下没有这样做,因为它看到你正在请求你试图插入的同一个对象(在同一个会话中)所以它只是返回你那个引用。
如果您让hibernate管理其会话(使用会话工厂或类似工具),我不认为您必须明确关闭会话。我知道我不是,但我在Spring中使用Hibernate,并使用管理实际Hibernate会话的@Transactional
注释。如果要立即插入,请调用save()方法中的最后一次调用。通常,一旦方法退出,将自动调用commit()
。
所有load()
将会为您提供与Account
相同的session.save()
实例。关闭或刷新会话,然后再次尝试load()
,并设置您的值。