Ошибка «транзакция не выполняется» при использовании @Transactional - PullRequest
1 голос
/ 29 июня 2011

Все, я пытаюсь использовать аннотационную транзакцию в Spring и получаю javax.persistence.TransactionRequiredException: транзакция не выполняется

ошибка все время.

Ошибка трассировки стека:

[22:40:11:354] 00000024 SystemErr     R javax.persistence.TransactionRequiredException: no transaction is in progress
[22:40:11:354] 00000024 SystemErr     R     at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:301)
[22:40:11:354] 00000024 SystemErr     R     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[22:40:11:354] 00000024 SystemErr     R     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
[22:40:11:354] 00000024 SystemErr     R     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
[22:40:11:354] 00000024 SystemErr     R     at java.lang.reflect.Method.invoke(Method.java:611)
[22:40:11:354] 00000024 SystemErr     R     at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
[22:40:11:354] 00000024 SystemErr     R     at $Proxy45.flush(Unknown Source)
[22:40:11:354] 00000024 SystemErr     R     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[22:40:11:354] 00000024 SystemErr     R     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
[22:40:11:354] 00000024 SystemErr     R     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
[22:40:11:354] 00000024 SystemErr     R     at java.lang.reflect.Method.invoke(Method.java:611)
[22:40:11:354] 00000024 SystemErr     R     at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
[22:40:11:354] 00000024 SystemErr     R     at $Proxy42.flush(Unknown Source)
[22:40:11:354] 00000024 SystemErr     R     at com.test.MyDAO.saveOrUpdateData
.
.
.

Обратите внимание, что тот же код работает нормально, когда я использую AOP.

Технологический стек выглядит следующим образом:

Spring 3.0.5
Struts 2.2.1.1
Hibernate 3.3.2GA
JPA 1.0
JBPM 4.4

Вот мои конфигурации приложения:

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean
        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <!--    <bean-->
    <!--        class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />-->


    <jee:jndi-lookup id="dataSource" jndi-name="jdbc/my_dataSource1.1"
        cache="true" resource-ref="true" lookup-on-startup="true"
        proxy-interface="javax.sql.DataSource" />

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="persistenceXmlLocation" value="META-INF/my-persistence.xml" />
    </bean>

<!--    
Also tried the JTA transaction manager....

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">

-->
    <bean id="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>

    <tx:annotation-driven/>


<!--    <tx:advice id="txAdvice" transaction-manager="transactionManager">-->
<!--        <tx:attributes>-->
<!--            <tx:method name="get*" read-only="true" />-->
<!--            <tx:method name="saveOrUpdate*" propagation="REQUIRES_NEW" read-only="false"/>-->
<!--        </tx:attributes>-->
<!--    </tx:advice>-->
<!--    <aop:config>-->
<!--        <aop:pointcut id="daoOperations"-->
<!--            expression="execution(* com.honda.naps.dao..*.*(..))" />-->
<!--        <aop:advisor advice-ref="txAdvice" pointcut-ref="daoOperations" />-->
<!--    </aop:config>-->


     <!-- This is the DAO that's injected -->
     <bean id="myDAO" class="com.test.MyDAO" />
     <bean id="myBaseDAO" class="com.test.BaseDAO" />
     <!-- 
          This is the struts action that's created .. in struts.xml I have used
          <constant name="struts.objectFactory" value="spring" />
      -->    
      <bean id="myAction" scope="prototype" class="com.test.MyAction">
      </bean>

       <!-- My BO instance -->
       <bean id="myBO" class="com.test.MyBOImpl">
          <property name="myDAO" ref="myDAO" />
          <property name="myBaseDAO" ref="myBaseDAO" />
        </bean>

</beans>

Также в struts.xml я вызываю saveOrUpdateData () для класса MyDAO.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" metadata-complete="true">
    <display-name>NAPSWeb</display-name>
    <context-param>
        <param-name>
            org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG</param-name>
        <param-value>/WEB-INF/tiles.xml</param-value>
    </context-param>

    <context-param> 
        <param-name>log4jConfigLocation</param-name> 
        <param-value>/WEB-INF/resources/log4j.properties</param-value> 
    </context-param>

    <context-param>   
        <param-name>log4jRefreshInterval</param-name> 
        <param-value>1000</param-value> 
    </context-param>    

    <listener> 
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> 
    </listener>

    <listener>
        <listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring_config/applicationContext.xml</param-value>
    </context-param>
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>
            org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>*.action</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/struts/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <distributable></distributable>

</web-app>

my-persistence.xml

http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version = "1.0"> org.hibernate.ejb.HibernatePersistence jdbc / my_dataSource1.1

<class>com.test.MyTbl1</class>
<class>com.test.MyTbl2</class>
<class>com.test.MyTbl3</class>    

<properties>
        <!-- HIBERNATE properties --> 
        <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.CMTTransactionFactory"/> 
        <!--  <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.WebSphereExtendedJTATransactionLookup"/> -->
        <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.WebSphereTransactionManagerLookup"/>
        <property name="jta.UserTransaction" value="java:comp/UserTransaction"/> 
        <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
        <!--        <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>-->
        <property name="hibernate.showsql" value="true"/>
        <!--        <property name="hibernate.cache.use_second_level_cache" value="false"/>        -->
        <!--   <property name="jta.UserTransaction" value="java:comp/UserTransaction"/> -->
        <property name="databasePlatform" value="org.hibernate.dialect.SQLServerDialect"/> 

