-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 
Author Message
 Post subject: CMT not rollingback. JBoss 3.2.1 Hibernate 2
PostPosted: Mon Sep 01, 2003 12:39 pm 
Newbie

Joined: Sat Aug 30, 2003 5:46 am
Posts: 5
This is almost a continuation of http://forum.hibernate.org/viewtopic.php?t=109


I have a Stateless Session bean which containts my hibernate code.
My current problem is that DB changes are not getting rolledback when the Session bean function throws an exception.

Also if I remove session.flush() calls from within the bean methods nothing is written to the DB (making me think, has the container actually commited a transaction)


My understanding, from reading Ed Romans book, is that for a CMT Bean the container will automagically rollback the transaction if the method throws. Perhaps this assumption is incorrect.

I have a gut feeling that my hibernate session is not aware of the container transaction.


Is this caused beacuase Im using PostgreSQL which is not an XA datasource?
Or
Am I mission something with the way im using Hibernate/JBoss?



I feel really dumb for asking all these newbie questions, if I get this working, I'll write a tutorial to redeem myself.


Thanks in advance
Peter Henderson.




Anyway onto the code.


The Stateless Session bean
Code:
/**
* @ejb.bean         name="PurchaseOrder"
*                   description="PurchaseOrder test bean"
*                   jndi-name="ejb/starjarcrm/PurchaseOrder"
*                   type="Stateless"
*                   transaction-type="Container"
*
* @ejb.security-role-ref role-link="Administrator"
*                        role-name="admin"
*
* @ejb.permission   role-name="Administrator"
*
* @ejb.transaction  type="Required"
*
*/
public class PurchaseOrderBean implements SessionBean {
   
    org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger( this.getClass() );   
   
    private SessionContext ctx;

    /** Retrieves the HibernateSession factory from JNDI, then creates a new Session.
     * @throws NamingException If the HibernateFactory was not found.
     * @throws HibernateException If hibernate could not create a session.
     * @return A hibernate session.
     */
    private Session getSession() throws NamingException, HibernateException {
        Object objref = new InitialContext().lookup("java:/hibernate/HibernateFactory");
        SessionFactory sf = (SessionFactory)PortableRemoteObject.narrow(objref, SessionFactory.class);
        return sf.openSession();
    }

