2011-12-28 41 views
2

我正在嘗試JPA/Hibernate和Spring。我有一個控制器 - >服務 - > DAO結構,我有一些問題JPA。我認爲它的交易相關,但找不到問題。從DAO回來時的Spring/JPA分離的實體

我有@Service和@Transactional註解的服務。我有一個「removeAll()」方法,我首先調用「findAll」,然後迭代列表以在實體上調用「remove()」。當我調用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())所做的抽象。我認爲不是在CourseTemplateDAOImpl類中注入entitymanager,而是在JPADAOImpl中配置實體管理器,因爲它對所有DAO實現都是通用的。

我已經修改了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類

@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); 
} 

,你也可以與傳播起到見參考文獻在Spring Documentation特地需要嵌套功能。

0

CourseTemplate是怎麼樣的?也許你有懶惰的關係,並在同一時間在這種關係CascadeType.ALL?也許你應該在你的findAll中獲取元素,以免它們分離?

0

你說的正確,我們比DAO層更喜歡服務層@Transactional方法。 我會建議更改事務隔離級別和Transaction propagation

更改爲嵌套應該工作。

更好的是,在方法上放置@Transactional註解。在你的情況下

@Transactional public Integer removeAllTemplates(){ 
... 
} 
相關問題