не в состоянии сохранить сущность в JPA весной 3 - PullRequest
2 голосов
/ 08 декабря 2010

Я не могу сохранить сущность в JPA, хотя 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();
   }

  });
 }

}

Вот класс TestDao


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 работает, но когда мы вносим изменение в атрибут учителя, то сохранение или объединение, похоже, не спасают сущность ... Если мы очищаем ее, мы получаем исключение

javax.persistence.TransactionRequiredException: no transaction is in progress

Пожалуйста, сообщите

Ответы [ 2 ]

5 голосов
/ 08 декабря 2010

Spring использует основанную на прокси AOP, поэтому аспекты (включая транзакционный аспект) не применяются, когда методы вызываются из одного класса.

В общем случае

  • @Transactional аннотацииобычно следует размещать в методах обслуживания, а не в методах DAO
  • Ваш saveTeacher() выглядит как метод обслуживания, было бы лучше поместить его в отдельный класс обслуживания и аннотировать как @Transactional
  • Вам не нужно persist() в saveTeacher() - изменения, внесенные в постоянные объекты, должны сохраняться автоматически
  • Остерегайтесь динамического прокси и различия между прокси целевого класса (относительно TestDao) - см. Ссылкиниже

См. также:

2 голосов
/ 08 декабря 2010

Вы вызываете локальный метод при вызове 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 в общий суперкласс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...