    /** Adds a line item to a Purchase Order, updating StockItem totals as needed.
     * If the Purchase order has already been sent, update the stock item to reflect the
     * new qty on order.
     *
     * @ejb.interface-method view-type="remote"
     * @ejb.transaction type="Required"
     * ---ejb.transaction type="RequiresNew"---
     *
     * @param poid The ID of the Purchase Order.
     * @param supplierPartID
     * @param qty in supplier units
     * @throws PurchaseOrderDBException
     * @throws NamingException
     */
    public void addPOLineItem( Long poid, Long supplierPartID, double qty ) throws PurchaseOrderDBException, NamingException {
        System.out.println("ENTERED addPOLineItem");
       
       
        long startTime = System.currentTimeMillis();
        Session s = null;
        Transaction tx = null;
        try {
            s = getSession();
            //tx = s.beginTransaction();    // now done by the container.
           
            SupplierPartDTO sup = (SupplierPartDTO)s.load(SupplierPartDTO.class, supplierPartID, LockMode.UPGRADE );
            PurchaseOrderDTO po = (PurchaseOrderDTO)s.load(PurchaseOrderDTO.class, poid, LockMode.UPGRADE );
            StockItemDTO si = (StockItemDTO)s.load(StockItemDTO.class, sup.getStock().getID(), LockMode.UPGRADE );

            if( po.getCompany()!=sup.getCompany() ) {
                // cant add a part from a different supplier.
                throw new PurchaseOrderDBException("Cannot add a part from a different supplier. PurchaseOrder is for " + po.getCompany().getName() + " part if supplier by " + sup.getCompany().getName() );
            }
           

            PurchaseOrderLineItemDTO poli  = new PurchaseOrderLineItemDTO();

            poli.setConversion( sup.getConversionRate() );
            poli.setDescription( sup.getDescription() );
            //poli.setID(   // Assigned by DB
            poli.setLineNo( po.getLineItems() .size() + 1 );
            //poli.setPurchaseOrder( // Assigned when we add to the PO
            poli.setStockItem( si );
            poli.setStockQuantity( qty * sup.getConversionRate() );
            poli.setSupplierPart( sup );
            poli.setSupplierQty( qty );
            poli.setSupplierQtyReceived( 0 );
            poli.setSupplierStockCode( sup.getSupplierPartNumber() );
            poli.setTotal( qty * sup.getPrice() );
            poli.setUnitPrice( sup.getPrice() );
           
           
            po.addLineItem( poli );
            po.updateTotals();
           
            if( po.getSentDate()!=null ) {
                // PO has been sent, so adjust qty on order.
                si.setQuantityOnOrderPO( si.getQuantityOnOrderPO()+poli.getStockQuantity() );
            }
           
            s.update(si);
            s.save( poli );
           
            // make sure the status is correct.
            updatePOStatus(s, po);
            s.update(po);
           
            s.flush();
            //tx.commit();  // now done by the container.
            log.debug("Success addPOLineItem");

           
            if( (0+1)==1 ) {    // need this otherwise we get compiler erros about code not being reachable.
                // Throw an exception.
                // If everything is working, the add line item should be rolledback
                throw new PurchaseOrderDBException("TESTING FAILURE NOTHING SHOULD HAPPEN TO THE DB");
            }
           
           
        } catch(HibernateException he ) {
            log.error("Failure addPOLineItem", he );
            try {
                if(tx!=null) tx.rollback();
            } catch( HibernateException rbe ) {
                log.error( "Failed to rollback transaction", rbe ) ;
            }
            throw new PurchaseOrderDBException("Hibernate problem");
        } finally {
            if( s!=null ) try{ s.close(); }catch(Exception e) {}
        }
       
        if( log.isDebugEnabled() ) {
            long endTime = System.currentTimeMillis();
            long dur = endTime - startTime;
            log.debug( "PERFORMANCE: addPOLineItem " + poid + " took " + dur + "ms" );
        }
        System.out.println("EXIT addPOLineItem");
    }


Notice after all the DB manipulation I have inserted a throw("TESTING..") exception.


Hibernate JMX config.
Code:
<server>
<mbean code="net.sf.hibernate.jmx.HibernateService" name="jboss.jca:service=HibernateFactory,
                            name=HibernateFactory">
    <depends>jboss.jca:service=RARDeployer</depends>
    <depends>jboss.jca:service=LocalTxCM,name=StarjarCRMDS</depends>


    <classpath codebase='.' archives='starjarcrmdb.jar' />
   
