6 Replies Latest reply: May 25, 2012 11:20 AM by Jonathan Clarke RSS

Transaction commit just does not work.

Mader Levap Newbie
I have these classes:

@Name("someService")
@Scope(ScopeType.APPLICATION)
@AutoCreate
public class SomeService implements Serializable
{
  @In(create = true)
  private InterfaceToSomeBean someBean;
  @In
  private EntityManager       entityManager;

  @Asynchronous
  @Transactional // yes, already must be here because of "some doing here"
  public synchronized QuartzTriggerHandle execute(@Expiration Date when, @IntervalDuration long interval)
  {
    // ...some doing here...
    someBean.callOne();
    // ...some doing here...
    someBean.callTwo();
    // ...some doing here...
  }
}

@Name("someBean")
@Scope(ScopeType.SESSION)
public class SomeBean implements InterfaceToSomeBean, Serializable
{
  @In
  private EntityManager  entityManager;

  // BOTH of these does NOT work
  //@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
  //@Transactional
  public void callOne()
  {
    // do some long updates/inserts/other horrible, horrible things to data
  }

  // BOTH of these does NOT work
  //@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
  //@Transactional
  public void callTwo()
  {
    // do another series of long updates/whatever
  }
}

public interface InterfaceToSomeBean
{
  public void callOne();
  public void callTwo();
}

I tried both @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) and @Transactional for callOne() and callTwo(). Does not work. AFAIK there is no way to enforce commit in middle of method (flush() does something else). Nice design decisions you have there.

What I wanted to achieve: after calling callOne() there is end of transaction and all data commits (and are readable for rest of system). Same with callTwo().
What I get in reality: unfortunately, everything is commited AFTER end of service execute() call. Until then service happily prevents half of system from reading (just READING) data.

I do not know if removing "@Transactional" from execute() would help, but it would be very inconvenient due to some other code in this service (throws javax.persistence.TransactionRequiredException because of entityManager.flush() call).
  • 1. Re: Transaction commit just does not work.
    Marek Novotny Newbie

    First @TransactionAttribute is for EJB 3 beans, @Transactional is for Seam POJO Component.


    You didn't write what transaction manager you use in your application i components.xml.

  • 2. Re: Transaction commit just does not work.
    Mader Levap Newbie
    "First @TransactionAttribute is for EJB 3 beans, @Transactional is for Seam POJO Component."
    I know it. I tried both, because it just does not work.

    "You didn't write what transaction manager you use in your application i components.xml."
    Sorry. These are almost no changes from standard entries generated by seam-gen. We are using SEAM 2.1, JBoss 4.2.3, Hibernate.

    persistence-dev.xml:
    <persistence-unit name="some">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <jta-data-source>someDatasource</jta-data-source>
      <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
        <property name="hibernate.hbm2ddl.auto" value="validate"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.format_sql" value="true"/>
        <property name="hibernate.default_schema" value="public"/>
        <property name="jboss.entity.manager.factory.jndi.name" value="java:/someEntityManagerFactory"/>
      </properties>
    </persistence-unit>

    some-ds.xml:
    <datasources>
      
       <local-tx-datasource>
          <jndi-name>someDatasource</jndi-name>
          <use-java-context>false</use-java-context>
          <connection-url>jdbc:postgresql://someip/somedatabase</connection-url>
          <driver-class>org.postgresql.Driver</driver-class>
          <user-name>no_gonna_give</user-name>
          <password>you_wish_;)</password>
         
         <min-pool-size>5</min-pool-size>
         <max-pool-size>100</max-pool-size>
       </local-tx-datasource>
    </datasources>

    components.xml:
    ...
    <persistence:managed-persistence-context name="entityManager" auto-create="true" persistence-unit-jndi-name="@puJndiName@"/>
    ...

    Note: line '<transaction:ejb-transaction />' is NOT present in components.xml.
  • 3. Re: Transaction commit just does not work.
    Marek Novotny Newbie

    if you want to commit something in the middle of a method you need user transactions or EJB3 beans with  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW).


    So you have got now Seam POJO components and this is not supported in Seam to simulate EJB container what is what you want. If you change your SomeBean to Stateless Session Bean and declare @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) for both methods it should work as EJB container suspend existing transaction to get done calling method callOne and then callTwo in independent transactions to method execute transaction.



    Also in that case you need <transaction:ejb-transaction /> set up.

  • 4. Re: Transaction commit just does not work.
    Jonathan Clarke Newbie

    Hi Marek,

     

    I have exactly the same problem as PP, only that I have some batch processing done in a Quartz job, so it's nothing to do with screen handlers, or anything linked to a button. Can you point me in the direction of some UserTransaction code that actually works, please? Every finding online is someone either having problems, or having solved it within a stateless backing bean, or something like that. I can get a POJO in a Quartz job working with Hibernate, but if the batch processing takes too long, then the transaction times out. I want to do a loop around some data, and then commit at the end of each loop. Looping around a dataset, then calling a method that's got the @Transactional annotation does not work. Also, because it's a Quartz job, I cannot inject the EntityManager, so I have to use:

     

    EntityManagerFactory fEntityManagerFactory = Persistence.createEntityManager("PersistenceName_1";

    EntityManager fEntityManager = fEntityManagerFactory.createEntityManager();

     

    I'd like to keep Seam managed transactions for the screen interactions, but the back-end components seem to be lacking in transaction support. I simply want to do old-skool transaction.begin()... something... commit(), but there's very little documentation that assists in the scenario I'm in.

     

    Can you help, please?

    Jonathan.

  • 5. Re: Transaction commit just does not work.
    Marek Novotny Apprentice

    Jonathan,

     

    in case you would like to use user managed transactions in a method you can use something like:

     

    org.jboss.seam.transaction.UserTransaction transaction = org.jboss.seam.transaction.Transaction.instance();
    transaction.begin();
    
    ...
    
    transaction.commit();
    

     

    or you can use use org.jboss.seam.util.Work<T> like is used in

     

    return new Work() {  <implement here your business logic> in T work()  }.workInTransaction();
    

     

    That usage above can be seen for instance in org.jboss.seam.transaction.TransactionInterceptor - http://anonsvn.jboss.org/repos/seam/branches/community/Seam_2_2/src/main/org/jboss/seam/transaction/TransactionInterceptor.java around line 91

  • 6. Re: Transaction commit just does not work.
    Jonathan Clarke Newbie

    The .workInTransaction() technique works! Thank you, but I really think this approach has to be brought out in the open, especially for the developers that want to do some decent non-event related database work. I can't even find that function in the Seam documentation, although I may have just missed. I think it's really important for others to know about this one.