JPA2.0 commits transaction on flush immediatly - java

I'm using EJB3 and JPA2 in a project containing several modules.
Lately i have noticed that the DB-records won't rollback on exception. After doing some research i found that entity manager commits the transaction on flush immediatly even before the method ends, so that it can't rollback on exception.
I inject entity manager using
#PersistenceContext
private EntityManager entityManager;
To create a new record is persist and flush beeing called in the same class
entityManager.persist(entity);
entityManager.flush();
Even if i call throw new RuntimException("") right after flush, it wont rollback. On debug after flush is invoked i can select the DB-record with a database tool, before the method ends.
I already checked the persistence.xml and found nothing unusual. I dont use any other specifig configuration.
I'm out of ideas what might cause this behavior. I appriciate any clue.

You need to specify transaction boundaries, otherwise a new transaction will be opened and commited after each data manipulation query (INSERT, UPDATE, DELETE). As em.flush() will trigger such SQL query to be executed, it will open an implicit transaction and commit it if the SQL is successful, rollback in case of error.
In order to set transaction boundaries and make a RuntimeException trigger a rollback, the best option is to call entityManager methods from an EJB object. You must use a JTA datasource, not RESOURCE_LOCAL. If you don't use JTA datasource, you need to manage transactions by yourself, ie. by using entityManager.getTransaction() object.
Outside of an EJB, or with non-JTA datasource, you do not have any transaction open, unless you start it yourself by calling entityManager.getTransaction().begin(). However, in this way, your transaction will not be rolled back when Exception is thrown. Instead, you must roll back in catch block. This is mostly outside of Java EE container, in a Java SE application. In Java EE, I strongly suggest to use JTA datasource. Example:
public class NotAnEJB {
public persistEntity(EntityManager em, MyEntity entity) {
em.getTransaction().begin();
try {
em.persist(entity);
em.flush();
if (shouldFail()) {
throw new RuntimeException();
}
em.commit();
} catch (Exception e) {
em.rollback();
}
}
}

Related

Spring #Transactional is consistantly rolling back transaction upon exception

Alrighty folks. I've read quite a bit of docs. And at my wits end on why this is happening.
Like many of the other people, we have a service interfacing with a oracle db. This is a pretty standard setup
#Service
public class DaoService {
private JdbcTemplate jdbcTemplate;
private SimpleJdbcInsert insertA;
private SimpleJdbcInsert insertB;
private SimpleJdbcInsert insertC;
#Autowired
public Dao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
// Assume all Inserts are initialized
}
#Transactional(rollbackFor = Exception.class)
public void insertStuff(Stuff stuff) {
insertA.execute(stuff.A);
// Suppose a connection failed here
insertB.executeBatch(stuff.B);
insertC.executeBatch(stuff.C);
}
Now here lies our issue. For 99% of all rollbacks they are a-ok.
When a connection gets closed for unknown reasons is where our problems occur.
The exception message being
TransactionSystemException: Could not roll back JDBC transaction;
nested exception is java.sql.SQLException: "The connection is closed"
See, it tries to rollback as it's supposed to. But the issue is that stuffA lingers in the DB will stuffB and stuffC is not. This happens only like 1% of the time. (aka, sometimes despite the rollback failure, no 'stuff' will be in the DB.
Am I understanding something wrong? I thought spring only commits at the end of a successful transaction? Anyone have an idea on how I can stop these partial commits despite making in #Transactional?
p.s. for what it's worth. autocommit is defaulted to being on. However I read that it's not taken into consideration when something is #Transactional
From the Database JDBC Developer's Guide:
If the auto-commit mode is disabled and you close the connection without explicitly committing or rolling back your last changes, then an implicit COMMIT operation is run.
Maybe this is the case you are running into.
According to this answer, Spring only offers you an interface for transaction manager and the implementation may vary. However, most transaction manager implementations will turn off autocommit during an #Transactional call then return it to the previous state after commit.
That being said, on some databases there are ways to execute autonomous transactions inside an outer transaction that may not be visible to your application or to Spring. I know Oracle allows this. Have you checked all of the triggers on the tables? I worked on one application that had an audit trigger that would force orphaned data into some of the tables in situations like this. Can you tell us which database you are using?
try this :
#Transactional(propagation = Propagation.REQUIRES_NEW)
hope it will work

