JPA实体未正确更新

时间:2012-02-12 23:00:12

标签: java jpa

我在Glassfish 3上使用JPA2和Eclipselink实现。

我有一个简单的登录/注销应用程序。

这些是实体bean的映射:

@Entity
@Table(name = "user_account")
public class UserAccount implements Serializable{
    @Id
    private Integer id;
    private String email;
    private String password;
    private Integer role;

    @OneToOne(fetch=FetchType.EAGER)
    @PrimaryKeyJoinColumn
    private UserDetail userDetail;

    // get+set
}

@Entity
@Table(name = "user_detail")
public class UserDetail implements Serializable{
    private static final long serialVersionUID = 1L;
    @Id
    private Integer id;
    @Temporal(TemporalType.DATE)
    private Date birth;
    @Column(name="origin_city")
    private String originCity;
    @Column(name="residence_city")
    private String residenceCity;
    private String description;

    @OneToOne(mappedBy="userDetail")
    private UserAccount userAccount;
}

UserService课程中,我有一个简单的CRUD实现。所有方法都运行得很好,但问题是有时保存在Persistance Context / JPA Cache中的Entity Object不会与数据库信息同步。

作为一个具体的例子,当我删除一些用户详细信息(来自user_detail表)时,数据库条目被删除,但是当我再次读取信息时,返回的实体仍然具有详细信息。我猜这个信息保存在JPA缓存中,然后在没有先检查数据库的情况下返回。

这是正确的行为吗?有没有办法使缓存信息与数据库保持同步?

LE :用户服务包含调用帮助程序方法的read(email, password)方法。此帮助程序方法包含CriteriaAPI查询,该查询为所有用户提供所需的电子邮件和密码。 Criteria查询已经过测试,工作正常。

public UserAccount read(String email, String password){
    List<UserAccount> userList = getUserList(null, email, password, Constants.RESULT_SINGLE);
    return (userList.isEmpty() ? null : userList.get(0));
}

private List<UserAccount> getUserList(Integer id, String email, String password, String resultType){
    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<UserAccount> shell = builder.createQuery(UserAccount.class);
    Root<UserAccount> entity = shell.from(UserAccount.class);
    shell.select(entity);
    shell.distinct(true);
    List<Predicate> predicateList = new ArrayList<Predicate>();
    if (id != null){
        ParameterExpression<Integer> param = builder.parameter(Integer.class, "id");
        predicateList.add(builder.equal(entity.get("id"), param));
    }
    if (email != null){
        ParameterExpression<String> param = builder.parameter(String.class, "email");
        predicateList.add(builder.equal(entity.get("email"), param));
    }
    if (password != null){
        ParameterExpression<String> param = builder.parameter(String.class, "password");
        predicateList.add(builder.equal(entity.get("password"), param));
    }

    if (predicateList.size() == 1){
        shell.where(predicateList.get(0));
    } else {
        Predicate[] p = new Predicate[predicateList.size()];
        p = predicateList.toArray(p);
        shell.where(builder.and(p));
    }   
    TypedQuery<UserAccount> selectQuery =  em.createQuery(shell);
    if (id != null) selectQuery.setParameter("id", id);
    if (email != null) selectQuery.setParameter("email", email);
    if (password != null) selectQuery.setParameter("password", password);

    return selectQuery.getResultList();
}

这是服务的删除方法:

public boolean deleteDetail(Integer userId) {
    boolean ok = true;
    try {
        UserDetail userDetails = em.find(UserDetail.class, userId);
        System.out.println("Trying to delete the detail. The address of the object is: " + userDetails);
        em.remove(userDetails);
        System.out.println("Object deleted. The address is: " + userDetails);
    } catch (Exception e) {
        e.printStackTrace();
        ok = false;
    }

    return ok;
}

1 个答案:

答案 0 :(得分:1)

阅读评论我发现您正在使用application-managed次交易。如Java EE Tutorial中所述,

  

应用程序管理的实体管理器不会自动传播   JTA事务上下文。此类应用程序需要手动获取   访问JTA事务管理器并添加事务划分   执行实体操作时的信息。该   javax.transaction.UserTransaction接口定义要开始的方法,   提交和回滚事务。注入一个实例   UserTransaction通过创建用注释注释的实例变量   @Resource ...

根据您发布的代码,您没有划分删除UserDetail记录的事务。此外,您尚未显示用于获取EntityManager引用的代码。你应该坚持使用相同的教程并使用

em = emf.createEntityManager();

获取实体管理器的更新实例。

否则,切换到Container-Managed交易,这些交易可以在大多数情况下简化生活。