简体   繁体   English

JPA / Hibernate与Spring事务未提交

[英]JPA/Hibernate with Spring Transactions not commiting

I recently added the JpaTransactionManager to my Config and tried using Spring transactions. 我最近将JpaTransactionManager添加到了Config中,并尝试使用Spring事务。 It seems to work correctly, except for one test which I have added below. 除了我在下面添加的一项测试外,它似乎正常工作。

Why am I not getting my expected IllegalStateException ? 为什么我没有得到预期的IllegalStateException I expect this to fail, because CascadeType is set to NONE on the parentCategory field. 我希望这会失败,因为在parentCategory字段上CascadeType设置为NONE If I add em.flush(); 如果我添加em.flush(); inside my repository class, I do get the expected exception. 在我的存储库类中,我确实得到了预期的异常。

As I understand it, adding @Transaction in my tests only adds the begin, commit and rollback transaction methods. 据我了解,在测试中添加@Transaction仅会添加begin,commit和rollback事务方法。 So it should fail at the commit method, but it doesnt. 因此,它应该在commit方法上失败,但是不会失败。

According to the Hibernate User Guide the hibernate.transaction.flush_before_completion is false by default. 根据《 Hibernate用户指南》hibernate.transaction.flush_before_completion默认为false。 Is this the reason why I don't get my expected exception? 这就是为什么我没有得到预期的例外的原因吗?

There is a similair post where a user states that the commit will cause a flush. 有一个类似的帖子 ,用户指出提交将导致刷新。 This is also the reason why I decided to ask this question. 这也是我决定问这个问题的原因。


This is my entity 这是我的实体

@Entity
@Table(name = "category")
public class Category {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "category_id", nullable = false, insertable = false, updatable = false)
  private Long id;

  @Column(name = "category", nullable = false, unique = true)
  private String categoryName;

  @ManyToOne // Default is CascadeType.NONE
  @JoinColumn(name = "parent_category_id", referencedColumnName = "category_id")
  private Category parentCategory;

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parentCategory")
  private List<Category> childCategories = new ArrayList<>();

  public Category(String categoryName, Category parentCategory) {
    this.categoryName = categoryName;
    this.parentCategory = parentCategory;
  }

  // default constructor, getters and setters ...
}

This is my repository 这是我的资料库

@Repository
public class CategoryDaoImpl {

  @PersistenceContext protected EntityManager em;

  @Override
  public E persist(E entity) {
    em.persist(entity);
    // em.flush(); // Why doesnt Spring transactions automatically add the em.flush()  inside the transaction?
    return entity;
  }

}

This is my test 这是我的考验

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DbConfig.class)
@Transactional
public class CategoryDaoTest {

  @Autowired private CategoryDao categoryDao;

  @Test(expected = IllegalStateException.class)
  public void createTwoCategoriesPersistChildAndGetIllegalStateException() {
    Category childCategory = new Category("firstChild", new Category("rootCategory", null));

    categoryDao.persist(childCategory);
  }

}

This is my config 这是我的配置

@Configuration
@ComponentScan(basePackages = "nl.yoshuan.pricecomparer")
@EnableTransactionManagement
public class TestConfig {

  @Bean
  public DataSource dataSource() {
    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
    return builder.setType(EmbeddedDatabaseType.HSQL).build();
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("nl.yoshuan.pricecomparer.entities");
    factory.setDataSource(dataSource());

    Map<String, Object> jpaProperties = new HashMap<>();
    jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
    jpaProperties.put("hibernate.show_sql", true);
    jpaProperties.put("hibernate.format_sql", true);
    jpaProperties.put("hibernate.use_sql_comments", true);
    jpaProperties.put("hibernate.hbm2ddl.auto", "create-drop");
    factory.setJpaPropertyMap(jpaProperties);

    return factory;
  }

  @Bean
  public PlatformTransactionManager transactionManager() {
    JpaTransactionManager txManager = new JpaTransactionManager();
  txManager.setEntityManagerFactory(entityManagerFactory().getObject());
    return txManager;
  }

}

This is my console output 这是我的控制台输出

2017-05-29 15:43:14 INFO  TransactionContext:101 - Began transaction (1) for test context [DefaultTestContext@971e903 testClass = CategoryDaoUTest, testInstance = nl.yoshuan.pricecomparer.dao.CategoryDaoUTest@2b2f5fcf, testMethod = addTwoCategoriesPersistChildAndGetIllegalStateException@CategoryDaoUTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@108531c2 testClass = CategoryDaoUTest, locations = '{}', classes = '{class nl.yoshuan.pricecomparer.config.TestConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@7661b5a]; rollback [true]
Hibernate: 
    /* insert nl.yoshuan.pricecomparer.entities.Category
        */ insert 
        into
            category
            (category_id, category, parent_category_id) 
        values
            (default, ?, ?)
2017-05-29 15:43:14 INFO  TransactionContext:136 - Rolled back transaction for test context [DefaultTestContext@971e903 testClass = CategoryDaoUTest, testInstance = nl.yoshuan.pricecomparer.dao.CategoryDaoUTest@2b2f5fcf, testMethod = addTwoCategoriesPersistChildAndGetIllegalStateException@CategoryDaoUTest, testException = java.lang.AssertionError: Expected exception: java.lang.IllegalStateException, mergedContextConfiguration = [MergedContextConfiguration@108531c2 testClass = CategoryDaoUTest, locations = '{}', classes = '{class nl.yoshuan.pricecomparer.config.TestConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].
2017-05-29 15:43:14 INFO  GenericApplicationContext:987 - Closing org.springframework.context.support.GenericApplicationContext@49206065: startup date [Mon May 29 15:43:14 CEST 2017]; root of context hierarchy
2017-05-29 15:43:14 INFO  LocalContainerEntityManagerFactoryBean:548 - Closing JPA EntityManagerFactory for persistence unit 'default'
2017-05-29 15:43:14 INFO  SchemaDropperImpl$DelayedDropActionImpl:524 - HHH000477: Starting delayed drop of schema as part of SessionFactory shut-down'
Hibernate: 

    alter table category 
       drop constraint FKs2ride9gvilxy2tcuv7witnxc
Hibernate: 

    drop table category if exists
2017-05-29 15:43:14 INFO  EmbeddedDatabaseFactory:217 - Shutting down embedded database: url='jdbc:hsqldb:mem:testdb'

java.lang.AssertionError: Expected exception: java.lang.IllegalStateException

    at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:32)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

I think you should add @TransactionConfiguration to your unit test. 我认为您应该将@TransactionConfiguration添加到单元测试中。 TransactionConfiguration defines class-level metadata for configuring transactional tests. TransactionConfiguration定义了用于配置事务测试的类级元数据。

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

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