Nested Transaction and EJBContext's setRollbackOnly()

I am reading the Transaction Management of Java EE 7 and I get confused by the concept of nested transaction and the functionality of EJBContext#setRollbackOnly().
Say I have two Session Beans, Bean1Impl and Bean2Impl and their signatures are:
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class Bean1Impl implements Bean1 {
#Resource
private EJBContext context;
#TransactionAttribute(REQUIRED)
public void method1() {
try {
//some operations such as persist(), merge() or remove().
}catch(Throwable th){
context.setRollbackOnly();
}
}
}
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class Bean2Impl implements Bean2 {
#Resource
private EJBContext context;
#TransactionAttribute(REQUIRED)
public void method2() {
try {
//some operations such as persist(), merge() or remove().
//an exception has been thrown
}catch(Throwable th){
context.setRollbackOnly();
}
}
}
As stated in Java EE 7 Tutorial:
51.3.1.1 Required Attribute
If the client is running within a transaction and invokes the enterprise bean's method, the method
executes within the client's transaction. If the client is not
associated with a transaction, the container starts a new transaction
before running the method.
The Required attribute is the implicit transaction attribute for all
enterprise bean methods running with container-managed transaction
demarcation. You typically do not set the Required attribute unless
you need to override another transaction attribute. Because
transaction attributes are declarative, you can easily change them
later.
In this case I don't need to specify #TransactionAttribute(REQUIRED) annotation declaration in the methods Bean1Impl#method1() and Bean2Impl#method2(). Am I right?
So in the above code the transaction of Bean2Impl#method2() would be running within the transaction of Bean1Impl#method1().
Can I consider it as a Nested Transaction?
If there is an Exception has been thrown inside the method Bean2Impl#method2() which eventually would lead to a call to the method EJBContext.setRollbackOnly() from the catch block and as expected it should roll back the operations performed within the try block of this method. In this case what would happen to the transaction and as well as the Bean1Impl#method1(). Would it be rolled back as well? What I mean is:
What would happen if there is a call of EJBContext.setRollbackOnly() from Bean2Impl#method2() and
Bean2Impl#method2() is called from the method Bean1Impl#method1() before any database operation like persist, merge or remove.
Bean2Impl#method2() is called from the method Bean1Impl#method1() after any database operation like persist, merge or remove.
And lastly what would happen if the method Bean2Impl#method2() get executed successfully but EJBContext.setRollbackOnly() is called from Bean1Impl#method1() after successful return of Bean2Impl#method2()?
To add to #Philippe Marshall's correct answer and your comment - REQUIRES_NEW will create a new transaction, independent from the first one. They are not nested. The first transaction is suspended while the second is active. Once the second transaction commits, the first one is resumed.
You do not have to setRollbackOnly() manually. Most PersistenceExceptions will do that if needed. You will gain nothing by rolling back transactions that you don't have to. For example, when querying data, you may get a NoResultException or a NonUniqueResultException. They do not cause a transaction to be rolled back as there is no risk of inconsistencies between the persistence context and the DB.
You do not need to specify neither #TransactionAttribute(REQUIRED) nor #TransactionManagement(TransactionManagementType.CONTAINER)- both are the default settings.
EDIT: to answer your further questions:
I am assuming #TransactionAttribute(REQUIRES_NEW) on method2 and therefore two separate transactions.
If there is an Exception that leads to the rollback of the transaction in method2, the transaction from method1 will not be rolled back if the Exception is caught. If the Exception is not caught, both transactions will be rolled back.
When setting the rollback flag on a transaction, it does not matter whether it happens before or after DB operations, since the entire transaction is rolled back.
Once method2 returns, it's transaction is committed. Rolling back or committing the transaction from method1 afterwards has no influence on the results of the first transaction.
A general advice - do not catch Throwable - it is much too broad and you might swallow exceptions which you would rather let propagate to the surface.
This is not nested transactions, JavaEE / JTA does not support nested transaction. If #method2() is called from #method1() it runs in the same transaction. If you want to have a different transaction you need #REQUIRES_NEW. EJBContext.setRollbackOnly() only works on the current transaction. Note there is a chance that after calling EJBContext.setRollbackOnly() all operations on the transactional resource including reads will throw an exception (JBoss AS 5.1 did this, don't know the current behaviour).
Update:
}catch(Throwable th){
context.setRollbackOnly();
}
You don't need this for runtime exceptions, this is the default behaviour of EJBs.

