简体   繁体   English

在存储库中保存实体不起作用SPRING

[英]Saving entity in repository does not work SPRING

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. 存储库是自动装配的,在运行时我使用saveAndFlush来保存实体。 I'm using PostgreSQL. 我正在使用PostgreSQL。 Above test methods I added comments with explanation what is going on. 在上面的测试方法中,我添加了评论并解释了发生了什么。 I expected that method saveAndFlush should work but it did not. 我期望saveAndFlush方法可以工作,但它没有。 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 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;
    }
}

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

    ...
}

For starter, you're actually working on 2 different EntityManager in your non-working test case: 对于初学者,您实际上在非工作测试用例中处理2个不同的EntityManager

  1. EntityManager autowired into your test by Spring (this one is singleton and should be avoided anyway) ,other is EntityManager自动连接到您的测试由Spring(这个人是独立的,并无论如何都应该避免),另一种是
  2. EntityManager created by the EntityManagerFactory configured in your ApplicationConfiguration. 由ApplicationConfiguration中配置的EntityManager创建的EntityManagerFactory

At the same time, you also have another Session running along side the aforementioned 2 EntityManagers due to your configuration of Hibernate SessionFactory . 同时,由于您配置了Hibernate SessionFactory ,您还可以在前面提到的2个EntityManagers旁边运行另一个Session。 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. 另外,由于配置了HibernateTransactionManager ,由@Transactional创建的所有事务都绑定到由SessionFactory创建的Hibernate会话,并且您的Repository使用的EntityManager当然无法知道它。 This is why TransactionRequiredException was thrown when your Repository tried to persist data. 这就是当您的存储库尝试保留数据时抛出TransactionRequiredException原因。

To fix it, you may consider removing the Hibernate's SessionFactory and switch the transaction manager to a JpaTransactionManager . 要修复它, 您可以考虑删除Hibernate的SessionFactory并将事务管理器切换到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. 然后,您的Repository上的@Transactional将具有创建新事务并将其绑定到Spring已知的现有EntityManager的效果。

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. 一方面注意,TestClass上的@Transactional根本没有帮助,因为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 . 为了使其工作,需要提供正确的事务测试类配置,如下所述: http//docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM