将存储库中的实体不起作用SPRING [英] Saving entity in repository does not work SPRING

查看:196
本文介绍了将存储库中的实体不起作用SPRING的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将实体保存在存储库中,但它根本不起作用。存储库是Autowired,在运行时我使用saveAndFlush来保存实体。我正在使用PostgreSQL。以上测试方法我添加了评论和解释发生了什么。我期望saveAndFlush方法可以工作,但它没有。我找不到原因。

  @Transactional 
公共类TestClass {

@Autowired私有MyRepository存储库;
@Autowired私有EntityManager entityManager;

//工作版本
public void writingToRepositoryWorking(){
entityManager.getTransaction()。begin();
entityManager.persist(new MyData(99));
entityManager.getTransaction()。commit();



//不工作并抛出异常
// TransactionRequiredException:没有事务在进行中
public void writingToRepositoryNotWorking(){
repository.saveAndFlush(new MyData(99));
}

//不工作,没有例外,库中没有数据,
//但自动生成的ID增加
public void writingToRepositoryNotWorkingToo(){
repository.save(new MyData(99));


存储库接口文件

  @Repository 
@Transactional
公共接口MyRepository扩展了JpaRepository< MyData,Long> {}

MyData文件

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

private int testValue;
$ b $ public MyData(){}

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

public long getId(){
return id;
}

public int getTestValue(){
return testValue;


$ / code $ / pre
$ b $ p ApplicationConfiguration文件

  @Configuration 
@EnableJpaRepositories(com.mypackage.app)
@EnableTransactionManagement
@PropertySource(classpath:application。属性)
@EnableWebMvc
类ApplicationConfiguration扩展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();

$ b $Bean
Autowired $ b $ public LocalSessionFactoryBean sessionFactory(DataSource dataSource){
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setPackagesToScan(com.mypackage.app);
factory.setHibernateProperties(hibernateProperties());
退货工厂;


公共属性hibernateProperties(){
属性properties = new Properties();
properties.setProperty(hibernate.dialect,org.hibernate.dialect.PostgreSQLDialect);
properties.setProperty(hibernate.show_sql,true);
properties.setProperty(hibernate.hbm2ddl.auto,update);
返回属性;


$Be
@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);
返回dataSource;

$ b $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();

返回em.getObject();
}

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

...
}




一方面要注意的是由于Spring类没有实例化和管理这个类的实例,所以你的TestClass上的@Transactional根本没有任何帮助。要做到这一点,需要按照以下描述提供事务测试类的适当配置: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html



希望这有助于。


I'm trying to save entity in repository but it does not work at all. Repository is Autowired and in runtime I use saveAndFlush to save entity. I'm using PostgreSQL. Above test methods I added comments with explanation what is going on. I expected that method saveAndFlush should work but it did not. I can not find why.

@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 interface file

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

MyData file

@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 file

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

    ...
}

解决方案

For starter, you're actually working on 2 different EntityManager in your non-working test case: One is the EntityManager autowired into your test by Spring (this one is singleton and should be avoided anyway) and one is the EntityManager created by the EntityManagerFactory configured in your ApplicationConfiguration. At the same time, you also have another Session running along side the aforementioned 2 EntityManagers due to your configuration of Hibernate SessionFactory. Additionally, because of the configured HibernateTransactionManager, all transactions created by @Transactional are bound to the Hibernate's Session created by SessionFactory and the EntityManager used by your Repository certainly has no way to know about it. This is why TransactionRequiredException was thrown when your Repository tried to persist data.

To fix it, you may consider removing the Hibernate's SessionFactory and switch the transaction manager to a JpaTransactionManager. Then, @Transactional on your Repository will have the effect of creating a new transaction and binding it to the existing EntityManager that is known to Spring.

One side note is that the @Transactional on your TestClass doesn't help at all as the instance of this class is not instantiated and managed by Spring. To make this work, a proper configuration of transactional test class needs to be provided as described here: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html.

Hope this helps.

这篇关于将存储库中的实体不起作用SPRING的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