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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30122829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 09:11:00  来源:igfitidea点击:

Saving entity in repository does not work SPRING

javaspringhibernaterepositoryspring-data

提问by Marcin Lagowski

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.

我正在尝试将实体保存在存储库中,但它根本不起作用。存储库是自动装配的,在运行时我使用 saveAndFlush 来保存实体。我正在使用 PostgreSQL。在上面的测试方法中,我添加了注释并解释了正在发生的事情。我预计该方法 saveAndFlush 应该可以工作,但它没有。我找不到原因。

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

    ...
}

采纳答案by Phoenix VN

For starter, you're actually working on 2 different EntityManagerin your non-working test case:

首先,您实际上EntityManager在非工作测试用例中处理2 个不同的测试用例:

  1. EntityManagerautowired into your test by Spring (this one is singleton and should be avoided anyway) ,other is
  2. EntityManagercreated by the EntityManagerFactoryconfigured in your ApplicationConfiguration.
  1. EntityManager由 Spring 自动连接到您的测试中(这个是单例的,无论如何都应该避免),另一个是
  2. EntityManagerEntityManagerFactory您的 ApplicationConfiguration 中的配置创建。

At the same time, you also have another Session running along side the aforementioned 2 EntityManagersdue to your configuration of Hibernate SessionFactory. Additionally, because of the configured HibernateTransactionManager, all transactions created by @Transactionalare bound to the Hibernate's Session created by SessionFactoryand the EntityManagerused by your Repository certainly has no way to know about it. This is why TransactionRequiredExceptionwas thrown when your Repository tried to persist data.

同时,EntityManagers由于您的 Hibernate 配置,您还有另一个 Session 与上述 2 一起运行SessionFactory。此外,由于配置了HibernateTransactionManager,所有创建的事务@Transactional都绑定到创建的 Hibernate 会话,SessionFactory并且EntityManager您的 Repository 使用的当然无法知道它。这就是为什么TransactionRequiredException在您的存储库尝试保留数据时抛出的原因。

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

要修复它,您可以考虑删除 HibernateSessionFactory并将事务管理器切换到JpaTransactionManager. 然后,@Transactional在您的 Repository 上将创建一个新事务并将其绑定EntityManager到 Spring 已知的现有事务。

One side note is that the @Transactionalon 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.

一方面要注意的是,@Transactional您的 TestClass 上的 根本没有帮助,因为此类的实例不是由 Spring 实例化和管理的。为了完成这项工作,需要提供事务测试类的正确配置,如下所述:http: //docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html

Hope this helps.

希望这可以帮助。