Forums

Home » Liferay Portal » English » 3. Development

Combination View Flat View Tree View
Threads [ Previous | Next ]
toggle
Andrey Filippov
Transaction propagation
October 21, 2010 8:41 AM
Answer

Andrey Filippov

Rank: New Member

Posts: 23

Join Date: October 21, 2010

Recent Posts

Hi,

We ran into the transaction problem in our project. Imagine the situation when in *LocalServiceImpl method there are several entities created. Some of these entities are portal specific (e.g. User, Company, JournalArticle etc.) and some of them were created with ServiceBuilder. If I throw SystemException in the end of this method I will have all portal entities rolled back but all plugin entities stored in the db directly (somehow they are not wrapped with transaction). I suppose that this is lack of config, but I compared all configurations with other portlets (e.g. mail-portlet) - they look similar. We use Tomcat and Mysql but all tables have InnoDB engine. Could somebody help?

Sorry if I miss thread with the same topic.
Deb Troxel
RE: Transaction propagation
October 21, 2010 11:28 AM
Answer

Deb Troxel

Rank: Junior Member

Posts: 81

Join Date: February 22, 2010

Recent Posts

Are you including a reference to the Portal classes in your Entity? e.g.
1<reference package-path="com.liferay.portal" entity="User" />


My understanding is that you need to reference the injected service (it will appear in your *ServiceBaseImpl class) if you want to use the same transaction and that if you call the Util methods they will be separate transactions.

I haven't tried this myself, so please let us know if this works.
Andrey Filippov
RE: Transaction propagation
October 22, 2010 3:15 AM
Answer

Andrey Filippov

Rank: New Member

Posts: 23

Join Date: October 21, 2010

Recent Posts

Thanks Deb for the quick response. Actually it also will not work. I added:

1    @BeanReference(type = SocialActivityLocalService.class)
2    protected SocialActivityLocalService socialActivityLocalService;


manually both for SocialActivity and JournalArticle entities - nothing happened. After debugging I found a strange thing - all save operatians logically goes through com.liferay.portal.dao.orm.hibernate.SessionImpl class. That class has _session variable of org.hibernate.Session type. In this _session we have reference to JDBCContext object where finally info about hibernate ttransaction is stored. So this JDBCContext is completely different for my entities and for portals. In my case hibernateTransaction variable inside JDBCContext is null, but it is not for portals objects... I could not find out the reason... Or this is just wrong searching direction.
Appreciate your help.
Andrey Filippov
RE: Transaction propagation
October 24, 2010 11:58 AM
Answer

Andrey Filippov

Rank: New Member

Posts: 23

Join Date: October 21, 2010

Recent Posts

Guys, probably somebody from the staff could explain such a strange behaviour? This is a bit crucial - I think...

Thanks.
Tomas Polesovsky
RE: Transaction propagation
October 24, 2010 12:35 PM
Answer

Tomas Polesovsky

LIFERAY STAFF

Rank: Liferay Master

Posts: 643

Join Date: February 13, 2009

Recent Posts

Hi


AFAIK there isn't one hibernate session. Each web app has its own hibernate session. I.e. Portal has one and you application has another one.

I suppose you use 6. Liferay 6 config files are different from Liferay 5. I've looked for a moment at the spring configs for 6.0 portlets and I see:
1    <bean id="liferayTransactionManager" class="com.liferay.portal.kernel.util.InfrastructureUtil" factory-method="getTransactionManager" />


In Liferay 5.2.3 transaction manager has used portlet's hibernate session:
1    <bean id="liferayHibernateSessionFactory" class="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration">
2        <property name="dataSource" ref="liferayDataSource" />
3    </bean>
4    <bean id="liferayTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
5        <property name="dataSource" ref="liferayDataSource" />
6        <property name="globalRollbackOnParticipationFailure" value="false" />
7        <property name="sessionFactory" ref="liferayHibernateSessionFactory" />
8    </bean>


I guess that in Liferay 6 InfrastructureUtil returns portal's transaction manager that applies to portal's hibernate session. Now I really guess - maybe if you rollback transaction then Portal's transaction manager rollbacks only Hibernate session that belongs to portal, not your plugin.

-- tom
Andrey Filippov
RE: Transaction propagation
October 25, 2010 9:50 AM
Answer

Andrey Filippov

Rank: New Member

Posts: 23

Join Date: October 21, 2010

