JPA Entity не обновляется правильно - PullRequest
1 голос
/ 13 февраля 2012

Я использую JPA2 с реализацией Eclipselink на Glassfish 3.

У меня есть простое приложение для входа / выхода.

Это бины сущностей и их отображения:

@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.Все методы работают нормально, но проблема в том, что иногда объект Entity, сохраненный в контексте Persistance / JPA Cache, не синхронизируется с информацией базы данных.

В качестве конкретного примера, когда я удаляю некоторые пользовательские данные (из таблицы user_detail) запись базы данных удаляется, но когда я снова читаю информацию, возвращаемая сущность все еще имеет информацию Details.Я предполагаю, что эта информация была сохранена в кеше 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 Ответ

1 голос
/ 13 февраля 2012

Читая комментарии, я вижу, что вы используете application-managed транзакции.Как указано в Учебное пособие по Java EE ,

Менеджеры объектов, управляемых приложениями, не распространяют автоматически контекст транзакции JTA.Такие приложения должны вручную получить доступ к диспетчеру транзакций JTA и добавить информацию о разграничении транзакций при выполнении операций объекта.Интерфейс javax.transaction.UserTransaction определяет методы для запуска, фиксации и отката транзакций.Внедрите экземпляр UserTransaction, создав переменную экземпляра с аннотацией @Resource ...

Из опубликованного вами кода вы не разграничиваете транзакцию, которая удаляет запись UserDetail.Кроме того, вы не показали код, который используете для получения ссылки на EntityManager.Вам следует придерживаться того же учебника и использовать

em = emf.createEntityManager();

для получения обновленного экземпляра Entity Manager.

В противном случае переключитесь на Container-Managed транзакции, которые значительно упрощают жизнь в большинствеситуации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...