manual commits with #Transactional attribute

I use spring+hibernate template to process entities. There is rather big amount of entities to be loaded all at once, so I retrieve an iterator from hibernate template.
Every entity should be processed as a single unit of work. I tried to put entity processing in a separate transaction (propagation = REQUIRED_NEW). However I ended with exception stating that proxy is bounded to two sessions. This is due to suspended transaction used for iterator lazy loading. I am using the same bean for lazy loading and for processing entities. (May be it should be refactored into two separate daos: one for lazy loading and one for processing?)
Then I tried to use single transaction that is committed after each entity is processed. Much better here, there are no exceptions during entity processing, but after processing is finished and method returns, exception is thrown from spring transaction managing code.
#Transactional
public void processManyManyEntities() {
org.hibernate.Sesstion hibernateSession = myDao.getHibernateTemplate().getSessionFactory().getCurrentSession();
Iterator<Entity> entities = myDao.findEntitesForProcessing();
while (entities.hasNext()) {
Entity entity = entities.next();
hibernateSession.beginTransaction();
anotherBean.processSingleEntity(entity);
hibernateSession.getTransaction().commit();
}
}
processSingleEntity is a method in another bean annotated with #Transactional, so there is one transaction for all entities. I checked what transaction causes an exception: it is the very first transaction returned from hibernateSession.beginTransaction(), so it just not updated in transaction manager.
There are several questions:
is it possible to avoid session bind exception without refactoring the dao? that is not relevant question as problem is with Session and hibernate not with dao
is it possible to update transaction in the transaction manager? solved
is it possible to use the same transaction (for anotherBean.processSingleEntity(entity);) without #Transactional annotation on processManyManyEntities?
I would prefer to remove the #Transactional annotation on "processManyManyEntities()", and, to eagerly load all data from "findEntitesForProcessing".
If your want each entity of data to be transactional in "processSingleEntity", the #Transactinoal on "processSingleEntity" is fine. You don't have to annotate the #Transactional on "processManyManyEntities()". But in case of lazy loading, eager loading is a necessary mean to prevent the source data from loading in another session, say, in "processSingleEntity".
Since the transaction for each entity of data, the transactional boundary in loading of source data is not the case of your transaction. Don't let the "lazy loading" to complicate your intent of transaction for modification of data.
That is possible to update transaction in transaction manager. All you need to do is get SessionHolder instance from TransactionSynchronizationManager.getResource(sessionFactory) and set transaction in the session holder to the current. That makes possible to commit transaction whenever it is necessary and allows transaction to be committed by spring transaction manager after method return.

Why do we have to manually flush() the EntityManager in a extended PersistenceContext?

