gpt4 book ai didi

java - 当对象不在持久性上下文中时,Hibernate 合并不查询数据库

转载 作者:搜寻专家 更新时间:2023-11-01 03:54:42 25 4
gpt4 key购买 nike

我正在使用:

  1. Spring 3.1
  2. Spring 数据 JPA 1.1
  3. hibernate 4.1

我有一个问题。我有一个标准的 Spring Data JPA DAO:

public interface DnarDao extends JpaRepository<Dnar, Long> {
// insert Spring Data magic here!
}

这是 Dnar 代码:

@Entity
@Table(name="req_dnar", schema=SCHEMA)
@Inheritance(strategy=JOINED)
@DiscriminatorColumn(name="form_type", discriminatorType=STRING, length=64)
public abstract class Dnar {

@Id
@GeneratedValue(strategy=SEQUENCE, generator="dnar_gen_seq")
@SequenceGenerator(name="dnar_gen_seq", sequenceName="req_dnar_seq")
@Column(name=C_DNAR_ID, nullable=false)
private Long dnarId;

@Column(name="form_type", nullable=false, length=64)
@Enumerated(EnumType.STRING)
private FormType formType;
// remainder omitted
}

还有一个实现类的例子:

@Entity
@Table(name="req_dnar_general_lv")
@DiscriminatorValue("GENERAL_LV")
public class GeneralLvDnar extends Dnar {
//remainder omitted
}

另外,这是我的 Hibernate 东西的 Spring 配置:

<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
<property name="uRL" value="${JDBC_URL}"/>
<property name="user" value="${USER_ID}"/>
<property name="password" value="${PASSWORD}"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list><value>com/mycomp/domain</value></list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.id.new_generator_mappings">true</prop>
</props>
</property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<jpa:repositories base-package="com.mycomp.dao" />

<tx:annotation-driven />

第 1 轮 - 问题

DAO 的客户端是 DnarManagerImpl 类:

@Transactional
@Override
public Dnar save(final Dnar dnar) {

Dnar managedDnar = dnarDao.save(dnar);
return managedDnar;
}

上面的代码有效,但它总是在数据库中创建一个新的dnar 行。我已经调试了 Spring Data JPA 代码,它似乎工作正常。例如,如果我保存同一个对象 3 次,Hibernate 调用是:

  1. getSession().persist(entity);
  2. getSession().merge(entity);
  3. getSession().merge(entity);

Hibernate 为上述输出的 SQL 是:

  1. 插入...
  2. 插入...
  3. 插入...

第 2 轮 - 黑客修复

通过一些实验,我发现我可以通过使用 dnarDao.findOne(id); 告诉当前 session 这个实体存在。这解决了我的问题:

@Transactional
@Override
public Dnar save(final Dnar dnar) {

// Hack to get the Dnar in the current persistence context
if (dnar.getDnarId() != null) {
dnarDao.findOne(dnar.getDnarId());
}
Dnar managedDnar = dnarDao.save(dnar);
return managedDnar;
}

同样,Hibernate session 调用是:

  1. getSession().persist(entity);
  2. getSession().merge(entity);
  3. getSession().merge(entity);

Hibernate 输出的 SQL 现在是正确的:

  1. 插入...
  2. 更新...
  3. 更新...

问题

根据Hibernate docs ,这就是 merge() 的工作原理:

  1. 如果当前存在与持久性上下文关联的具有相同标识符的托管实例,则将给定对象的状态复制到托管实例上
  2. 如果当前没有与持久化上下文关联的托管实例,尝试从数据库加载它,或者创建一个新的托管实例
  3. 返回托管实例
  4. 给定的实例不会与持久化上下文相关联,它保持分离状态并且通常被丢弃

显然,在我的示例中,第 2 项没有发生。 Hibernate 没有尝试从数据库中加载这个实体。 Hibernate 从不 输出选择(我的 hack 修复中的异常)。 Sooo ....我哪里错了?我确信 Hibernate 确实按照文档工作,只是我做了一些愚蠢的事情。

最佳答案

查看这段代码:

@Transactional
@Override
public Dnar save(final Dnar dnar) {
Dnar managedDnar = dnarDao.save(dnar);
return managedDnar;
}

如果您想保存一个新创建的对象,我认为您实际上是在做正确的事情。但是,如果您只是修改现有的,则应使用更新。如果您从 session 中获得了那个 dnar 实例,您就知道它存在(至少在 session 范围内),因此您可以只对其使用更新。如果您自己创建了对象并想将其保存在数据库中,则应使用 save。

有一个名为“saveOrUpdate”的大量方法调用可以为您处理这个问题,它会尝试通过调用先前不在数据库中的保存(基于标识符的缺失)来持久化一个实体,或者如果您的实体有 ID,将调用更新。假设您的 dao 中有 saveOrupdate,那么您的代码将更改为此。这是描述行为的 SO 中的一个很好的答案:

Hibernate saveOrUpdate behavior

@Transactional
@Override
public Dnar save(final Dnar dnar) {
Dnar managedDnar = dnarDao.saveOrUpdate(dnar);
return managedDnar;
}

关于java - 当对象不在持久性上下文中时,Hibernate 合并不查询数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11856731/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com