2010-12-08 5 views
2

Я не могу сохранить объект в JPA, хотя findAll работает здесь. Вот JpaDAOНевозможно сохранить объект в JPA весной 3

 

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

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

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

Вообще говоря

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

Смотрите также: