为什么HibernateTemplate.merge()会毫无例外地完成但不会保留数据?

时间:2016-10-27 20:36:30

标签: java spring hibernate

我想在不提交大量代码和配置示例的情况下尽可能使这个问题变得通用,这样答案提交者可以涵盖广泛的可能性,因此可以在某种程度上使用#34;学术性和#34;。

我有两个实体类FooBar。它们连接到持久性存储(在我的情况下为PostgreSQL,但我认为这不重要)使用JPAHibernate作为提供者。它们分别由FooDaoBarDao管理,两个DAO都扩展了BaseDao,其中包含一个保存方法:

public T save(T object)
{

    return (T) hibernateTemplate.merge(object);
}

这两个DAO都不会覆盖(意味着它们按原样使用超类方法)。

问题是,当我调用myFooDao.save(myFoo)时,它实际上会将对象持久存储到数据库中,但是当我调用myBarDao.save(myBar)时,对象不会持久存在,没有例外是

所有这些都在Spring上下文之外,两个DAO都是injected。我还应该添加两个表,每个主键都绑定到自己的序列。虽然Bar插入实际上从未实际持久化,但相关序列每次都会增加,这很奇怪。因此,Hibernate确实准备了一个事务,但从序列中获取了下一个值,这会增加序列,但新行永远不会显示在数据中。

我希望探讨一些可能发生异常情况的一般情况。首先,是否可以设置配置以便Foo自动提交但Bar不是,我应该深入了解上下文配置以找出差异?或者可能是Hibernate认为写入成功提交,因为数据库引擎没有正确报告失败?

2 个答案:

答案 0 :(得分:1)

每次更新查询后,Hibernate不一定会保留您的更改(例如saveOrUpdatemerge)。

它对持久性的行为是由与你的HibernateTemplate绑定的Session的FlushMode定义的。可能的FlushModes在此处描述:https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/FlushMode.html

默认情况下,Hibernate会话设置为FlushMode.AUTO。这意味着,如果不是绝对地并且通过以下查询显然需要(为了保持数据库一致性),除了通过迭代序列分配id之外,不会进行持久性更改。

这是你观察到的结果。

要回答您的问题,如果您想在合并后立即保留更改,则需要:

1)在合并之前(或者在实现HibernateTemplate时),将与HibernateTemplate相关联的Session的刷新策略更改为“ALWAYS”。

hibernateTemplate.setFlushModeName("FLUSH_ALWAYS");

2)合并后显式刷新会话。

hibernateTemplate.flush();

但是你还应该注意,HibernateTemplate是一种不推荐使用Hibernate与数据库交互的方法,特别是因为HibernateTemplate不能引导人们正确处理数据库事务。

首先,当事务以FlushMode.AUTO提交时,事务中使用的合并将自动保留。

在Spring应用程序中,您可以使用@Transactional注释,它通过事务隐式执行带注释方法中包含的所有逻辑。

@Autowired
private SessionFactory sessionFactory;

@Transactional
public void doUpdate(Object myObject) {
  Session hibSession = sessionFactory.getCurrentSession();
  hibSession.merge(myObject);
}

在此处查看有关Spring事务管理的完整说明:http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html(@Transactional注释的16.5.6段)。

答案 1 :(得分:1)

合并时您的实体的状态是什么?如果实体处于持久性上下文(例如会话)中,则如果对对象进行了任何更改,则将发生更新。 (如果没有变化,Hibernate将悄然忽略合并。)

如果实体不在持久化上下文中,但它存储在数据库中,那么将插入一个新行,因此您将重复。

另外,请确保您为实体实施 self.dismiss(animated: false) let newViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "viewController2") UIApplication.topViewController()?.present(newViewController, animated: true, completion: nil) equals()方法。