2010-12-08 14 views
2

JPAでエンティティを永続化できませんが、findAllは で動作します。ここ はここTestDaoクラスは、Spring 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); 
    } 
} 

Testクラス:

@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に係る)対象クラスのプロキシ区別対動的プロキシの用心 - も参照してください

、以下のリンクを参照してください。

関連する問題