1

Spring、JPA、GlassFish 3.1 で初めてのプロジェクトを行っていますが、いくつか問題があります。一週間解決策を探していましたが、何も見つかりませんでした。

Entity (Role と呼ばれる)、任意のエンティティにアクセスするための一般的なメソッドを備えた GeneralReposiroty、Role に関する特定のメソッドを実装する RoleRepository、および RoleRepository を呼び出す Service クラスがあります。Service クラスのメソッドはトランザクションですが、propagation プロパティが REQUIRED、REQUIRES_NEW、または NESTED の場合、RollBackException が発生します。伝播が必須の場合、次のような例外がスローされます。

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:339)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:262)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:101)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
    ...

NOT_SUPPORTED、NEVER、または SUPPORT の場合、選択クエリは正常に機能しますが、作成、更新、または削除クエリを実行しようとすると、同じ RollbackException が発生します。

選択クエリをデバッグしましたが、RollBackException がスローされる前に、クエリは正常に結果を取得し、例外は関数の最後にスローされます。さらに、EntityManager の find() でエンティティを取得し、サービス メソッドに @Transactional アノテーションがない場合は正常に動作しますが、トランザクション対応にすると、同じ例外でクラッシュします。

これは私が持っているすべてのエンティティで発生しますが、それを使用して問題を説明します。

Spring の構成に何か問題があると思いますが、何が原因かわかりません。

これは例外の完全なトレースです (いくつかの行では、AuthenticationSuccessHandler クラスへの参照があります。これは、サービス クラスを呼び出す場所だからです)。

WARNING: StandardWrapperValve[default]: PWC1406: Servlet.service() for servlet default threw exception
org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Transaction marked for rollback.
    at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:845)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:662)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:632)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:314)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
    at com.citius.reservas.service.service$$EnhancerByCGLIB$$37b50d4.tryJPAFind(<generated>)
    at com.citius.reservas.AuthenticationSuccessHandlerImpl.onAuthenticationSuccess(AuthenticationSuccessHandlerImpl.java:47)
    ...
Caused by: javax.transaction.RollbackException: Transaction marked for rollback.
    at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:428)
    at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:855)
    at com.sun.enterprise.transaction.UserTransactionImpl.commit(UserTransactionImpl.java:208)
    at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:842)
    ... 45 more

次のエンティティがあります。

@Entity
@Table(name = "roles", catalog = "reservas")
@XmlRootElement
public class Role implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @NotNull
    @Size(min = 1, max = 50)
    private String name;

    private static final long serialVersionUID = 1L;

GenericRepository は、すべてのリポジトリによって実装される一般的なクラスです。

public class GenericRepositoryImpl<T> implements GenericRepository<T> {

    @PersistenceContext
    private EntityManager em;

    private Class<T> type;

    public GenericRepositoryImpl( ){
        Type t = getClass().getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType) t;
        type = (Class) pt.getActualTypeArguments()[0];
    }

    @Override
    public T find(Object pk) {
        try{
            return em.find(type, pk);
        }catch(java.util.NoSuchElementException ex){
            return null;
        }
    }

    @Override
    public T create(T t) {
        em.persist(t);
        em.flush();
        em.refresh(t);
        return t;
    }

    @Override
    public List<T> query(Query q) {
        List<T> list= q.getResultList();
        if(list==null)
            list=new ArrayList<T>();        
        return list;
    }
}

これはロール リポジトリです。

@Repository
public class RoleRepositoryImpl extends GenericRepositoryImpl<Role> 
    implements RoleRepository{

    @PersistenceContext
    private EntityManager em;

    @Override
    public Role findByName(String name) {
        Query q = (Query) this.em.createNamedQuery("Role.findByName");
        q.setParameter("name", name);
        Role r = (Role) q.getSingleResult();
        return r;
    }

    @Override
    public List<Role> findAll() {
        Query q = (Query) this.em.createNamedQuery("Role.findAll");
        return this.query(q);
    }
}

サービス クラス:

@Service
public class service {

    @Autowired
    private RoleRepository roleRepository;

    @Transactional
    //This throws a RollBackException
    public void tryJPAEmpty(){

        roleRepository.findByName("example");
    }

    //This doesn't
    public Role tryJPAFind(){
        return roleRepository.find(new Integer(1));
    }
}

Spring 構成 (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:context="http://www.springframework.org/schema/context"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:tx="http://www.springframework.org/schema/tx" 
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
          http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
          http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
">
    <context:component-scan base-package="com.***.***" />

    <jpa:repositories base-package="com.***.***.repositories" />

    <tx:annotation-driven />
    <tx:annotation-driven transaction-manager="transactionManager" />
    <context:annotation-config />

    <beans>
        <bean id="EntityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
            <property name="persistenceUnitName" value="JPAReservas"/>
        </bean>

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

        <bean id="transactionManager" 
            class="org.springframework.transaction.jta.JtaTransactionManager" >
            <property name="allowCustomIsolationLevels">
                <value>true</value>
            </property>
        </bean>
    </beans>
</beans>

Persistence.xml (GlassFish サーバーに作成されたデータ ソースと接続プールがあります):

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence  
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">

  <persistence-unit name="JPAReservas" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>Reservas_mysql</jta-data-source>

    <!--Named queries-->
    <mapping-file>META-INF/mapping/Role.xml</mapping-file>

    <exclude-unlisted-classes>false</exclude-unlisted-classes>
  </persistence-unit>
</persistence>

最後に、次のように xml ファイルでクエリに名前を付けました。 SELECT r FROM Role r

    <named-query name="Role.findByName">
        <query>SELECT r FROM Role r WHERE r.name = :name</query>
    </named-query>

私は本当にSpringとJPAに慣れていないので、改善点やできる変更を知っているなら教えてください。

4

1 に答える 1

0

OK、トランザクションタイプを RESOURCE_LOCAL に変更して解決しましたが、最初は Glassfish で多くの問題が発生します。それが私がそれを解決した方法です:

web.xml のヘッダーに metadata-complete="true" を追加しました。これが必要な理由は次のとおりです

<web-app 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_3_0.xsd"
         version="3.0" metadata-complete="true">

RESOURCE_LOCAL ではアプリケーションが Glassfish の接続プールを使用しないため、persistence.xml を変更しました。データベース接続に関する情報を入力する必要があります。

<persistence-unit name="JPAReservas" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <mapping-file>META-INF/mapping/User.xml</mapping-file>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/reservas"/>
      <property name="javax.persistence.jdbc.user" value="admin"/>
      <property name="javax.persistence.jdbc.password" value="adminpassword"/>
    </properties>
  </persistence-unit>

最後に、JTA と同じ EntityManager クラスを RESOURCE_LOCAL で使用できないため、applicationContext.xml (Spring 構成) を変更しました。

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
       <property name="entityManagerFactory" ref="EntityManagerFactory" />
</bean>

それだけです。なぜ以前のように JTA を使用できないのかわかりませんが、解決しました!!! :)。ありがとうございました!

于 2013-05-15T11:48:42.710 に答える