JPA:persist()未在数据库中创建实体

时间:2015-08-17 14:16:19

标签: java hibernate postgresql jpa

代码

我的实体定义如下:

@Entity(name="setting")
@NamedQueries({ 
    @NamedQuery(name=JpaSetting.FIND_BY_NAME,
                query="SELECT s FROM setting s WHERE s.name = :name"),
})
public class JpaSetting {

    // CONSTANTS \\
    protected static final String FIND_BY_NAME = "JpaSetting.findByName";
    protected static final String NAME_ATTR = "name";

    // FIELDS \\
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id")
    private int m_id;

    @Column(name="name", nullable=false, unique=true)
    private String m_name;

    @Column(name="value")
    private String m_value;

    /* Classic getters and setters here... */
}

服务是:

public class SettingsService {
    @PersistenceContext(type=PersistenceContextType.EXTENDED)
    private EntityManager m_em;


    private JpaSetting retrieveSetting(String p_name)
    throws NoResultException {
        return m_em.createNamedQuery(JpaSetting.FIND_BY_NAME, JpaSetting.class)
            .setParameter(JpaSetting.NAME_ATTR, p_name)
            .getSingleResult();
    }

    @Transactional
    public void save(String p_name, String p_value) {
        try {
            m_em.merge(
                retrieveSetting(p_name).setValue(p_value) );
        }
        catch (NoResultException e) {
            m_em.persist(
                new JpaSetting().setName(p_name).setValue(p_value) );
        }
    }
}

问题:save()方法中,m_em.persist()不会在数据库中创建实体。生成实体的id(通过调试确认),我可以在Hibernate日志中看到select nextval('sequence')请求,但是没有创建请求。

setting存在(使用生成的ddl创建),现在为空。我可以使用psql客户端插入和删除设置,并使用与应用程序使用的帐户相同的帐户。

没有抛出任何异常,一切似乎都正常工作。 除了实体没有坚持。

我在同一个应用程序中使用了另一个实体/服务(使用相同的持久性单元)persist()有效,但我找不到明显的区别。

修改 我只是试图在数据库中创建记录以检查merge情况,但它也不起作用。所以,这是一个更普遍的问题,但我不知道它在哪里。

2 个答案:

答案 0 :(得分:1)

我找到了。

事实证明,save()方法是由同一个类的另一个方法调用的, 没有用@Transactional注释。

当我使用默认拦截模式proxy时,所述代理无法拦截从非事务方法到@Transactional的调用。因此,没有使用任何事务,并且提交从未发生过。

我通过将@Transactional添加到类本身来解决它,因为它的所有公共方法都应该是事务性的。

答案 1 :(得分:0)

我不知道持久性是如何起作用的,try{ m_em.merge在JPA过程中会产生异常。该异常很可能EJBTransactionRollback与当前JPA堆栈关联的任何查询。

由于JPA不立即提交事务(它们是在最佳时间由提供者确定的稍后时间提交的),这就是为什么你看到它在调试模式下生成一个id的原因(虽然它永远不会被提交。)没有抛出异常的原因是因为你在JPA关闭事务时超出范围然后抛出EJBTransactionRollback;在flush()之后添加persist()将导致事务正确提交。您应该在此时看到回滚发生并抛出异常。

如果我是你,使用save()方法,我会使用您的retrieveSetting()查询,如果没有结果,则persist()。我认为问题在于将persist()放在catch块中,您不能期望回滚一个事务查询,并且提交同一事务中的另一个查询。