</properties>

</persistence-unit>

Класс метода DAO, использующий @Transactional, выглядит следующим образом:

// Класс MyDAO

public class MyDAO extends BaseDAO
{
    @Transactional(propagation=Propagation.REQUIRES_NEW, readOnly=false)
    public void saveOrUpdateData()
    {
        MyTbl1 mt1 = new MyTbl1();
        //do something with mt1
        getEntityManager().persist(mt1);
        getEntityManager().flush();
    }
}

BaseDAO класс:

public class BaseDAO {

    /**
     * Variable which stores the injected 
     * JPA Entity Manager.
     */ 
    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        System.out.println("getting the entity manager.");
        return entityManager;
    }

    @PersistenceContext(unitName="MY_JPA")
    public void setEntityManager(EntityManager entityManager) {
        logger.debug("Setting the entity manager.");
        this.entityManager = entityManager;
    }

}

Используемые библиотеки:

ejb3-persistence.jar
hibernate-annotations.jar
hibernate-commons-annotations.jar
hibernate-entitymanager.jar
hibernate3.3.2.GA.jar    
antlr-2.7.6.jar
aopalliance-1.0.jar
asm-1.5.3.jar
asm-all-2.2.3.jar
aspectjrt.jar
aspectjweaver.jar
cglib-nodep-2.1_3.jar
commons-beanutils-1.8.0.jar
commons-collections-3.1.jar
commons-digester-1.8.1.jar
commons-io-1.3.2.jar
commons-logging-1.0.4.jar
commons-logging-api-1.1.jar
dom4j-1.6.1.jar
freemarker-2.3.8.jar
javassist-3.12.0.GA.jar
jbpm.jar
juel-api.jar
juel-engine.jar
juel-impl.jar
log4j-1.2.16.jar
ognl-3.0.jar
org.springframework.aop-3.0.5.RELEASE.jar
org.springframework.asm-3.0.5.RELEASE.jar
org.springframework.aspects-3.0.5.RELEASE.jar
org.springframework.beans-3.0.5.RELEASE.jar
org.springframework.context-3.0.5.RELEASE.jar
org.springframework.context.support-3.0.5.RELEASE.jar
org.springframework.core-3.0.5.RELEASE.jar
org.springframework.expression-3.0.5.RELEASE.jar
org.springframework.jdbc-3.0.5.RELEASE.jar
org.springframework.orm-3.0.5.RELEASE.jar
org.springframework.transaction-3.0.5.RELEASE.jar
org.springframework.web-3.0.5.RELEASE.jar
slf4j-api-1.6.1.jar
slf4j-nop-1.6.1.jar
struts2-convention-plugin-2.2.1.1.jar
struts2-core-2.2.1.1.jar
struts2-dojo-plugin-2.2.1.1.jar
struts2-json-plugin-2.2.1.jar
struts2-spring-plugin-2.2.1.1.jar
struts2-tiles-plugin-2.1.6.jar
tiles-api-2.1.2.jar
tiles-compat-2.1.2.jar
tiles-core-2.1.2.jar
tiles-jsp-2.1.2.jar
tiles-servlet-2.1.2.jar
xwork-core-2.2.1.1.jar

Конфигурация системы:

Websphere App server TE 7.0.0.15 in RAD IDE 7.5
OS: Windows XP SP3
DB: MS SQL Server 2008 enterprise edition

У меня включена загрузка класса parent_last и назначен поставщик JPA по умолчанию как "org.hibernate.ejb.HibernatePersistence" на моем сервере приложений Websphere.

Любая помощь приветствуется.

Спасибо

=============================================

Добавление этого для всеобщего пользования ...

Мне, наконец, пришлось заняться управлением транзакциями на основе AOP.Я не смог найти способ заставить @Transactional работать в моем приложении.

Добавление ниже части, которую я добавил для интеграции AOP в свое приложение (в applicationContext.xml):

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="get*" read-only="true" />
        <tx:method name="saveOrUpdate*" propagation="REQUIRES_NEW" read-only="false"/>
    </tx:attributes>
</tx:advice>
<aop:config>
    <aop:pointcut id="daoOperations"
        expression="execution(* com.test..*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="daoOperations" />
</aop:config>

Надеюсь, это поможет,

1 Ответ

0 голосов
/ 29 июня 2011

Контекст приложения должен обернуть myDao рекомендованным прокси.Отслеживание стека обрывается при вызове dao.saveOrUpdateData.Если вы исследуете трассировку стека за пределами этого вызова в трассировке стека, вы должны найти прокси-сервер DAO, обертывающий реальный вызов метода DAO в вызове TransactionsTemplate.doInTransaction.Если это не так, то эта проблема может проявляться, потому что вы непосредственно вводите bean-компонент myDao в свой BO.Автоматическое подключение myDao к BO может работать.

...