2015-05-08 14 views
7

Sto provando a salvare l'entità nel repository ma non funziona affatto. Repository è Autowired e in runtime utilizzo saveAndFlush per salvare entità. Sto usando PostgreSQL. Sopra i metodi di prova ho aggiunto commenti e spiegazioni su cosa sta succedendo. Mi aspettavo che il metodo saveAndFlush funzionasse, ma non è così. Non riesco a trovare il perché.L'entità di salvataggio nel repository non funziona 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)); 
    } 
} 

file di interfaccia repository

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

file di MyData

@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; 
    } 
} 

file di ApplicationConfiguration

@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

Si sta utilizzando il gestore transazioni errato. Per JPA è necessario un 'JpaTransactionManager' non il' HibernateTransactionManager'. Anche perché mescolare il 2. –

+0

Invece di creare 2 istanze, basta creare un 'LocalContainerEntityManagerFactory' e usare' HibernateJpaSessionFactoryBean' per esporre un 'SessionFactory'. Ora hai solo bisogno di un singolo transactionamanger e puoi usare sia JPA sia un semplice 'SessionFactory' di Hibernate se hai davvero bisogno di questo. –

+0

Non aiuta, perché devo ancora iniziare Transaction e commit invece di usare saveAndFlush sul repository. Pensi che potrebbe essere in letargo + caso specifico postgresql? Può essere fatto senza chiamare begin e commit? –

risposta

8

Per antipasto, si sta effettivamente lavorando su 2 EntityManager diverso nella vostra Test case non funzionante: Uno è EntityManager avviato automaticamente nel test da Spring (questo è singleton e deve essere comunque evitato) e uno è EntityManager creato da EntityManagerFactory configurato in ApplicationConfiguration. Allo stesso tempo, hai anche un'altra Sessione che funziona insieme ai 2 EntityManagers summenzionati a causa della tua configurazione di Hibernate SessionFactory. Inoltre, a causa del HibernateTransactionManager configurato, tutte le transazioni create da @Transactional sono associate alla Sessione di Hibernate creata da SessionFactory e l'EntityManager utilizzato dal Repository non ha certamente alcun modo per saperlo. Questo è il motivo per cui TransactionRequiredException è stato generato quando il repository ha cercato di mantenere i dati.

Per risolvere il problema, si può prendere in considerazione la rimozione di SessionFactory di Hibernate e passare il gestore delle transazioni a un JpaTransactionManager. Quindi, @Transactional sul repository avrà l'effetto di creare una nuova transazione e collegarla all'EntityManager esistente che è noto a Spring.

Una nota a margine è che @Transactional sul tuo TestClass non aiuta affatto poiché l'istanza di questa classe non viene istanziata e gestita da Spring. Per fare questo, è necessario fornire una configurazione corretta della classe di test transazionale come descritto qui: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html.

Spero che questo aiuti.

+0

Ho eliminato tutte le cose inutili dalla configurazione dell'applicazione e sta funzionando ora! Grazie per la risposta –