Я пытаюсь сохранить состояние для нескольких вызовов, используя EXTENDED_PERSISTENT_CONTEXT. Насколько я понимаю, управляемые объекты не будут отсоединяться между вызовами, однако я продолжаю получать ошибки, связанные с отсоединенными объектами в вызовах, после того, как я ранее выдавал ошибки проверки. Состояние сохраняется в сеансовом компоненте с отслеживанием состояния:
@Named(SessionFacadeBean.SEAM_NAME)
@SessionScoped
@Stateful
@LocalBean
@AccessTimeout(value = 10, unit = TimeUnit.SECONDS)
public class SessionFacadeBean implements Serializable
{
public static final String SEAM_NAME = "sessionCacheBean";
@PersistenceContext(unitName = GlobalParameters.BACKEND_CODE_PERSISTENCE_CONTEXT_NAME, type = PersistenceContextType.EXTENDED)
private EntityManager em;
private ParentOne sessionData;
public synchronized ParentOne getSessionData() {
if(sessionData == null) {
sessionData = new ChildTwo();
}
return sessionData;
}
public boolean getLock() {
return true;
}
public void clearLock() {
}
// Other stuff I don’t ‘think’ is relevant.
}
(Упрощенное) состояние сохраняется с использованием спящего режима. Он состоит из трех классов (родительский и два дочерних, один из которых содержит список дочерних элементов):
@XmlRootElement(name = XMLConstants.COMPONENT_ELEMENT_NAME_IN_XML)
@XmlAccessorType(XmlAccessType.NONE)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "Class", length = 50)
@Entity
public class ParentOne
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@XmlElement(name = "ID")
private Long iD;
@XmlElement(name = "name")
protected String friendlyName = "";
}
@XmlRootElement(name = XMLConstants.COMPONENT_ELEMENT_NAME_IN_XML)
@XmlAccessorType(XmlAccessType.NONE)
@Entity
public class ChildOne extends ParentOne
{
public ChildOne(String name, ParentOne child) {
super(name);
myChild = child;
}
@ManyToOne(cascade = CascadeType.ALL)
protected ParentOne myChild;
}
@XmlRootElement(name = XMLConstants.COMPONENT_ELEMENT_NAME_IN_XML)
@XmlAccessorType(XmlAccessType.NONE)
@Entity
public class ChildTwo extends ParentOne
{
public ChildTwo() {
super(“common”);
}
}
Я обращаюсь к bean-компоненту с состоянием из bean-компонента без сохранения состояния следующим образом:
@Stateless
@LocalBean
@Path("/")
public class MyService
{
@PersistenceContext(unitName = GlobalParameters.BACKEND_CODE_PERSISTENCE_CONTEXT_NAME)
private EntityManager em;
@Inject
private SessionFacadeBean sessionBean;
@POST
@Path("/create/item")
@ValidateRequest
public ComponentShortSummary addItem(@Form NewItemForm itemForm)
{
if(sessionBean.getLock()) {
try {
if(itemForm.getName().equals("INVALID") == true) {
throw new ConstraintViolationException("Failed", new HashSet<ConstraintViolation<?>>());
}
ChildOne child = new ChildOne(itemForm.getName(), sessionBean.getSessionData());
em.persist(child);
return null;
}
finally {
sessionBean.clearLock();
}
} else {
return null;
}
}
}
Чтобы воспроизвести проблему, я выполняю следующую последовательность:
- Вызовите addItem с допустимым именем (это сохранит элемент в базе данных).
- Вызовите addItem с именем «INVALID», это вызовет исключение ограничения.
- Вызовите addItem с допустимым именем (это приводит к ошибке отсоединенной сущности в строке
em.persist(child)
.
Чего я не понимаю, так это того, как/почему я оказался с отсоединенными сущностями. В реальном коде я бы выполнял некоторую проверку запроса/состояния перед изменением состояния (поэтому я не вижу причин, по которым состояние было бы отсоединено).
Если я уберу вызов sessionBean.getLock()
, проблема исчезнет (объекты сохраняются правильно). Целью методов блокировки, по сути, является сериализация доступа к состоянию сеанса, однако в настоящее время метод getLock()
пуст, похоже, проблема может быть связана с тем фактом, что я вызываю bean-компонент с состоянием перед тем, как выдать исключение.
Может ли кто-нибудь объяснить, что происходит, что приводит к тому, что мои объекты становятся отсоединенными / если есть способ избежать этого (и в идеале указать мне на любую документацию, подтверждающую объяснение)?
Хотя, вероятно, есть способы обойти текущую проблему, выполняя проверку перед доступом к компоненту с отслеживанием состояния вообще, меня беспокоит общий случай (где любое исключение генерируется после обращения к компоненту с отслеживанием состояния в вызове). Существует ли общепринятая стратегия работы с исключениями, когда я не хочу, чтобы объекты из расширенного постоянного контекста были отсоединены?