In our J2EE application, we use a EJB-3 stateful bean to allow the front code to create, modify and save persistent entities (managed through JPA-2).
It looks something like this:
#LocalBean
#Stateful
#TransactionAttribute(TransactionAttributeType.NEVER)
public class MyEntityController implements Serializable
{
#PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager em;
private MyEntity current;
public void create()
{
this.current = new MyEntity();
em.persist(this.current);
}
public void load(Long id)
{
this.current = em.find(MyEntity.class, id);
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void save()
{
em.flush();
}
}
Very important, to avoid too early commits, only the save() method is within a transaction, so if we call create(), we insert nothing in the database.
Curiously, in the save() method, we have to call em.flush() in order to really hit the database. In fact, I tried and found that we can also call em.isOpen() or em.getFlushMode(), well anything that is "em-related".
I don't understand this point. As save() is in a transaction, I thought that at the end of the method, the transaction will be committed, and so the persistent entity manager automatically flushed. Why do I have to manually flush it?
Thanks,
Xavier
To be direct and to the metal, there will be no javax.transaction.Synchronization objects registered for the EntityManager in question until you actually use it in a transaction.
We in app-server-land will create one of these objects to do the flush() and register it with the javax.transaction.TransactionSynchronizationRegistry or javax.transaction.Transaction. This can't be done unless there is an active transaction.
That's the long and short of it.
Yes, an app server could very well keep a list of resources it gave the stateful bean and auto-enroll them in every transaction that stateful bean might start or participate in. The downside of that is you completely lose the ability to decide which things go in which transactions. Maybe you have a 2 or 3 different transactions to run on different persistence units and are aggregating the work up in your Extended persistence context for a very specific transaction. It's really a design issue and the app server should leave such decisions to the app itself.
You use it in a transaction and we'll enroll it in the transaction. That's the basic contract.
Side note, depending on how the underlying EntityManager is handled, any persistent call to the EntityManager may be enough to cause a complete flush at the end of the transaction. Certainly, flush() is the most direct and clear but a persist() or even a find() might do it.
If you use extended persistence context all operations on managed entities done inside non-transactional methods are queued to be written to the database. Once you call flush() on entity manager within a transaction context all queued changes are written to the database. So in other words, the fact that you have a transactional method doesn't commit the changes itself when method exits (as in CMT), but flushing entity manager actually does. You can find full explanation of this process here
Because there is no way to know "when" the client is done with the session (extended scope).

Entitymanager causing memory leak?

I have a slow memory leak in my Java application. I was wondering if this could be caused by not always closing the Entitymanager when used. However using myeclipse to generate DB code, I'm getting methods like this:
public Meit update(Meit entity) {
logger.info("updating Meit instance");
try {
Meit result = getEntityManager().merge(entity);
logger.info("update successful");
return result;
} catch (RuntimeException re) {
logger.error("update failed");
throw re;
}
}
Which never close the EntityManager. Considering this is generated code, I'm wondering who's right, me or the IDE.
As #Ruggs said if you are managing the EntityManager lifecycle yourself (as opposed to having CMP Container Managed Persistence done by a J2EE) then you need to close the EntityManager yourself or at least call EntityManager.clear() to detach entities.
EntityManager are lightweight object so there is no need for just having one, you can create one for each transaction and close it after the transaction is committed.
All the entities that load/persist through an EntityManager stay in memory until you explicitly detach the entities from it (via EntityManager.detach() or EntityManager.clear() or EntityManager.close()). So it's better to have short-lived EntityManagers. If you persist 1000000 entities via the same EntityManager without detaching them after you will get a OOME (doesn't matter if you persist each entity in it's own EntityTransaction).
It's all explained in this post http://javanotepad.blogspot.com/2007/06/how-to-close-jpa-entitymanger-in-web.html.
As an example (taken from the earlier post) if you want to avoid "memory leaks" you should do something like this (if you are not using CMP):
EntityManager em = emf.createEntityManager();
try {
EntityTransaction t = em.getTransaction();
try {
t.begin();
// business logic to update the customer
em.merge(cust);
t.commit();
} finally {
if (t.isActive()) t.rollback();
}
} finally {
em.close();
}
Entity managers should generally have the same lifecycle as the application and not be created or destroyed on a per-request basis.
Your "memory leak" may be nothing more than the caching JPA is doing. You don't say which JPA provider you use but I know from experience that EclipseLink by default does extensive caching (which is part of the alleged benefits of JPA and ORM in general).
How do you know you have a memory leak?
Check whether it's really a leak
if so get the Eclipse Memory Analyzer and analyze it.
The blog posts here might also be useful.
It sounds like you are using an application managed EntityManager. You will need to call close the EntityManager yourself, it's part of the spec. You will also need to close the EntityManagerFactory when you shutdown your webapp.
I'd recommend using something like OpenEJB or Springframework to manage the EntityManager/EntityMangerFactory for you.

Categories