Recent Posts

Thanks for your reply Tom. Well the truth is somewhere in the middle... For both - my plugin and portal I am getting HibernateTransactionManager instance. And when I try to save objects (nothing matter portal or plugin) it looks that every save invocation is being surrounded with transaction. But when I put breakpoint into com.liferay.portal.dao.orm.hibernate.SessionImpl save method, in the hibernate session instance I could see only one difference - in the JDBCContext. For portal transactions hibernateTransaction is present, but for plugin it is null. It just completely breaks my head off - could not find the reason((

Thanks.
Andrey Filippov
RE: Transaction propagation
October 26, 2010 5:44 AM
Answer

Andrey Filippov

Rank: New Member

Posts: 23

Join Date: October 21, 2010

Recent Posts

Still not solved...

It is not clear if the stated behaviour is expected and correct.
...or it is possible to tell liferay to synchronize transactions from multiple different hibernate sessions (but 1 transaction manager) and have rollback possibility at least.
Deb Troxel
RE: Transaction propagation
October 26, 2010 2:58 PM
Answer

Deb Troxel

Rank: Junior Member

Posts: 81

Join Date: February 22, 2010

Recent Posts

Hi Andrey,

I do not think this is the expected behavior. I have been reading Rich Sezov's Liferay in Action book and the way he describes Service Builder transactions is the way you would expect them to work. On an exception everything should roll back, both Portal and Plugin entities.

I created a test portlet and was able to reproduce exactly what you see. Portal changes are rolled back, plugin entities are not.

I'm running Liferay 6.0.5 / Glassfish 2 / PostgreSQL

I can upload my sample code and open a bug report issue unless anyone can suggest what we might be missing here.
Deb Troxel
RE: Transaction propagation
October 27, 2010 2:50 PM
Answer

Deb Troxel

Rank: Junior Member

Posts: 81

Join Date: February 22, 2010

Recent Posts

Opened http://issues.liferay.com/browse/LPS-13454
Andrey Filippov
RE: Transaction propagation
October 28, 2010 8:47 AM
Answer

Andrey Filippov

Rank: New Member

Posts: 23

Join Date: October 21, 2010

Recent Posts

Hi Deb,

I also created small test portlet - everything as was described - I could confirm. Three cases were took into account:
1. Rollback for my own dummy object
2. Rollback for portal object
3. Rollback for both together
Dummy object is not rolled back in any case. I could share my code if necessary.
Deb Troxel
RE: Transaction propagation
October 29, 2010 1:23 PM
Answer

Deb Troxel

Rank: Junior Member

Posts: 81

Join Date: February 22, 2010

Recent Posts

More info:

I discovered that I have been getting this error when I deploy.

Error in annotation processing: java.lang.NoClassDefFoundError: org/springframework/transaction/PlatformTransactionManager

I found this post, which describes getting the same error when using EJBs. (Thanks Google Translate)

I am not using EJB but tried this solution of copying the spring dependencies to the glassfish domain lib. The exception disappeared, but the transaction roll back still didn't work.

First I tried just copying those files, then I tried removing them from the Liferay lib folder to ensure that they were coming from the common classloader, but still the transaction doesn't seem to be shared.

I am surprised that others don't seem to be complaining, so I still have to wonder if I am doing something stupid.

I am attaching a test war if anyone else is willing to try it. This is a portlet with two buttons. "Create Successfully" button calls FooLocalServiceUtil.addFoo() to insert a Foo record and a SocialActivity record. "Create With Exception" button calls addFooWithException() to do the same and then throw an exception.

When an exception is thrown, the SocialActivity record is rolled back, but the Foo record remains in the database.
Attachments: transaction-sample-portlet.zip (228.3k)
Francois Fournel
RE: Transaction propagation
January 7, 2011 7:17 AM
Answer

Francois Fournel

Rank: Junior Member

Posts: 99

Join Date: April 15, 2010

Recent Posts

Same problem for me. I don't manage to use transaction in my custom portlet. My use case is:

1)Call method "DeleteA" at ServiceALocalServiceImpl

Then in method "DeleteA", it calls "serviceBLocalService.DeleteB" the variable serviceBLocalService being a spring bean reference of course.
Then throw a PortalException() for sure.

2)In method "DeleteB" at ServiceBLocalServiceImpl a delete occurs for sure (return success).