    <!-- Make it deploy ONLY after DataSource had been started -->
    <attribute name="MapResources">
mappings/AddressDTO.hbm.xml,          mappings/PurchaseOrderDTO.hbm.xml,
mappings/BOMComponentDTO.hbm.xml,     mappings/PurchaseOrderLineItemDTO.hbm.xml,
mappings/BOMDTO.hbm.xml,              mappings/QuoteDTO.hbm.xml,
mappings/CategoryDTO.hbm.xml,         mappings/QuoteLineItemDTO.hbm.xml,
mappings/CompanyDTO.hbm.xml,          mappings/QuoteSectionDTO.hbm.xml,
mappings/ConfigDTO.hbm.xml,           mappings/QuoteValidityDTO.hbm.xml,
mappings/ContactCategoryDTO.hbm.xml,  mappings/SalesAreaDTO.hbm.xml,
mappings/ContactDTO.hbm.xml,          mappings/SalesChannelDTO.hbm.xml,
mappings/ContactStatusDTO.hbm.xml,    mappings/SalesOrderDTO.hbm.xml,
mappings/ContactTitlesDTO.hbm.xml,    mappings/SalesOrderLineItemDTO.hbm.xml,
mappings/ContactTypeDTO.hbm.xml,      mappings/SpecialProductsDTO.hbm.xml,
mappings/CorrespondenceDTO.hbm.xml,   mappings/StockItemDTO.hbm.xml,
mappings/CountriesDTO.hbm.xml,        mappings/StockTransactionDTO.hbm.xml,
mappings/CountyDTO.hbm.xml,           mappings/SupplierPartDTO.hbm.xml,
mappings/DeliveryOptionsDTO.hbm.xml,  mappings/TaskActivitiesDTO.hbm.xml,
mappings/HistoryActionsDTO.hbm.xml,   mappings/TaskDTO.hbm.xml,
mappings/HistoryDTO.hbm.xml,          mappings/UserDTO.hbm.xml,
mappings/IndustrySectorDTO.hbm.xml,   mappings/WorkOrderDTO.hbm.xml,
mappings/PaymentTermsDTO.hbm.xml,     mappings/WorkOrderLineItemDTO.hbm.xml,
mappings/PhoneNumberDTO.hbm.xml
    </attribute>
    <attribute name="JndiName">java:/hibernate/HibernateFactory</attribute>
    <attribute name="Datasource">java:/StarjarCRMDS</attribute>
    <attribute name="Dialect">net.sf.hibernate.dialect.PostgreSQLDialect</attribute>
    <attribute name="TransactionStrategy">net.sf.hibernate.transaction.JTATransactionFactory</attribute>
    <attribute name="TransactionManagerLookupStrategy">net.sf.hibernate.transaction.JBossTransactionManagerLookup</attribute>
    <attribute name="UseOuterJoin">false</attribute>
    <attribute name="ShowSql">false</attribute>
    <attribute name="UserTransactionName">java:/UserTransaction</attribute>
    <!--attribute name="UserTransactionName">java:comp/UserTransaction</attribute-->
    <!--attribute name="UserTransactionName">java:comp/UserTransaction/</attribute-->
   
</mbean>
</server>




Datasouce config
Code:
<datasources>
  <local-tx-datasource>
    <jndi-name>StarjarCRMDS</jndi-name>
    <connection-url>jdbc:postgresql://192.168.200.50:5432/starjarcrm</connection-url>
    <driver-class>org.postgresql.Driver</driver-class>
    <user-name>postgres</user-name>
    <password></password>
    <transaction-isolation>TRANSACTION_SERIALIZABLE</transaction-isolation>
  </local-tx-datasource>

</datasources>


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 01, 2003 6:26 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
The J2EE spec specifies that ONLY unchecked exceptions will cause a transaction rollback.

This problem is, of course, nothing to do with Hibernate.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 01, 2003 10:22 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
Whenever exceptions occur in CMT beans, it is generally good pratice to doom the current transaction using the javax.ejb.EJBContext.setRollbackOnly() method. That way you can be certain the transaction will not be allowed to commit.

Assuming you've stored off the SessionContext given to you by the container as sessionContext:
Code:
    ...
    }
    catch(HibernateException he )
    {
        log.error("Failure addPOLineItem", he );
// This is all unnecessary
//        try
//       {
//            if(tx!=null) tx.rollback();
//        }
//        catch( HibernateException rbe )
//        {
//            log.error( "Failed to rollback transaction", rbe ) ;
//        }
        try
        {
            sessionContext.setRollbackOnly();
        }
        catch( Exception e )
        {
            log.warn( "Unable to doom transaction", e );
        }
        throw new PurchaseOrderDBException("Hibernate problem");
    }


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 01, 2003 10:31 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Please not also that


Transaction.rollback() calls setRollbackOnly()


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 02, 2003 4:41 am 
Newbie

Joined: Sat Aug 30, 2003 5:46 am
Posts: 5
Thanks for the feedback guys.

Im now calling ctx.setRollbackOnly(); just prior to throwing my test exception, yet the reccord that shouldnt be commited, is making its way into the DB.

Code:
                System.out.println("About to call ctx.setRollbackOnly()");
                ctx.setRollbackOnly();
                throw new PurchaseOrderDBException("TESTING FAILURE NOTHING SHOULD HAPPEN TO THE DB");


Does this mean that the Jboss transaction and Hibernate are not aware of each other?



Feeling even denser than normal, they put me on valium to visit the dentist.


