Сохранение объекта в репозитории не работает SPRING

Я пытаюсь сохранить объект в репозитории, но он не работает вообще. Репозиторий Autowired и во время выполнения я использую 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
@Transactional
public interface MyRepository extends JpaRepository<MyData, Long> {}

файл 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 файл

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

    ...
}

1 ответов


для стартера вы фактически работаете над 2 различными EntityManager в своем нерабочем тестовом примере: один из них-EntityManager, автоматически подключенный к вашему тесту весной (это одноэлементный и его следует избегать в любом случае), а другой-EntityManager, созданный EntityManagerFactory, настроенным в вашей ApplicationConfiguration. В то же время у вас также есть еще один сеанс, работающий вдоль вышеупомянутых 2 EntityManagers из-за вашей конфигурации Hibernate SessionFactory. Кроме того, из-за настроенного HibernateTransactionManager все транзакции, созданные @Transactional, привязаны к сеансу Hibernate, созданному SessionFactory, и EntityManager, используемый вашим репозиторием, конечно, не может знать об этом. Вот почему TransactionRequiredException было вызвано, когда ваш репозиторий попытался сохранить данные.

чтобы исправить это, вы можете рассмотреть вопрос об удалении sessionFactory Hibernate и переключить диспетчер транзакций на JpaTransactionManager. Затем @Transactional в вашем репозитории будет иметь эффект создания новой транзакции и привязки ее к существующему EntityManager, который известен как Spring.

одна сторона Примечания заключается в том, что @Transactional на вашем TestClass не помогает вообще, поскольку экземпляр этого класса не создается и не управляется Spring. Чтобы сделать эту работу, необходимо предоставить правильную конфигурацию транзакционного тестового класса, как описано здесь: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html.

надеюсь, что это помогает.