In the above case, "DeleteB" should be rolled back because the original call to DeleteA has failed, more precisely after the "DeleteB" succeed in deleting a record.
As a result, I have the record deleted by "DeleteB" and so method "DeleteA" has not been rolled back.


That's a problem for my custom portlet.

Any help ?
Francois Fournel
RE: Transaction propagation
February 1, 2011 9:55 AM
Answer

Francois Fournel

Rank: Junior Member

Posts: 99

Join Date: April 15, 2010

Recent Posts

Deb Troxel >

The problem was solved. See opened "issue" above.
It works for me (Tomcat bundle with Liferay 6.0.5 CE + MySQL)

Regards.
Deb Troxel
RE: Transaction propagation
February 1, 2011 12:42 PM
Answer

Deb Troxel

Rank: Junior Member

Posts: 81

Join Date: February 22, 2010

Recent Posts

Thanks Francois, but I am not convinced that my situation is the same. I am using the Glassfish 2.1 application server, which has built-in transaction management. Using JOTM with Tomcat makes sense to me, but I don't believe it's appropriate with Glassfish. (If someone has experience otherwise, please correct me.)

I haven't had time to do in-depth research on distributed transaction configuration under Glassfish, so was hoping someone here might have the experience to point in the right direction.
Laurent Gauthier
RE: Transaction propagation
June 1, 2011 5:58 PM
Answer

Laurent Gauthier

Rank: New Member

Posts: 15

Join Date: February 2, 2010

Recent Posts

For anybody reading this thread and trying to figure out how to ensure transactions are rolled back on error in a ServiceBuilder generated service that invokes Portal services, here are a few pointers:

1) Make sure you are using JTA (this is not the default with Tomcat , see references in this thread)

2) Service builder uses isolation.PORTAL by default. That implies that portal transactions are rolled back but not your service tx. To rollback all DB writes on exception, make sure you mark your method with isolation = Isolation.DEFAULT. For example use the following annotation or something similar:

@Transactional(isolation = Isolation.DEFAULT, rollbackFor = {
PortalException.class, SystemException.class}
)

3) Make sure you throw unchecked (Runtime) exceptions if you want the tx to be rolledback (unless you specified your exceptions in the rollbackFor clause of the annotation).

4) If you use MySQL, make sure your tables are all configured with InnoDB engine...

Have fun...

Final note: An alternative to item #2 is to set the following in your portal-ext.properties.

transaction.isolation.portal=-1

This has a global effect and in fact redefines the value associated with isolation.PORTAL from 2 to -1 which is the databases default isolation level.
Julien Ripault
RE: Transaction propagation
July 19, 2012 9:14 AM
Answer

Julien Ripault

Rank: New Member

Posts: 15

Join Date: March 19, 2012

Recent Posts

Hi,

I have this exact problem, meaning I use consecutively multiple liferay services: create an organization and then a user

And if the user creation fails, the organization is not rolled back.

I tried to annotate my service with @Transactional(isolation = Isolation.DEFAULT, rollbackFor = {PortalException.class, SystemException.class}). I did not work.

I tried the transaction.isolation.portal=-1 but not working as well.

In fact, I was thinking that as I have my own webapp, I surely did not use the same instance of Transaction Manager as Liferay's services so I quite understand why the rollback is not done. But it is weird that one cannot encapsulate with a transaction, multiple calls to liferay's services.

If someone has a solution, I'll be so glad emoticon

Thanks
Federico Miralles
RE: Transaction propagation
March 12, 2013 10:38 AM
Answer

Federico Miralles

Rank: New Member

Posts: 7

Join Date: September 20, 2012

Recent Posts

Hi Julien,

You could check:

Liferay Transactional Custom Services Made Easy

Federico Miralles @Rotterdam CS BV
Tanaji Londhe
RE: Transaction propagation
March 23, 2013 2:34 AM
Answer

Tanaji Londhe

Rank: Regular Member

Posts: 196

Join Date: April 25, 2012

Recent Posts

Hi Federico,
In my case Organization from liferay which is related Company in my custom DB. I have create DAO(i m not using service builder for DAO) for Company to perform CRUD operation.
Now here when i add any Company(thourgh custom ui) into my custom db that time i m adding Organization in a Liferay using Liferay API (eg
OrganizationLocalServiceUtil.add(organization) ). Both are running on different transaction.
How can i warp these two transaction into a single trasaction so i can rollback it.