Hibernate says "An exception thrown by Hibernate means you have to rollback your database transaction and close the Session immediately".
When persist method throws a SQLException and the entityManager becomes dirty, if I close the EntityManager, it still in Conversation Scope.
i'm using: tomcat 7, cdi 1.1, hibernate 4.1;
Is there any way to produce a new EntityManager for the current conversation to replace the dirty?
#Produces
#ConversationScoped
public EntityManager create(EntityManagerFactory emf) {
EntityManager em = emf.createEntityManager();
...
ViewBean
#Named #ConversationScoped
public class MyView implements Serializable {
enter code here
#Inject #Getter private EntityManager em;
...
public void persist(){
try{
getEm().getTransaction().begin();
getEm().persist(entityInstance);
getEm().getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
if(getEm().getTransaction().isActive()){
getEm().getTransaction().rollback();
}
}
}
No, there is not. Conversation scoped isn't a very good scope for an EntityManager anyway. It should really be Request or Default due to transaction boundaries.
Related
I am a long time Seam user who tries to move to Java EE7, JSF2.2 and CDI now.
In Seam you tend to use EntityManagers with extended scope most of the time (in the Seam Conversation Scope). You don't get any LIEs on Ajax request etc.
I am trying to do it in a similar way with Java EE7 and CDI but somehow the injected EntityManager is only transaction scoped. When I get a ajax request in the entities that were loaded before are not managed anymore.
I am using the new javax.faces.view.ViewScoped and javax.transactional.Transactional on my CDI bean.
My Producer:
#PersistenceContext(unitName = "primary", type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;
#Produces
#Default
#Dependent
public EntityManager getEntityManager() {
return entityManager;
}
And my CDI bean:
#Named
#ViewScoped
#Transactional
public class TestBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Inject
EntityManager entityManager;
Logger log = Logger.getLogger(TestBean.class);
private TestEntity lastTest = null;
public void testAdd(){
TestEntity test = new TestEntity();
test.setVal("Test "+System.currentTimeMillis());
entityManager.persist(test);
entityManager.flush();
log.infov("Created test entity {0}", test);
lastTest = test;
}
public void testRead(){
List<TestEntity> test = entityManager.createQuery("select t from TestEntity t").getResultList();
for(TestEntity t: test){
log.infov("Found {0} managed {1}",t,entityManager.contains(t));
}
if(lastTest!=null){
log.infov("Last Test {0} managed {1}",lastTest,entityManager.contains(lastTest));
}
}
So when I first call testAdd() via Ajax it creates a new test entity. When I then call testRead() it gets all test entities and checks that the last created test entity is still managed (which it should if it is an EntityManager with an extended persistent context). But entityManager.contains(lastTest) always returns false.
What am I doing wrong?
I believe I can't use #PersistenceContext directly in the CDI bean. So how do I get the desired (Seam like) behaviour?
When you specify that an injected EntityManager is an extended persistence context, all object instances remain managed. Extended persistence contexts can only be used within Stateful session beans.
This is according to JBOSS documentation: https://docs.jboss.org/ejb3/app-server/tutorial/extended_pc/extended.html.
Consider packaging your insert/update/delete operations into EJBs while simple read from database can be through CDI beans. But more complex operations involving multiple reads and writes as well as transaction should be within EJBs.
I wonder if it is ok to use UserTransaction like in this scenario below.
EntityManager is not thread-safe so there is helper class.
public class EMProducer {
#PersistenceContext
EntityManager em;
#Produces
#RequestScoped
public EntityManager createEM() {
return em;
}
}
and the Servlet:
#WebServlet("/test")
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Inject
EntityManager em;
#Resource
UserTransaction utx;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
MyEntity entity = new MyEntity("test entity");
//try...
utx.begin();
em.persist(entity);
utx.commit();
//catch...
}
}
The problem is that there is always the same instance of UserTransaction object injected. Is it ok or it should be done differently? Is the UserTransaction thread-safe?
When I use BMT EJBs there is also always the same UserTransaction instance injected so I think it is, but I would like to be sure how this works.
(I know about EJBs, #Transactional, that I shouldn't add business logic to servlets etc. but I'm asking about this use case)
I have a stateless bean class TestBean:
package samples;
import javax.ejb.*;
import javax.persistence.*;
#Stateless
public class TestBean {
#PersistenceContext
EntityManager em;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void doIt() throws Exception {
em.createQuery("UPDATE Employee e SET e.salary = e.salary * 1.05").executeUpdate();
throw new Exception("Let us stop it!");
}
}
Does the EntityManager commit the transaction and the update would take place?
By default EJB bean should rollback the transaction only on system exceptions, that is: RuntimeException, RemoteException. This kind of exceptions are wrapped-up in EJBException.
If you throw application exception (as it is in your example), EJB bean won't rollback the transaction- it expects you to handle the exception. Application exceptions are those that do not extend RuntimeException or RemoteException.
You can make your EJB bean to rollback on appication exceptions by annotating it with:
#ApplicationException(rollback=true)
How to reach the entity manager which managed the entity. I mean; suppose that i have an entity reference in the sessionBean, how can i get entityManager of this entity belonged one?
I had already tried (plz see getEntityManagerOfEntity() method) contains method of em; but it does not work.
Thx
bgrds
#Stateless(name = "MainManager", mappedName = "MainManager")
#TransactionManagement(TransactionManagementType.CONTAINER)
#Interceptors(value = { PerformanceMonitor.class, ProfileInterceptor.class })
public class MainManagerBean implements MainManager, MainManagerLocal
{
private Logger logger = Logger.getLogger(this.getClass());
#PersistenceContext(unitName = "DSApp")
private EntityManager manager;
#PersistenceContext(unitName = "DSIX")
private EntityManager integrationManager;
#Resource
SessionContext ctx;
public EntityManager getEntityManagerOfEntity(SuperEntity superEntity)
{
if (manager.contains(superEntity))
return manager;
else if (integrationManager.contains(superEntity))
return integrationManager;
return null;
}
public SuperEntity findByPrimaryKey(SuperEntity superEntity)
{
getEntityManagerOfEntity(superEntity).setFlushMode(FlushModeType.COMMIT);
return dao.findByPrimaryKey(getEntityManagerOfEntity(superEntity), superEntity);
You cannot backtrack the EntityManager from an entity using the JPA API, even when it is still managed.
What you can do, if you have references to different EMs in your bean and the entity is managed, is to check the right EM by calling em.contains(entity).
In most cases it is not really important to know, which EM has fetched an entity originally, since you can merge the entity into any persistence context and continue working with it.
I'm a novice.
Does Jersey and EJB hold the same EntityManager scope?
Should I have to pass the EntityManager to EJB for same persistence context?
The primary target usage is JTA.
#Stateless
class MyEJB {
public MyEntity find(Long id) {
...
}
#PersistenceContext;
EntityManager entityManager;
}
class MyResource {
#GET
#Path("/myentity/{id}");
public MyEntity get(#PathParam("id") final long id) {
final MyEntity found = myEjb.find(id);
// is found's state detached?
// should I have to reattach?
found.setDate(new Date());
return found;
}
#EJB
private MyEjb myEjb;
#PersistenceContext;
EntityManager entityManager;
}
Does Jersey and EJB hold the same EntityManager scope?
Should I have to pass the EntityManager to EJB for same persistence context?
I don't think that your wording is correct, but they can share the same EntityManager instance, and you have chosen the right way (through injection). Have a look at this chapter of the Java EE 6 Tutorial:
To obtain an EntityManager instance, inject the entity manager into the application component:
#PersistenceContext
EntityManager em;
So, once again, your approach is correct. With regards to the questions in the code comments: the fact that MyEntity is attached or detached, it depends on the implementation of the find method in your EJB. If you do the following, it will be attached:
public MyEntity find(Long id) {
return entityManager.find(MyEntity.class, id);
}
Finally, doing this way, if you have chosen JTA to use container managed transactions, the transactions will be automatically bounded with the natural boundaries of MyBean's methods. In order to have JTA transactions, you have to use this line in persistence.xml file:
<persistence-unit name="em" transaction-type="JTA">