【问题标题】:EntityManager.merge not doing anythingEntityManager.merge 没有做任何事情
【发布时间】:2012-01-31 03:11:33
【问题描述】:

我有一个用户实体:

@Entity
@Table( name = "bi_user" )
@SequenceGenerator( name = "USER_SEQ_GEN", sequenceName = "USER_SEQUENCE" )
public class User
        extends DataObjectAbstract<Long>
{
    private static final long serialVersionUID = -7870157016168718980L;

    /**
     * key for this instance. Should be managed by JPA provider.
     */
    @Id
    @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GEN" )
    private Long key;

    /**
     * Username the user will use to login.  This should be an email address
     */
    @Column( nullable=false, unique=true)
    private String username;

    // etc. other columns and getters/setters
}

其中 DataObjectAbstract 是一个简单的 @MappedSuperClass,它具有 jpa 版本和 equals/hashcode 定义。

我有一个看起来像这样的基础 dao 类

public abstract class BaseDaoAbstract<T extends DataObject<K>, K extends Serializable>
        implements BaseDao<T, K>
{

    @PersistenceContext
    private EntityManager em;

    /**
     * Save a new entity. If the entity has already been persisted, then merge
     * should be called instead.
     * 
     * @param entity The transient entity to be saved.
     * @return The persisted transient entity.
     */
    @Transactional
    public T persist( T entity )
    {
        em.persist( entity );
        return entity;
    }

    /**
     * merge the changes in this detached object into the current persistent
     * context and write through to the database. This should be called to save
     * entities that already exist in the database.
     * 
     * @param entity The entity to be merged
     * @return The merged entity.
     */
    @Transactional
    public T merge( T entity )
    {
        return em.merge( entity );
    }

    // other methods like persist, delete, refresh, findByKey that all delegate to em.
}

我在 web.xml 中定义了 OpenEntityManagerInView 过滤器如下

<filter>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <filter-class>
        org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>biEmf</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

我最近升级到 eclipselink 2.3.2 和 Spring 3.1 并从 CGLIB 代理转换为 Spring 使用 aspectJ 的 Load Time Weaving,但我没有为 eclipselink 配置 LTW。

问题出在这段代码中,它位于 spring ApplicationListener 中,请参阅 cmets。

        User user = userService.findByKey(userDetails.getKey());

        // THIS MERGE NEVER WRITES THROUGH TO THE DATABASE.
        // THIS DOESN'T WORK AS PERSIST EITHER
        user = userService.merge( user.loginSuccess() );

user.loginSuccess 只是设置了一些字段并返回this 我确定它正在通过代码,因为我在它周围得到了日志语句,我可以设置一个断点并遍历它。我的 postgres 日志没有显示任何流量到达 postgres 以进行合并。

我在所有地方都保存了其他内容,包括更改密码时位于其他位置的用户,而且我知道这段代码曾经可以工作。这里有什么明显的不对吗?我是否错误地使用了 OpenEntityManagerInViewFilter?我是否需要使用@Transactional 方法才能将实体视为托管?任何帮助表示赞赏。

更新 我按照prajeesh的建议尝试了冲洗。这是代码

@Transactional
public T merge( T entity )
{
    entity = em.merge( entity );
    em.flush();
    return entity;
}

com.bi.data 的一个班级里。我的 spring 应用程序配置文件中有这个

<context:component-scan base-package="com.bi.controller,com.bi.data,com.bi.web" />

在我的 spring 配置中,我有

<context:load-time-weaver/>
<tx:annotation-driven mode="aspectj"/>    

使用如下所示的 aop.xml:

<aspectj>
    <weaver>
        <!-- only weave classes in our application-specific packages -->
        <include within="com.bi..*"/>
    </weaver>
</aspectj>

我得到了一个

javax.persistence.TransactionRequiredException: 
Exception Description: No transaction is currently active

那么显然有些地方配置错误,但是什么?

更新 2: 我恢复了我的更改以启用加载时间编织,现在合并在有或没有刷新的情况下进行,但我仍然不明白 LTW 的问题是什么......

【问题讨论】:

  • 您的事务似乎配置正确。也许包括您的 persistence.xml,确保您使用的是 RESOURCE_LOCAL。启用最好的登录以查看发生了什么。
  • 感谢詹姆斯的想法。我下班后看看。我很确定我们正在使用 RESOURCE_LOCAL,因为我们在 tomcat 中运行,所以 JTA 从来没有。
  • 您是否尝试将propagation=Propagation.REQUIRED 添加到@Transactional 注释中?
  • 我没试过。我在问题的更新 2 中进行了更改,并且没有回头。

标签: java spring jpa eclipselink


【解决方案1】:

em.merge() 之后也可以尝试em.flush()。有时EntityManager 只是保留更改以供以后更新。

【讨论】:

    【解决方案2】:

    EntityManager 自动提交为假。请使用如下交易;

    EntityManager em = null;
    EntityTransaction t = null;
    try {
        em = emf.createEntityManager();
        t = em.getTransaction();
        t.begin();
        em.merge(myTestObject);
        t.commit();
    } catch (Exception e) {
        t.rollback();
        throw new RuntimeException(e.getMessage());
    }finally{
        if(em != null)
            em.close();
    }
    

    【讨论】:

    • 我正在使用 jpa,它不允许 em.getTransaction(),
    • 有时 JPA 在路径中找不到 persistence.xml 文件。你的persistence.xml 路径在哪里?如果您的 em 为 null,请将 persistence.xml 移至 src/main/java/META-INF/persistence.xml
    【解决方案3】:

    我遇到了这个问题,并通过更改范围得到了解决。

    @PersistenceContext(type=PersistenceContextType.EXTENDED)
    

    参考:Manipulating Entities with EntityManager

    【讨论】:

    • 我在一个大项目中搜索了这个解决方案几个月,谢谢!
    【解决方案4】:

    transaction.begin()transaction.end() 方法在哪里?在 RESOURCE_LOCAL 中,您应该管理事务而不是应用程序...

    【讨论】:

      【解决方案5】:

      检查你的 Spring 配置文件中是否有以下行: 这启用了@Transactional 注释支持,并确保设置了 mode="proxy", not mode="aspectj"

      【讨论】:

        猜你喜欢
        • 2012-09-07
        • 2016-10-02
        • 2013-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多