2011-12-28 17 views
2

JPA/HibernateとSpringを試しています。私はコントローラ - >サービス - > DAOの構造体を持っており、私はいくつかの問題JPAを持っています。私はその取引は関係していると思うが、問題を見つけることはできない。Spring/JPA DAOから戻ってきたときの分離エンティティ

私は@Serviceと@Transactionalで注釈が付けられたサービスを持っています。私は、最初に "findAll"を呼び出してから、リスト上を反復して "remove()"というエンティティを呼び出す、 "removeAll()"メソッドを持っています。 removeメソッドを呼び出すと、「不正な引数の例外:デタッチされたインスタンスを削除する」というメッセージが表示されます。

私は赤で、サービスクラスに@Transactional注釈を入れるだけで、DAOは何とかトランザクションに参加する必要があります。 @TransactionのすべてをDAOクラスに置くと、すべて正常に動作します。しかし、私が覚えているように、私はサービスクラスのアノテーションだけが必要です。多分設定に問題がありますが、それは見つけられません。

誰かが見てもらえたら、すぐに見えるかもしれません。

ここに私のサービスクラスのコードスニペット:

@Service("courseService") 
@Transactional 
public class CourseServiceImpl implements CourseService { 
    @Autowired 
    @Qualifier("courseTemplateDAO") 
    private CourseTemplateDAO courseTemplateDAO; 

    public Integer removeAllTemplates() { 
     int removed = 0; 

     List<CourseTemplate> courseTemplates = getCourseTemplateDAO().findAll(); 
     for (CourseTemplate currCourseTemplate : courseTemplates) { 
      getCourseTemplateDAO().remove(currCourseTemplate); 
      removed++; 
     } 

     return removed; 
    } 

    public CourseTemplateDAO getCourseTemplateDAO() { 
     return courseTemplateDAO; 
    } 

    public void setCourseTemplateDAO(CourseTemplateDAO courseTemplateDAO) { 
     this.courseTemplateDAO = courseTemplateDAO; 
    } 
} 

ジェネリックDAOクラス、かなり標準:

public abstract class JPADAOImpl<T> extends JpaDaoSupport implements JPADAO<T> { 
    private Class<T> entityClass; 

    public JPADAOImpl() { 
     ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass(); 
     this.entityClass = (Class<T>) genericSuperclass.getActualTypeArguments()[0]; 
    } 

    public void persist(T entity) { 
     getJpaTemplate().persist(entity); 
    } 

    public void remove(T entity) { 
     getJpaTemplate().remove(entity); 
    } 

    public T merge(T entity) { 
     return getJpaTemplate().merge(entity); 
    } 

    public void refresh(T entity) { 
     getJpaTemplate().refresh(entity); 
    } 

    public T flush(T entity) { 
     getJpaTemplate().flush(); 
     return entity; 
    } 

    public T findById(long id) { 
     return getJpaTemplate().find(entityClass, id); 
    } 

    public List<T> findAll() { 
     List<T> res = getJpaTemplate().execute(new JpaCallback<List<T>>() { 
      public List<T> doInJpa(EntityManager em) throws PersistenceException { 
       Query q = em.createQuery("SELECT h FROM " + entityClass.getName() + " h"); 
       return q.getResultList(); 
      } 
     }); 

     return (List<T>) res; 
    } 

    public Integer removeAll() { 
     return getJpaTemplate().execute(new JpaCallback<Integer>() { 
      public Integer doInJpa(EntityManager em) throws PersistenceException { 
       Query q = em.createQuery("DELETE FROM " + entityClass.getName() + " h"); 
       return q.executeUpdate(); 
      } 
     }); 
    } 

    public Class<T> getEntityClass() { 
     return entityClass; 
    } 
} 

そして、私のCourseTemplateDAO実装クラス:

@Repository("courseTemplateDAO") 
public class CourseTemplateDAOImpl extends JPADAOImpl<CourseTemplate> implements CourseTemplateDAO { 

    @Autowired 
    private EntityManagerFactory entityManagerFactory; 

    public CourseTemplateDAOImpl() { 

    } 

    @PostConstruct 
    public void init() { 
     super.setEntityManagerFactory(entityManagerFactory); 
    } 
} 

私の春アプリケーションコンテキスト構成ファイル:

<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" 
xmlns:task="http://www.springframework.org/schema/task" 
xsi:schemaLocation=" 
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-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/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
     http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> 

<context:annotation-config /> 
<context:component-scan base-package="org.ksshi"/> 

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

<bean class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" id="entityManagerFactory"> 
    <property name="persistenceUnitName" value="KSSHIPersistenceUnit"/> 
</bean> 

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

<bean id="messageSource" class="org.ksshi.service.i18n.impl.I18NMessageSource"/> 

そして最後に、私の永続化設定ファイル:

