arg20
arg20

Reputation: 4991

Understanding JTA in EJB: Not flushing

So I have This EJB annotated at class level with @TransactionAttribute(TransactionAttributeType.REQUIRED), so that every method should execute in a transaction unless I override this behavior, when the transaction is committed, the data is meant to be flushed, right? So far so good. So now I have a public User find(String email) method, annotated with @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) so this method is not executed in a transaction, as it only fetches data.

Ok so I am testing my app, and I have a booter method that creates a couple of entities using an ejb and then uses the find method to fetch one. What, in my opinion, should happen:

->I create entity 1 calling save(User u) which is executed in a transaction. It commits, the data is flushed.

->Repeat this step with 2 more entities. their transactions commit, the data is flushed.

->At this point I should have 3 entities in my L2 cache (using Eclipselink) and in my database.

->I call the find(String email) method. It finds an entity, returns it, no exception, and my code executes nicely, I get excited, I open a beer, and I don't need to ask a question in stackoverflow.

What actually happens:

->I create all 3 entities. No exception.

->I call the find(String email) method, it raises an EjbException because it doesn't find the entity, debugging I find out that when this method is called, the database is empty, no data has been flushed (even if i call the flush method when i create the entities explicitly, which shouldnt be neccessary anyway). It throws the EJbException, my code stops, I check the database again and NOW the entites are there, once the exception was thrown because they weren't there. If I remove @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) from the find method, which causes it to execute the search inside a transaction, my code works.

->I don't open a beer.

So now seriously, what's going on? Why do I need to search for the entity inside a transaction otherwise it doesn't flush anything?

EDIT: Persistence Unit:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="TribunalExpedientes" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>tribunalexpedientes</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <shared-cache-mode>ALL</shared-cache-mode>
     <properties>
      <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
     </properties>
  </persistence-unit>
</persistence>

No Exception raised except for the one saying that no entity has been found when I search, after which, the cache is flushed to the database.

Upvotes: 4

Views: 4363

Answers (3)

Robert Franz
Robert Franz

Reputation: 543

Well, committing a transaction doesn't require Eclipselink to flush the data. That's the reason. This in my opinion a really ugly behavior. Eclipselink is allowed to flush the data when it wants to do it. I had also some problems with that. E.g. when using @PrePersist or @PreUpdate it is not guaranteed, that this happens when committing the transaction. E.g. when calculating some statistics, your not able to use them within the same transaction, as Eclipselink could do the processing when the transaction is already finished.

You have to use the entity that you use in order to make a em.persist(). In case you perform a db query. Eclipselink is required to flush the entity, as the query might not be correct. But using em.flush() instead will cause some really really ugly performance problems when trying to scale the application.

Upvotes: 0

Chris
Chris

Reputation: 21145

Add which will show you when the statements are executed, and when the transaction commits. Since NOT_SUPPORTED suspends the transaction, you can only 'find' the data if the prior transaction has commited. Chances are good that your save methods are wrapped in a larger transaction which your find method is suspending. Flush won't change this because this data is still transactionally isolated.

Try using REQUIRES_NEW to have the save methods put in their own transactions that get commited when done.

Upvotes: 1

James
James

Reputation: 18379

My guess is that you do not have things configured correctly. Include your persistence.xml and what application server and database you are using.

Are you using JTA or RESOURCE_LOCAL, you should be using JTA and should be setting your target-server in your persistence.xml.

Also check for any errors. If an error occurs, then the transaction will be rolled back.

NOT_SUPPORTED is not a good idea in general, it means an exception will be thrown if this method is called in a transaction. Which may be what is occurring.

Upvotes: 3

Related Questions