Peter Henderson


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 02, 2003 4:47 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Perhaps your datasource is not aware of JTA?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 15, 2003 12:51 pm 
Beginner
Beginner

Joined: Mon Sep 15, 2003 12:41 pm
Posts: 21
gavin wrote:
Perhaps your datasource is not aware of JTA?


I just met the same problem on pure Postgres/Hibernate project
(no EJB, I mean). Tracing queries on the server side I see that
commit is issued immediately after call to save(); when I call
rollback after that, nothing to rollback already.

Server is configured to have autocommit=false, and even
when I set ses.connection().setAutocommit(false) the same
continues to happen.

The scenario is like following: an object with id generator=native
is created and save is called. Here I see select from hibernate_sequence,
then rollback; then insert and commit! But I haven't committed yet.

I'm using JDBC2 Postgres driver, it could be their fault... I'll
try JDBC3 soon, and I'll extract minimal test to confirm the
bug(?) this week.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 15, 2003 12:56 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Quote:
and I'll extract minimal test to confirm the bug(?) this week.


OK, but I'm quite certain that this has nothing to do with Hibernate, so don't send it to me!


Last edited by gavin on Mon Sep 15, 2003 1:01 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 15, 2003 1:00 pm 
Beginner
Beginner

Joined: Mon Sep 15, 2003 12:41 pm
Posts: 21
gavin wrote:


OK, but I'm quite certain that this has nothing to do with Hibernate, so don't send it to me!
[/quote]

If I'll find out that you're right, I'll send it ... not to you ;)
But anyway -- if and until it exists it would be good if Hibernate
community and newbies would be aware. So I'll just post the
results (if any) here.


Top
 Profile  
 
 Post subject: Mmm... Bug?
PostPosted: Mon Sep 15, 2003 5:02 pm 
Beginner
Beginner

Joined: Mon Sep 15, 2003 12:41 pm
Posts: 21
I was wrong about Postgres JDBC driver, it's OK.
The problem was in my code, but, indeed, I close to
believe here is a bug in Hibernate (or I'am misundertanding
something).

Here is the test. It starts transaction, creates
an object, then rolles back the transaction. No SQL issued.
In the same session, it starts new transaction and attempts
to load the created object by id -- and succeeds! In my opinion,
it shall fail here: the object disappeared with the rolled back
transaction, it doesn't exists in DB, it exists only in Session
cache.

If you uncomment lines (1) and (2), i.e. start new session,
the test will pass.

Is it bug?

Code:
    public void testTxRollback() throws Exception
    {
        Configuration cfg = new Configuration();
        cfg.addFile("Foo.hbm.xml");       

        SessionFactory sessions = cfg.buildSessionFactory();
       
        // new SchemaExport(cfg).create(true, true);
       
        Session ses = sessions.openSession();
        Transaction tx = ses.beginTransaction();
       
        Foo foo = new Foo("Hello,world");
        ses.save(foo);
        System.out.println("foo.id="+foo.getId());
        System.out.println("foo.name="+foo.getName());
       
        tx.rollback();
        // ses.close(); // (1)
       
        // ses = sessions.openSession(); // (2)
        tx = ses.beginTransaction();
        try
        {
            ses.load(Foo.class, new Long(foo.getId()));
            fail("oops: it shouldn't be visible");           
        }
        catch( Exception ex )
        {
            ex.printStackTrace();
        }
        ses.close();               
    }


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 15, 2003 6:48 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 7:19 pm
Posts: 2364
Location: Brisbane, Australia
Try flushing the session before you roll it back. This syncs the system so the rollback will work correctly.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 15, 2003 9:39 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
You are not allowed to keep working with the session after a transaction rolls back.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 16, 2003 2:27 am 
Beginner
Beginner

Joined: Mon Sep 15, 2003 12:41 pm
Posts: 21
gavin wrote:
You are not allowed to keep working with the session after a transaction rolls back.


I see, thanx.

Well, can you then somehow enforce it in runtime?
For example, throw an exception with appropriate
message when any usage of Session happens after
tx.rollback()?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.