<persistence 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_2_0.xsd" 
     version="2.0"> 

<persistence-unit name="KSSHIPersistenceUnit" transaction-type="RESOURCE_LOCAL"> 
    <description> 
     Persistence unit for the KSSHI application 
    </description> 

    <provider>org.hibernate.ejb.HibernatePersistence</provider> 

    <class>org.ksshi.entity.CourseTemplate</class> 
    <class>other classes</class> 

    <properties> 
     <property name="hibernate.hbm2ddl.auto" value="update"/> 
     <property name="hibernate.show_sql" value="true"/> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/> 
     <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> 
     <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/ksshi"/> 
     <property name="hibernate.connection.username" value="sa"/> 
     <property name="hibernate.connection.password" value=""/> 

     <property name="hibernate.c3p0.min_size" value="5"/> 
     <property name="hibernate.c3p0.max_size" value="20"/> 
     <property name="hibernate.c3p0.timeout" value="300"/> 
     <property name="hibernate.c3p0.max_statements" value="50"/> 
     <property name="hibernate.c3p0.idle_test_period" value="3000"/> 
    </properties> 
</persistence-unit> 

答えて

0

すべての構成が正しく見えます。しかし、私はあなたがのJpaDaoSupportで作成した抽象概念と、JPAテンプレート(getJpaTemplate())を使用した場所についてはわかりません。私は、あなたがすべてのDAOの実装に一般的なので、JPADAOImplで設定されたそれを持つことができるCourseTemplateDAOImplクラスのentitymanagerを注入する代わりに思う。

私はJPADAOImplクラスを変更しても、主キーのための汎用的な引数を追加した

public abstract class JPADAOImpl<T, PK extends Serializable> implements JPADAO<T, PK> { 
    private Class<T> entityClass; 

    @PersistenceContext(type=PersistenceContextType.TRANSACTION) 
    protected EntityManager entityManager; 

    @SuppressWarnings("unchecked") 
    public JPADAOImpl() { 
     ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass(); 
     this.entityClass = (Class<T>) genericSuperclass.getActualTypeArguments()[0]; 
    } 

    public void persist(T entity) { 
     entityManager.persist(entity); 
    } 

    public void remove(T entity) { 
     entityManager.remove(entity); 
    } 

    public T merge(T entity) { 
     return entityManager.merge(entity); 
    } 

    public void refresh(T entity) { 
     entityManager.refresh(entity); 
    } 

    public T flush(T entity) { 
     entityManager.flush(); 
     return entity; 
    } 

    public T findById(PK id) { 
     return entityManager.find(getEntityClass(), id); 
    } 

    @SuppressWarnings("unchecked") 
    public List<T> findAll() { 
     String all = "select h from " + getEntityClass().getSimpleName() + " h"; 
     Query query = entityManager.createQuery(all); 
     return (List <T>)query.getResultList(); 
    } 

    public Integer removeAll() { 
     Query q = entityManager.createQuery("DELETE FROM " + getEntityClass().getName() + " h"); 
     return q.executeUpdate(); 
    } 

    public Class<T> getEntityClass() { 
     return entityClass; 
    } 
} 

JPADAOインタフェース

public interface JPADAO<T, PK extends Serializable> { 

    void persist (T entity); 

    void remove(T entity); 

    T merge(T entity); 

    void refresh(T entity); 

    T flush(T entity); 

    T findById(PK id); 

    List<T> findAll(); 

    T update(T entity); 
} 

CourseTemplateDAOImplクラス

(あなたはそれが常にlong型であると仮定しています)
@Repository("courseTemplateDAO") 
public class CourseTemplateDAOImpl extends JPADAOImpl<CourseTemplate, long> implements CourseTemplateDAO { 


} 
2

トランザクションの表記法をメソッド定義に移動してみてください。 (以下のコードは、生産ですでに作業コードである)のように:

@Transactional 
public void delete(User entity){ 
    userDAO.delete(entity); 
} 

@Transactional(readOnly=true) 
public User findUserByUsername(String username){ 
    return getUserDAO().findOne(username); 
} 

また、あなたがPROPAGATIONと遊ぶことができるがSpring Documentation特別必要ネストされた機能でリファレンスを参照してください。

0

CourseTemplateはどのように見えますか?たぶんあなたは怠惰な関係を持っていて、同時にその関係にCascadeType.ALLがありますか?おそらく、あなたはfindAllの要素を取得してデタッチされないようにするべきでしょうか?

0

あなたは、DAOレイヤーよりもサービス層@トランザクション型メソッドが好きだと言うのは間違いありません。 トランザクション分離レベルを変更することをお勧めします。Transaction propagation

さらに、@Transactionalアノテーションをメソッドに配置してください。あなたの場合

@Transactional public Integer removeAllTemplates(){ 
... 
} 
関連する問題