2015-05-08 10 views
7

Ich versuche Einheit in Repository zu speichern, aber es funktioniert nicht bei allen. Repository ist Autowired und in Laufzeit verwende ich saveAndFlush, um die Entity zu speichern. Ich benutze PostgreSQL. Über den Testmethoden habe ich Kommentare mit Erklärungen hinzugefügt, was vor sich geht. Ich habe erwartet, dass die Methode saveAndFlush funktionieren sollte, aber nicht. Ich kann den Grund nicht finden.Saving Einheit in Repository funktioniert nicht SPRING

@Transactional 
public class TestClass{ 

    @Autowired private MyRepository repository; 
    @Autowired private EntityManager entityManager; 

    // Working version 
    public void writingToRepositoryWorking() { 
     entityManager.getTransaction().begin(); 
     entityManager.persist(new MyData(99)); 
     entityManager.getTransaction().commit(); 

    } 

    // not working and throws exception : 
    // TransactionRequiredException: no transaction is in progress 
    public void writingToRepositoryNotWorking() { 
     repository.saveAndFlush(new MyData(99)); 
    } 

    // not working, no exception, no data in repository, 
    // but auto generated ID is incremented 
    public void writingToRepositoryNotWorkingToo() { 
     repository.save(new MyData(99)); 
    } 
} 

Repository-Schnittstelle

Datei
@Repository 
@Transactional 
public interface MyRepository extends JpaRepository<MyData, Long> {} 

MyData Datei

@Entity(name = "myData") 
public class MyData { 
    @Id @GeneratedValue(strategy = GenerationType.AUTO) long id; 

    private int testValue; 

    public MyData() { } 

    public BugData(int testValue) { 
     this.testValue = testValue; 
    } 

    public long getId() { 
     return id; 
    } 

    public int getTestValue() { 
     return testValue; 
    } 
} 

ApplicationConfiguration Datei

@Configuration 
@EnableJpaRepositories("com.mypackage.app") 
@EnableTransactionManagement 
@PropertySource("classpath:application.properties") 
@EnableWebMvc 
class ApplicationConfiguration extends WebMvcConfigurationSupport { 

    @Value("${jdbc.url}") private String KEY_JDBC_URL; 

    @Value("${jdbc.username}") private String KEY_JDBC_USERNAME; 

    @Value("${jdbc.password}") private String KEY_JDBC_PASSWORD; 

    @Bean 
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { 
     return new PropertySourcesPlaceholderConfigurer(); 
    } 

    @Bean 
    @Autowired 
    public LocalSessionFactoryBean sessionFactory(DataSource dataSource) { 
     LocalSessionFactoryBean factory = new LocalSessionFactoryBean(); 
     factory.setDataSource(dataSource); 
     factory.setPackagesToScan("com.mypackage.app"); 
     factory.setHibernateProperties(hibernateProperties()); 
     return factory; 
    } 

    public Properties hibernateProperties() { 
     Properties properties = new Properties(); 
     properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"); 
     properties.setProperty("hibernate.show_sql", "true"); 
     properties.setProperty("hibernate.hbm2ddl.auto", "update"); 
     return properties; 
    } 

    @Bean 
    @Autowired 
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) { 
     return new HibernateTransactionManager(sessionFactory); 
    } 

    @Bean 
    public DataSource dataSource() { 
     BasicDataSource dataSource = new BasicDataSource(); 
     dataSource.setDriverClassName("org.postgresql.Driver"); 
     dataSource.setUrl(KEY_JDBC_URL); 
     dataSource.setUsername(KEY_JDBC_USERNAME); 
     dataSource.setPassword(KEY_JDBC_PASSWORD); 
     return dataSource; 
    } 

    @Bean 
    public EntityManagerFactory entityManagerFactory() { 
     LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); 

     em.setDataSource(dataSource()); 
     em.setPackagesToScan("com.mypackage.app"); 
     em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); 
     em.setJpaProperties(hibernateProperties()); 
     em.afterPropertiesSet(); 

     return em.getObject(); 
    } 

    @Bean 
    public EntityManager entityManager(EntityManagerFactory entityManagerFactory) { 
     return entityManagerFactory.createEntityManager(); 
    } 

    ... 
} 
+2

Sie verwenden den falschen Transaktionsmanager. Für JPA benötigen Sie einen 'JpaTransactionManager', nicht den' HibernateTransactionManager'. warum auch mischen die 2. –

+0

Stattdessen 2 Instanzen zu schaffen, nur einen 'LocalContainerEntityManagerFactory' erstellen und verwenden Sie die' 'HibernateJpaSessionFactoryBean' eine SessionFactory' zu belichten. Sie brauchen jetzt nur noch einen einzigen Transaktions-Fehler und können sowohl JPA als auch eine einfache Hibernate 'SessionFactory' verwenden, wenn Sie dies wirklich brauchen. –

+0

Es hilft nicht, weil ich noch Transaction und commit beginnen muss, anstatt saveAndFlush für das Repository zu verwenden. Glauben Sie, es könnte Winterschlaf + postgresql spezifischen Fall sein? Kann es ohne Aufruf und Begehen getan werden? –

Antwort

8

Für Starter sind Sie eigentlich auf 2 verschiedenen EntityManager arbeiten in Ihrem Nicht-Arbeitstestfall: Eine davon ist die EntityManager in Ihrem Test von Spring autowired (dieses Singleton ist und sollte auf jeden Fall vermieden werden) und man ist der EntityManager durch die in Ihrem ApplicationConfiguration konfiguriert EntityManagerFactory erstellt. Gleichzeitig haben Sie aufgrund der Konfiguration von Hibernate SessionFactory eine weitere Sitzung, die neben den oben genannten 2 EntityManagern ausgeführt wird. Darüber hinaus, da der konfigurierten HibernateTransactionManager, alle von @Transactional erstellt Transaktionen des von Session erstellt Session des Hibernate gebunden sind und der von Ihrem Repository verwendet EntityManager hat sicherlich keine Möglichkeit, darüber zu wissen. Aus diesem Grund wurde TransactionRequiredException ausgelöst, als Ihr Repository versuchte, Daten persistent zu machen.

es zu beheben, können Sie die Session des Hibernate Entfernen betrachten kann und die Transaktions-Manager auf einen JpaTransactionManager wechseln. Dann bewirkt @Transactional in Ihrem Repository, dass eine neue Transaktion erstellt und an den vorhandenen EntityManager gebunden wird, der Spring bekannt ist.

Eine Randnotiz ist, dass der @Transactional auf Ihrem Testclass überhaupt nicht helfen, wie die Instanz dieser Klasse nicht instanziiert und verwalten von Frühling. Damit dies funktioniert, muss eine korrekte Konfiguration der Transaktionstestklasse wie hier beschrieben bereitgestellt werden: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html.

Hoffe, das hilft.

+0

Ich habe alle unnötigen Dinge aus der Anwendungskonfiguration gelöscht und es funktioniert jetzt! Danke für die Antwort –

Verwandte Themen