I'm trying to maintain state across multiple calls by using an EXTENDED_PERSISTENT_CONTEXT. My understanding is that managed entities will not detach between calls however I keep getting errors related to detached entities in calls after I have previously thrown validation errors. The state is being maintained in a stateful session bean:
#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.
}
The (simplified) state is being stored using hibernate. It consists of three classes (a parent, and two children, one of which contains a list of children):
#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”);
}
}
I’m accessing the stateful bean from a stateless bean like so:
#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;
}
}
}
To reproduce the problem, I perform the following sequence:
Call addItem with a valid name (this persists the item to the database).
Call addItem with a name ‘INVALID’, this throws the constraint exception.
Call addItem with a valid name (this results in a detached entity error on the line em.persist(child).
What I don’t understand is how/why I’m ending up with detached entities. In the real code, I would be performing some request / state validation, before modifying the state (so there is no reason that I can see for the state to have been detached).
If I remove the call to sessionBean.getLock() then the problem goes away (the objects persist correctly). The purpose of the lock methods is essentially to serialize access to the session state, however currently the getLock() method is empty, it feels like the problem might be related to the fact that I’m calling into the stateful bean before throwing the exception.
Can anybody explain what’s going on that results in my entities becoming detached / if there is a way to avoid it (and ideally point me at any documentation that supports the explanation)?
Whilst there are probably ways that I can work around the current issue, performing validation before accessing the stateful bean at all, I’m concerned about the general case (where any exception is thrown after the stateful bean has been accessed in the call). Is there an accepted strategy for dealing with exceptions when I don’t want the entities from the extended persistent context to be detached?
It looks like this is expected behaviour. Thanks to Scott Marlow's reference to the JPA spec, section 3.3.2.
Transaction Rollback
For both transaction-scoped and extended
persistence contexts, transaction rollback causes all pre-existing
managed instances and removed instances[31] to become detached. The
instances’ state will be the state of the instances at the point at
which the transaction was rolled back. Transaction rollback typically
causes the persistence context to be in an inconsistent state at the
point of rollback. In particular, the state of version attributes and
generated state (e.g., generated primary keys) may be inconsistent.
Instances that were formerly managed by the persistence context
(including new instances that were made persistent in that
transaction) may therefore not be reusable in the same manner as other
detached objects—for example, they may fail when passed to the merge
operation.[32]
So, entities that are involved in the active transaction are detached when the transaction is rolled back and by calling out to the sessionBean I am involving it in the transaction.
One way around this appears to be to decorate acceptable exceptions with the #AppicationException annotation. This marks the exception as non-fatal and prevents the transaction from being rolled back. This approach is described in some detail by David Blevin.
Related
I am updating my application from Spring Boot 1.4.5 / Hibernate 4.3.5 to Spring Boot 2.0.9 / Hibernate 5.2.18 and code that used to work in the previous configuration is no longer working.
The scenario is as follows:
Start a transaction by entering a method annotated with #Transactional
Hydrate the entity
Change the entity
Make another query
Detect a problem. As a result of this problem, determine that changes should not persist.
Evict the entity
Exit the method / transaction
With Hibernate 4.3.5, calling entityManager.detach() would prevent the changes from being persisted. However, with Hibernate 5.2.18, I'm finding that changes are persisted even with this call. I have also tried to evict() from the session and I have tried to clear() all entities from the session (just to see what would happen).
So I ask - is it possible to discard entity changes in Hibernate 5.2.18 the way that I was able to do in Hibernate 4.3.5?
The relevant code is below...
#Entity
public class Agreement {
private Long agreementId;
private Integer agreementStateId;
#Id
#Column(name = "agreement_id")
public Long getAgreementId() {
return agreementId;
}
public void setAgreementId(Long agreementId) {
this.agreementId = agreementId;
}
#Basic
#Column(name = "agreement_state_id", nullable = false)
public Integer getAgreementStateId() {
return agreementStateId;
}
public void setAgreementStateId(Integer agreementStateId) {
this.agreementStateId = agreementStateId;
}
}
#Component
public class Repo1 {
#PersistenceContext(unitName = "rights")
private EntityManager entityManager;
public void evict(Object entity) {
entityManager.detach(entity);
}
public Agreement getAgreement(Long agreementId) {
// Code to get entity is here.
// Agreement with an agreementStateId of 5 is returned.
}
public void anotherQuery() {
// Code to make another query is here.
}
}
#Component
public class Service1 {
#Autowired
Repo1 repo;
#Transactional
public void doSomething() {
Agreement agreement = repo.getAgreement(1L);
// Change agreementStateId. Very simple for purposes of example.
agreement.setAgreementStateId(100);
// Make another query
repo.anotherQuery();
// Detect a problem here. Simplified for purposes of example.
if (agreement.getAgreementStateId() == 100) {
repo.evict(agreement);
}
}
}
I have found the problem and it has nothing to do with evict(). It turns out that an additional query was causing the session to flush prior to the evict() call.
In general, the application uses QueryDSL to make queries. Queries made in this way did not result in the session flushing prior to making a query. However in this case, the query was created via Session.createSQLQuery(). This uses the FlushMode already assigned to the session which was FlushMode.AUTO.
I was able to prevent the flush by calling setHibernateFlushMode(FlushMode.COMMIT) on the query prior to making the query. This causes the session FlushMode to temporarily change until after the query has been run. After that, the evict() call worked as expected.
Consider the following situation:
We receive a request from a web service which updates our entity. Sometimes we might get two requests at (almost) the same time. We had situations in which our entity looked completely wrong, because of concurrent updates. The idea is to lock the entity pessimistic so that whenever the first request comes it instantly locks the entity and the second request can't touch it (Optimistic locking is no alternative for us). I wrote an integration test to check this behaviour.
I got an integration test which looks like the following:
protected static TestRemoteFacade testFacade;
#BeforeClass
public static void setup() {
testFacade = BeanLocator.lookupRemote(TestRemoteFacade.class, TestRemoteFacade.REMOTE_JNDI_NAME, TestRemoteFacade.NAMESPACE);
}
#Test
public void testPessimisticLock() throws Exception {
testFacade.readPessimisticTwice();
}
which calls the bean
#Stateless
#Clustered
#SecurityDomain("myDomain")
#RolesAllowed({ Roles.ACCESS })
public class TestFacadeBean extends FacadeBean implements TestRemoteFacade {
#EJB
private FiolaProduktLocalFacade produkt;
#Override
public void readPessimisticTwice() {
produkt.readPessimisticTwice();
}
}
with produkt being a bean itself
#Stateless
#Clustered
#SecurityDomain("myDomain")
#RolesAllowed({ Roles.ACCESS })
public class ProduktFacadeBean implements ProduktLocalFacade {
#Override
public void readPessimisticTwice() {
EntityManager entityManager = MyService.getCrudService().getEntityManager();
System.out.println("Before first try.");
entityManager.find(MyEntity.class, 1, LockModeType.PESSIMISTIC_WRITE);
System.out.println("Before second try.");
entityManager.find(MyEntity.class, 1, LockModeType.PESSIMISTIC_WRITE);
System.out.println("After second try.");
}
}
with
public class MyService {
public static CrudServiceLocalFacade getCrudService() {
return CrudServiceLookup.getCrudService();
}
}
public final class CrudServiceLookup {
private static CrudServiceLocalFacade crudService;
private CrudServiceLookup(){
}
public static CrudServiceLocalFacade getCrudService() {
if (crudService == null)
crudService = BeanLocator.lookup(CrudServiceLocalFacade.class, CrudServiceLocalFacade.LOCAL_JNDI_NAME);
return crudService;
}
public static void setCrudService(CrudServiceLocalFacade crudService) {
CrudServiceLookup.crudService = crudService;
}
}
#Stateless
#Local(CrudServiceLocalFacade.class)
#TransactionAttribute(TransactionAttributeType.MANDATORY)
#Interceptors(OracleDataBaseInterceptor.class)
public class CrudServiceFacadeBean implements CrudServiceLocalFacade {
private EntityManager em;
#Override
#PersistenceContext(unitName = "persistence_unit")
public void setEntityManager(EntityManager entityManager) {
em = entityManager;
}
#Override
public EntityManager getEntityManager() {
return em;
}
}
The problem that arises now is: If I start the integration test once with a breakpoint at System.out.println("Before second try."); and then start the integration test a second time, the latter one can still read MyEntity. Remarkable is that they were different instances (I made this observation on the instanceId in debug mode). This suggests that the entityManager didn't share his hibernate context.
I made the following observations:
Whenever I call a setter on entity and save it to the db, the lock is aquired. But this is not what I need. I need the lock without having modified the entity.
I tried the method entityManager.lock(entity, LockModeType.PESSIMISTIC_WRITE) as well, but the behaviour was the same.
I found Transaction settings in DBVisualizer. At the moment it is set to TRANSACTION_NONE. I tried all the others (TRANSACTION_READ_UNCOMMITTED, TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE) as well, without any success.
Let the first thread read the entity, then the second thread read the same entity. Let the first tread modify the entity and then the second modify it. Then let both save the entity and whoever saves the entity last wins and no exceptions will be thrown.
How can I read an object pessimistic, that means: Whenever I load an entity from the db I want it to be locked immediately (even if there was no modification).
Both ways you describe ie.
em.find(MyEntity.class, 1, LockModeType.PESSIMISTIC_WRITE)
em.lock(entity, LockModeType.PESSIMISTIC_WRITE)
hold a lock on the related row in database but only for the the entityManager lifespan, ie. for the time of the enclosing transaction, the lock will be so automatically released once you've reached the end of the transaction
#Transactional()
public void doSomething() {
em.lock(entity, LockModeType.PESSIMISTIC_WRITE); // entity is locked
// any other thread trying to update the entity until this method finishes will raise an error
}
...
object.doSomething();
object.doSomethingElse(); // lock is already released here
Have you tried to set the isolation level in your application server?
To get a lock on a row no matter what you are trying to do afterwards (read/write), you need to set the isolation level to TRANSACTION_SERIALIZABLE.
Lock fails only if another thread is already holding the lock. You can take two FOR UPDATE locks on single row in DB, so it's not JPA-specific thing.
A very simple use case implemented using DDD and java.
I have a FooEntity and a FooRepository. The Entity has a delete method which validates certain state to check whether it is safe to be deleted, and in case this evaluates to true invoke the delete in the repository, which is injected in the entity.
So far so good, but, what happens if somebody invokes the delete method directly in the repository? Then the validation wouldn't be performed.
Placing the validation in the repository would solve the problem, but this would be clearly wrong since it would make necessary to expose the internal state of the entity.
What am I missing?
public class FooEntity {
#inject
FooRepository fooRepository;
private Boolean canBeDeleted;
public void delete(){
if (canBeDeleted){
fooRepository.delete(this);
}
throw new CannotBeDeletedException();
}
}
public class FooRepository {
#inject
FooDAO fooDAO;
public void delete(FooEntity fooEntity){
fooDAO.delete(fooEntity.getId());
}
}
Don't expose the internal state, expose a method like isDeletable() on the entity. The repository's delete can call entity.isDeletable() before deleting, and raise an exception if you are trying to delete an entity that is not deletable. That way you separate the concerns. The entity has the domain knowledge of it's "deletableness", while the repo knows how to delete the entity.
The example code is fine as is (except that it's strange to have a DAO inside a repository class, as "repository" is just a more abstract name for the same concept as the DAO).
You can't really prevent other developers from calling the wrong methods, except for using static analysis code inspections where available.
The repository should only concern itself with removing the given entity instance from the set of persistent entities. It cannot have logic for checking whether the entity is allowed to be deleted or not, even if the isDeletable() method is in the entity class.
I would put the delete functionality in a domain service.
public class FooService {
#inject
FooRepository fooRepository;
public void delete(Foo foo) {
if( /* insert validation stuff here to check if foo can be deleted */ ) {
fooRepository.delete(foo);
}
}
The way I do it though is I typically use a ValueObject to represent an Entity's identity. E.g.
public class FooId() {
String foodId;
public String FooId(String fooId) {
this.foodId = foodId;
}
}
public class Foo() {
FooId id;
/* other properties */
}
I would then revise FooService to:
public class FooService {
#inject
FooRepository fooRepository;
public void delete(FooId fooId) {
foo = fooRepository.retrieve(fooId);
if( /* insert validation stuff here to check if foo can be deleted */ ) {
fooRepository.delete(foo);
}
}
To delete a foo (assuming fooId was passed by a command from the UI:
fooService.delete(fooId);
I would not inject a FooRepository in an a class that represents entity. I don't think that it is the rightful place. An Entity for me should not be able to create or delete itself. These functions should be in a Domain Service for that Entity.
i was just working on #EmbededId code, i want to do an auto increment before the entity is persisted, this is want to do without use of #GeneratedValue and an identity column,
below is the table with composite id,
create table TBL_EMPLOYEE_002(
ID integer,
COUNTRY varchar(50),
NAME varchar(50),
constraint PK_EMP_00240 primary key(ID,COUNTRY)
)
this is the code for Entity mapping,
#Entity
#Table(name="TBL_EMPLOYEE_002")
public class EmployeeEntitySix implements Serializable{
// contructor's
#EmbeddedId
private EmployeeIdTwo id;
#Column(name="NAME")
private String employeeName;
// getters and setter's
#PrePersist
public void incId(){
EntityManager em = null;
Query q = null;
EntityManagerFactory emf = null;
try{
emf = Persistence.createEntityManagerFactory("forPractise");
em = emf.createEntityManager();
q = em.createQuery("select max(e.id.employeeId) from EmployeeEntitySix e");
List list = q.getResultList();
Integer i = (list != null && list.size() > 0) ? Integer.valueOf(list.get(0).toString()) : 0;
this.getId().setEmployeeId(++i);
}catch(Exception e){
System.out.println("EXCETION WHILE INCREASING COUNTER...");
e.printStackTrace();
}finally{
if(em != null && em.isOpen()){
em.close();
}
if(getEmf() != null && getEmf().isOpen()){
getEmf().close();
}
}
}
This is the composite id mapping,
#Embeddable
public class EmployeeIdTwo implements Serializable{
#Column(name="ID")
private Integer employeeId;
#Column(name="COUNTRY",length=50)
private String empCountry;
// getters and setters
}
this code is of my main method, this main method is in some other class,
public static void main(String [] args){
EntityManagerFactory emf = null;
EntityManager em = null;
EntityTransaction tx = null;
try{
emf = Persistence.createEntityManagerFactory("forPractise");
em = emf.createEntityManager();
tx = em.getTransaction();
tx.begin();
EmployeeEntitySix employee = new EmployeeEntitySix(new EmployeeIdTwo("ZIMBABWE"), "Henry Olanga");
em.persist(employee);
....
}
Now the above code runs fine,
whenever i persist the entity "EmployeeEntitySix", the method annotated with #PerPersist runs, which will first fetch the max id, increments its, set it into the id in the embeded entity and persist the entity.
Now my question is,
I am creating EntityManagerFactory twice,
first in the main method,
second time in the #PrePersist method in entity EmployeeEntitySix. So whether i can use the first Entitymanagerfactory created in main method in the entity EmployeeEntitySix while pre-persist, or else whether i can reuse the entitymanager created in first time in main method in the #PrePersist method in entity.
Just for information, I am using plain java environment, I am not using a Java EE container.
Hibernate by default tries to persist all fields of an entity class or embedded id, including the field emf, but it does not know how to persist a field of the type EntityManagerFactory.
Of course it does not make sense to persist an EntityManagerFactory. You could mark the field as #Transient to prevent it from being persisted, but then you are just going to face different problems.
The injection of an EntityManagerFactory with a #PersistenceUnit annotation only works on CDI Beans and EJBs in applications that run on a Java EE-compliant application server. As you are using a main method, I assume that your example is a simple JSE program.
Furthermore you should not access EntityManagers in lifecycle callback methods such as #PrePersist. A quote from the JPA Specification (JSR 317: JavaTM Persistence API, Version 2.0):
In general, the lifecycle method of a portable application should not invoke EntityManager
or Query operations, access other entity instances, or modify relationships within the
same persistence context. A lifecycle callback method may modify the non-relationship
state of the entity on which it is invoked.
I suggest that you keep the EntityManagerFactory out of your embedded id class and also get rid of the incId-Method. Instead you could execute the query to determine the new employeeId in your main method, before calling persist. This works fine as long as only one instance of the program works with the database. When there are multiple programs trying to insert new employees there could be race conditions where the two programs try to insert the same id.
In order to prevent this you can use a database sequence to generate the employeeId, with the annotations #GeneratedValue and #SequenceGenerator. You find more information about id generation here: http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Sequencing
My previous question How to wrap Wicket page rendering in a Spring / Hibernate transaction? has led me to thinking about transaction demarcation in Wicket.
Whilst the example there was easily solved by moving business logic down into a Spring-managed layer, there are other places where this is not possible.
I have a generic DAO class, implemented by Hibernate, with
public class HibernateDAO<T> implements DAO<T> {
protected final Class<T> entityClass;
private final SessionFactory sessionFactory;
#Transactional
public T load(Serializable id) {
return (T) getSession().get(entityClass, id);
}
#Transactional
public void saveOrUpdate(T object) {
getSession().saveOrUpdate(object);
}
}
and a generic model to fetch it
public class DAOEntityModel<T> extends LoadableDetachableModel<T>{
private DAO<T> dao;
private final Serializable id;
public DAOEntityModel(DAO<T> dao, Serializable id) {
this.dao = dao;
this.id = id;
}
public <U extends Entity> DAOEntityModel(DAO<T> dao, U entity) {
this(dao, entity.getId());
}
public Serializable getId() {
return id;
}
#Override
protected T load() {
return dao.load(id);
}
}
Now I have a minimal form that changes an entity
public class ScreenDetailsPanel extends Panel {
#SpringBean(name="screenDAO") private DAO<Screen> dao;
public ScreenDetailsPanel(String panelId, Long screenId) {
super(panelId);
final IModel<Screen> screenModel = new DAOEntityModel<Screen>(dao, screenId);
Form<Screen> form = new Form<Screen>("form") {
#Override protected void onSubmit() {
Screen screen = screenModel.getObject();
dao.saveOrUpdate(screen);
}};
form.add(
new TextField<String>("name", new PropertyModel<String>(screenModel, "name")));
add(form);
}
}
So far so good - thanks for sticking with it!
So my issue is this - when the form is submitted, the PropertyModel will load the screenModel, which will happen in the transaction delineated by the #Transactional dao.load(id). The commit of the changes will when the (different) transaction started for dao.saveOrUpdate(object) is committed. In between these times all bets are off, so that the object may no longer exist in the DB to be committed.
I'm never entirely sure with DB code and transactions. Should I just shrug this off as unlikely, although I could construct other more complicated but more dangerous scenarios? If not I can't see how to demarcate the whole page logic in a single transaction, which is what my instinct tells me I should be aiming for.
Typically you would solve this by putting the #Transactional annotation on a service-level class, used by your front-end layer code, which wraps around the DAO operations - so that the load and save happens within the same transaction. In other words, you can solve this by creating a layer of code between the form and the DAO code, a "service layer", which provides the business-level logic and hides the presence of DAOs from the presentation layer.
I've not yet implemented it, but I'm pretty sure that #ireddick solution in How to control JPA persistence in Wicket forms? of lazily starting a tx in in the Wicket request cycle is the best solution here. I'm going to accept this proxy for it to stop Stack Overflow nagging me to accept an answer.