保存后,Hibernate无法持久化数据

6
有人能解释为什么这个例子中“lastAccessed”日期没有保存到数据库中,以及我如何让它保存到数据库中吗?我的理解是,在save()调用之后,do对象是一个附加的对象,因此所有修改都应该自动持久化。注意:“myDate”被正确持久化,因此所有其他Spring配置似乎都是正确的。
@Transactional(readOnly = false)
public DateObject getOrCreateDateObject(Date myDate) {
    DateObject do = null;

    do = getCurrentDateObject();  // For my tests, this has been returning null

    if (do == null) {
        // create a new object
        do = new DateObject();
        do.setDate(myDate);
        sessionFactory.getCurrentSession().save(do);
    }

    // This does not persist to the database
    do.setLastAccessed(new Date());

    return do;
}

我也尝试了以下组合(以及更多),在save()调用之后,但是都没有起作用:
sessionFactory.getCurrentSession().merge(do);  // tried before and after do.setDate(d2)

sessionFactory.getCurrentSession().update(do);

sessionFactory.getCurrentSession().saveOrUpdate(do);

sessionFactory.getCurrentSession().flush();

DateObject doCopy = (DateObject)sessionFactory.getCurrentSession().load(DateObject.class, do.getId());
sessionFactory.getCurrentSession().merge(doCopy);
doCopy.setLastAccessed(new Date());

我希望这是一个容易回答的问题,只是我没有看到。谢谢你的帮助!
编辑#1 05/22/2012
如请求所示,这里是实体的映射,指定在src/main/resources/META-INF/dateobject.hbm.xml中。 我可以看到使用mysql客户端中的“SELECT * FROM dateObjects”来创建数据库中的列。 MY_DATE被正确填充,但LAST_ACCESSED设置为NULL。
<class name="com.example.entity.DateObject" table="dateObjects">
    <id name="id" column="DATE_OBJECT_ID">
        <generator class="identity" />
    </id>
    <property name="date" type="date" column="MY_DATE" />
    <property name="lastAccessed" type="date" column="LAST_ACCESSED" />
</class>

编辑 #2 05/24/2012

我在https://github.com/eschmidt/dateobject上有一个可行的SSCCE。有趣的是,Web客户端(调用localhost:8080/view/test)显示lastAccessed已正确设置,但当我使用MySQL客户端检查数据库时,它显示lastAccessed为NULL。有了这个完整的代码集,有人能看到为什么数据库不会更新,即使该方法被标记为@Transactional吗?


你有收到任何异常吗?是否有打开的会话? - Art
在设置“lastAccessed”日期后,您需要调用“save”。 - Rosdi Kasim
@RosdiKasim:不对。OP在假设一旦附加到会话中,对象的状态将被持久化到数据库上是正确的。 - Ryan Stewart
你能展示一下 DateObject 的映射吗? - Tim Pote
@arturnt:日志中没有看到任何异常。我知道会话已经打开,因为do.date成功保存到数据库中了。 - Eric
显示剩余4条评论
2个回答

2
如果您确定在运行该代码后,do.date存储在数据库中而do.lastAccessed没有存储,则您的连接和事务显然已正确设置。我的第一个猜测是错误的映射,因为这是最简单的解决方案。您是否在字段、getter或setter上使用了@Transient注释来映射lastAccessed?(假设您正在使用注释来映射您的域对象。)
如果您能提供一个SSCCE,我敢打赌我或其他人可以给您一个明确的答案。
更新:将完整应用程序缩小到最小可能的代码很难。结果是,当您这样做时,您可能会找到答案。我在github上有很多示例项目,如果您只需要一些正确方向的提示,它们可能会帮助您。其中basic-springmvc可能最接近您所做的事情,但它使用注释而不是xml进行映射。它还是一个Spring MVC项目。手动启动Spring上下文比担心整个servlet容器和Spring MVC想要您拥有的多个上下文要简单得多。例如,spring-method-caching就有一个这样的示例。
至于您发布的映射,看起来很好,但是我已经很久没有接触过XML映射了。您使用字段还是属性访问?这可能会对事情产生影响。此外,是否有任何自定义侦听器拦截器在SessionFactory中可能会干扰您的对象?

1
正如我在对你的回答中所解释的那样,你并没有理解Hibernate的工作原理。无论何时调用save()都是无关紧要的。 - Ryan Stewart
@RyanStewart:我已经将我的 Hibernate 映射添加到问题中。我确定 do.date 被存储了,而 do.lastAccessed 仍然是 NULL。字段或 [gs]etter 上没有 Transient 注释。我将努力提供一个 SSCCE,但由于这是一个企业 Spring 应用程序,可能会很困难。您有没有关于为 Spring 设置 SSCCE 的技巧?谢谢! - Eric
@RyanStewart:我已经开始在这里设置一个SSCCE:https://github.com/eschmidt/dateobject然而,当我尝试将此应用程序部署到Glassfishv3时,我会收到以下异常:Exception while invoking class com.sun.enterprise.web.WebApplication start method : java.lang.Exception: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: java.lang.IllegalArgumentException: java.lang.ClassNotFoundException: org.spring.framework.web.context.ContextLoaderListener你知道为什么它似乎找不到spring-web jar吗? - Eric
容器没有问题。类名错误了。应该是 org.springframework,而不是 org.spring.framework - Ryan Stewart
@RyanStewart:哇,多一双眼睛确实很有帮助,谢谢!现在我可以重新专注于真正的问题了... - Eric
显示剩余4条评论

0
您正在使用 IDENTITY 生成策略生成标识符,因此此处的 save() 调用立即转换为插入。在此之后是否会执行任何 INSERT/UPDATE/DELETE SQL?如果没有,那么很可能是会话未被刷新。如果您不熟悉,请阅读有关刷新的文档,以确定刷新可能发生的几个时间点。

我尝试显式调用sessionFactory.getCurrentSession().flush(),但仍无法保存到数据库。如果我在日志中搜索LAST_ACCESSED,会返回46行。然而,查看SQL的最后几行,我看到一个“create table”,一个“select”,一个“insert”(但它只显示(?,?),所以我不确定它正在插入什么 - 我假设这是第一次保存),和一个“select”。我不确定为什么“create table”似乎来得这么晚... - Eric
如果您想查看Hibernate绑定到那些PreparedStatement参数,可以启用日志类别org.hibernate.type(Hibernate 3)或org.hibernate.type.descriptor.sql.BasicBinder(Hibernate 4)以TRACE级别记录。 - Steve Ebersole
但是在这里,我期望的是INSERT后跟着UPDATE。就像我上面提到的,你正在使用IDENTITY,所以当你调用save()时,Hibernate必须立即执行INSERT。 - Steve Ebersole
谢谢你的日志记录提示。我回到家后会启用它来处理。听起来日志中的SQL与应用程序中发生的情况相符(保存第一个日期,但不是第二个)。除了刷新会话为什么不写入数据库,还有其他想法吗? - Eric
我不会说它“只保存第一个日期,而不是第二个日期”。它在插入时保存两个日期。只是在插入时,“上次访问”的值为空,所以这就是写入的内容。是的,你需要找出为什么在此之后实体更改(设置“上次访问”)没有被处理并且没有转换为更新。你最好切换标识符生成器。IDENTITY生成与ORM结合使用还有其他限制性问题,我通常建议不要使用它。 - Steve Ebersole
我的底层数据库目前是MySQL。我原以为在MySQL中自动生成主键需要使用IDENTITY关键字,但这不是真的吗?如果不是,你有什么其他建议呢? - Eric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接