2010-12-08 4 views
2

findAll이 으로 작동하지만 JPA에서 엔티티를 유지할 수 없습니다. 여기 여기 TestDao 클래스 다음은 스프링 3에서 JPA 엔티티를 유지할 수 없습니다.


package aop.web.teacher.dao; 

import java.util.Date; 
import java.util.List; 

import javax.annotation.PostConstruct; 
import javax.persistence.EntityManager; 
import javax.persistence.EntityManagerFactory; 
import javax.persistence.PersistenceContext; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Repository; 
import org.springframework.stereotype.Service; 



import aop.web.teacher.rmodels.Teachermaster; 

@Service 
@Repository 
public class TestDaoImpl extends JpaDAO implements TestDao { 

@Autowired 
EntityManagerFactory entityManagerFactory; 

@PersistenceContext 
private EntityManager em; 

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

public int saveTeacher() { 
    List teacherList = findAll(); 
    Teachermaster m1 = teacherList.get(0); 
    logger.info("Found " + m1.getId() + " and " + m1.getRace()); 
    m1.setRace(m1.getRace() + "::" + System.currentTimeMillis()); 
    logger.info("New " + m1.getId() + " and " + m1.getRace()); 
    persist(m1); 
    return 0; 
} 

} 

봄 컨텍스트 XML 여기

http://pastebin.com/pKqzW9h1

우리가 변화를 만들 때 findall은이 을 작동하지만이되어있는 JpaDAO

 

package aop.web.teacher.dao; 

import java.lang.reflect.ParameterizedType; 
import java.util.List; 

import javax.persistence.EntityManager; 
import javax.persistence.PersistenceException; 
import javax.persistence.Query; 

import org.apache.log4j.Logger; 
import org.springframework.orm.jpa.JpaCallback; 
import org.springframework.orm.jpa.support.JpaDaoSupport; 
import org.springframework.stereotype.Repository; 
import org.springframework.stereotype.Service; 
import org.springframework.transaction.annotation.Propagation; 
import org.springframework.transaction.annotation.Transactional; 


public abstract class JpaDAO extends JpaDaoSupport { 
protected Class entityClass; 

private static Logger log = Logger.getLogger(JpaDAO.class); 

@SuppressWarnings("unchecked") 
public JpaDAO() { 
    ParameterizedType genericSuperclass = (ParameterizedType) getClass() 
    .getGenericSuperclass(); 
    this.entityClass = (Class) genericSuperclass 
    .getActualTypeArguments()[1]; 
} 

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) 
public void persist(E entity) { 
    getJpaTemplate().persist(entity); 
} 

@Transactional 
public void remove(E entity) { 
    getJpaTemplate().remove(entity); 
} 

@Transactional 
public E merge(E entity) { 
    return getJpaTemplate().merge(entity); 
} 

@Transactional 
public void refresh(E entity) { 
    getJpaTemplate().refresh(entity); 
} 

@Transactional 
public E findById(K id) { 
    return getJpaTemplate().find(entityClass, id); 
} 

@Transactional 
public E flush(E entity) { 
    getJpaTemplate().flush(); 
    return entity; 
} 

@SuppressWarnings("unchecked") 
@Transactional 
public List findAll() { 
    Object res = getJpaTemplate().execute(new JpaCallback() { 

    public Object doInJpa(EntityManager em) throws PersistenceException { 
    Query q = em.createQuery("SELECT h FROM " 
     + entityClass.getName() + " h"); 
    return q.getResultList(); 
    } 

    }); 

    return (List) res; 
} 

@SuppressWarnings("unchecked") 
@Transactional 
public Integer removeAll() { 
    return (Integer) getJpaTemplate().execute(new JpaCallback() { 

    public Object doInJpa(EntityManager em) throws PersistenceException { 
    Query q = em.createQuery("DELETE FROM " + entityClass.getName() 
     + " h"); 
    return q.executeUpdate(); 
    } 

    }); 
} 

} 
 

입니다 Teachermaster의 속성에 다음 지속되거나 병합되지 않습니다. 우리가 그것을 플러시 경우 m은

javax.persistence.TransactionRequiredException: no transaction is in progress 

알려 주시기 바랍니다

답변

2

당신은 호출 테스트 클래스에서 persist()을 호출 할 때 로컬 메소드. 이 방법을 사용하면 트랜잭션을 생성하는 프록시가 호출되지 않으므로 persist()에 대한 호출에는 트랜잭션이 없습니다.

올바르게 수행하는 방법은 테스트 클래스 이 아닌이 테스트 대상 객체를 확장하지만 주입해야합니다. 이렇게하면 프록시가 트리거되고 트랜잭션이 생성됩니다.

그건 그렇고, 나는 당신의 클래스 디자인이 조금 복잡하다는 사실을 덧붙여 야합니다. 다음과 같은 구조를 만들 것을 제안 할 수 있습니까?

DAO 인터페이스 :

public interface FooDao { 
    void persist(Foo foo); 
    // ... 
} 

DAO 구현 :

public class FooDaoImpl implements FooDao { 
    @PersistenceContext 
    private EntityManager entityManager; 

    @Transactional 
    public void persist(Foo foo) { 
     entityManager.persist(foo); 
    } 
} 

테스트 클래스 : 원하는 경우

@RunWith(SpringJunit4ClassRunner.class) 
@ContextConfiguration(...) 
public class FooDaoTest { 
    @Autowired 
    private FooDao fooDao; 

    @Test 
    public void testPersist() { 
     // do some testing 
    } 
} 

당신은,는 DAO 구현에 논리의 대부분을 추출 할 수 있습니다 일반 수퍼 클래스로 변환합니다.

5

봄이 메소드가 호출 될 때 적용되지 않습니다 프록시 기반의 AOP (트랜잭션 측면 포함) 때문에 측면을 사용하여 우리가 예외 얻을 ... 을 엔티티를 저장합니다 같은 학급에서 왔어.

일반적으로

  • @Transactional 주석 일반적으로 서비스 방법보다는 DAO 방법에 배치해야
  • 귀하의 saveTeacher() 서비스 방법처럼 보인다는 별도의 서비스 클래스에 배치하는 것이 좋습니다 것 및 당신은 saveTeacher()persist() 필요하지 않습니다
  • @Transactional로 주석 - 영구 객체에 대한 변경을
  • 자동으로 저장한다 (TestDao에 대한) 대상 클래스의 프록시 구분 대 동적 프록시주의 - 또한

참조 아래의 링크를 참조하십시오

관련 문제