2010-12-08 66 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; 
} 

} 

這裏是Spring上下文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使用基於代理技術的AOP,因此各方面(包括交易性方面)被稱爲方法時,不應用來自同一班。

一般來說

  • @Transactional註釋應經常放在服務的方法,而不是DAO方法
  • saveTeacher()看起來像一個服務的方法,這將是更好地將其放置在單獨的服務類註釋爲@Transactional
  • 你不saveTeacher()需要persist() - 持久對象的更改將自動存儲
  • 動態代理VS目標類代理的區別當心(關於向TestDao) - 見下文

也看到了鏈接: