Транзакции в Liferay

Те, кто активно используют Service Builder понимают, что поддержка транзакций в сгенерированных сервисах просто необходима. Более того, это даже предусмотрено разработчиками портала. Но есть загвоздка — это не работает. По крайней мере с версией 6.0.5.

На странице http://issues.liferay.com/browse/LPS-15904 описана причина этого дефекта.

Как правило, портлеты создают новую SessionFactory для загрузки собственных hbm файлов. Также известно, что портал и портлеты используют один и тот же менеджер для создания транзакций, который в свою очередь использует SessionFactory портала. Однако портлеты должны использовать свои собственные SessionFactory, иначе портлетные сессии не будут использоваться в портальных транзакциях. Результат — транзакции в портлетах вообще не работают.

Как вариант решения можно использовать JTA transaction manager. Eсть две библиотеки на выбор: JOTM или Atomikos. На сайте Liferay есть даже статья, которая описывает как настроить портал для каждой из библитек — http://www.liferay.com/community/wiki/-/wiki/Main/JTA-XA+on+Tomcat. Но к сожалению статья не помогла. Только после продолжительного поиска удалось найти работающее решение.

Настройка портала с библиотекой JOTM:
  1. Скачиваем библиотеку с сайта http://forge.ow2.org/projects/jotm, отдельно обновляем библиотеку xapool до последней версии, даже если это бета-версия;
  2. Добавляем необходимые jar-файлы в {tomcat}/lib:
  3. Удаляем commons-logging.jar из {tomcat}/lib/ext и log4j.jar из {tomcat}/webapps/ROOT/WEB-INF/lib а также из каждого портлета;
  4. Находим файл {tomcat}/conf/context.xml и добавляем следующее в конец секции Context:
  5. <Resource 
       auth="Container" 
       name="UserTransaction" 
       type="javax.transaction.UserTransaction" />
        
    <Resource 
       auth="Container" 
       driverclassname="com.mysql.jdbc.Driver" 
       factory="org.objectweb.jotm.datasource.DataSourceFactory" 
       max-connections="100" 
       maxactive="20" 
       name="jdbc/LiferayPool" 
       username="root" 
       password="" 
       type="javax.sql.DataSource" 
       url="jdbc:mysql://localhost/lportal?useUnicode=true&amp;characterEncoding=UTF-8
          &amp;useFastDateParsing=false" /> 
        
    <Transaction 
      factory="org.objectweb.jotm.UserTransactionFactory" 
      jotm.timeout="60" />
    
    
  6. Комментируем все jdbc.default.* свойства в portal-ext.properties, а затем добавляем следующее:
  7. transaction.manager.impl=org.springframework.transaction.jta.JtaTransactionManager
    transaction.manager.property.allowCustomIsolationLevels=true
    transaction.manager.property.globalRollbackOnParticipationFailure=true
    jdbc.default.jndi.name=jdbc/LiferayPool
    
Это собственно и все. Гарантий никаких, в моем случае это заработало, в любом другом может и не заработать — это Liferay.