java - JPA 实体未正确更新

标签 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 实现。所有方法都工作得很好,但问题是有时保存在持久性上下文/JPA 缓存中的实体对象与数据库信息不同步。

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

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

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;
}

最佳答案

阅读评论后,我发现您正在使用应用程序管理事务。如 Java EE Tutorial 中所述,

Application-managed entity managers don’t automatically propagate the JTA transaction context. Such applications need to manually gain access to the JTA transaction manager and add transaction demarcation information when performing entity operations. The javax.transaction.UserTransaction interface defines methods to begin, commit, and roll back transactions. Inject an instance of UserTransaction by creating an instance variable annotated with @Resource...

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

em = emf.createEntityManager();

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

否则,请切换到容器管理事务,这在大多数情况下都会使生活变得更加简单。

关于java - JPA 实体未正确更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9253521/

相关文章:

java - Android - 具有形状可绘制对象和以编程方式渐变的自定义按钮

java - 我们如何将可调用对象转换为可运行对象

java - 通过按钮使imageView可见和不可见

java - OData V4 中的双向导航

jpa - 休眠 jpa 单元测试自动检测不起作用

java - Maven JAXB 插件只执行一次

jpa - 使用 Eclipselink/JPA 更改实体类型?

java - 连接失败的 JPQL createNativeQuery

java - Hibernate和Spring数据jpa同时使用?

java - 每个实体的 DTO 对象