从DAO回来时的Spring/JPA分离的实体
我正在尝试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>
所有配置看起来是正确的。但是我不确定你在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 {
}
尝试将事务标记移动到方法定义,像(下面的代码是一个工作的代码已经在生产中):
@Transactional
public void delete(User entity){
userDAO.delete(entity);
}
@Transactional(readOnly=true)
public User findUserByUsername(String username){
return getUserDAO().findOne(username);
}
,你也可以与传播起到见参考文献在Spring Documentation特地需要和嵌套功能。
CourseTemplate
是怎么样的?也许你有懒惰的关系,并在同一时间在这种关系CascadeType.ALL
?也许你应该在你的findAll
中获取元素,以免它们分离?
你说的正确,我们比DAO层更喜欢服务层@Transactional方法。 我会建议更改事务隔离级别和Transaction propagation
更改为嵌套应该工作。
更好的是,在方法上放置@Transactional注解。在你的情况下
@Transactional public Integer removeAllTemplates(){
...
}