我最近添加JpaTransactionManager到我的配置和嘗試使用Spring交易。它似乎工作正常,除了我在下面添加的一個測試。JPA /休眠與春季交易不提交
爲什麼我沒有得到預期的IllegalStateException
?我預計這會失敗,因爲parentCategory
字段中的CascadeType
設置爲NONE
。 如果我在庫類中添加em.flush();
,我確實得到了預期的異常。
據我所知,在我的測試中添加@Transaction
只添加了begin,commit和rollback事務方法。所以它應該在提交方法失敗,但它沒有。
根據Hibernate User Guidehibernate.transaction.flush_before_completion
默認爲false。這是我沒有得到預期的異常的原因嗎?
有一個similair post用戶指出提交將導致刷新。這也是我決定問這個問題的原因。
這是我的實體
@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 ...
}
這是我的倉庫
@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;
}
}
這是我的測試
@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);
}
}
這是我的配置
@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;
}
}
這是我的控制檯輸出
2017-05-29 15:43:14 INFO TransactionContext:101 - Began transaction (1) for test context [[email protected] testClass = CategoryDaoUTest, testInstance = [email protected], testMethod = [email protected]DaoUTest, testException = [null], mergedContextConfiguration = [[email protected] 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 [[email protected]]; 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 [[email protected] testClass = CategoryDaoUTest, testInstance = [email protected], testMethod = [email protected]DaoUTest, testException = java.lang.AssertionError: Expected exception: java.lang.IllegalStateException, mergedContextConfiguration = [[email protected] 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 [email protected]206065: 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)
更新的控制檯輸出。 –