我正在使用 Spring 3.2.1.RELEASE、Hibernate 4.1.9.FINAL 作为 jpa 提供程序、spring data 1.2.0.RELEASE 用于存储库和 bitronix 2.1.3 作为事务管理器来启动一个项目。我对所有这些技术都是新手,所以如果我遗漏了一些重要的观点,我很抱歉。
我正在运行一个简单的单元测试来在数据库中创建一个用户对象:
@ContextConfiguration(locations={"classpath:tests-context.xml"})
@Transactional
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
@RunWith(SpringJUnit4ClassRunner.class)
public class UserTest extends AbstractTransactionalJUnit4SpringContextTests
{
@Autowired
protected UserMgmtService userService;
@Test
public void createUserTest()
{
User user = new User();
user.setFirstName("jonny");
user.setLastName("doe");
user.setUsername("user5");
user.setPasswordHash("1238");
user.setEmail("user5@domain.com");
System.out.println("Created user" + user);
User testUser = userService.saveUser(user);
System.out.println("Saved user" + testUser);
Assert.assertEquals("The user should be equal to saved user", user, testUser);
}
}
我使用的 test-context.xml 如下:
<context:annotation-config/>
<!-- Bitronix Transaction Manager embedded configuration -->
<bean id="btmConfig" factory-method="getConfiguration"
class="bitronix.tm.TransactionManagerServices">
</bean>
<!-- DataSource definition -->
<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource"
init-method="init" destroy-method="close">
<property name="className" value="bitronix.tm.resource.jdbc.lrc.LrcXADataSource" />
<property name="uniqueName" value="jdbc/MySQL_Test_Repository" />
<property name="minPoolSize" value="0" />
<property name="maxPoolSize" value="5" />
<property name="allowLocalTransactions" value="true" />
<property name="driverProperties">
<props>
<prop key="driverClassName">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306 MySQL_Test_Repository</prop>
<prop key="user">root</prop>
<prop key="password">123654</prop>
</props>
</property>
</bean>
<!-- create BTM transaction manager -->
<bean id="BitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig,dataSource"
destroy-method="shutdown" />
<!-- Transaction manager -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"
depends-on="BitronixTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager" />
<property name="userTransaction" ref="BitronixTransactionManager" />
<property name="allowCustomIsolationLevels" value="true" />
</bean>
<!-- AOP configuration for transactions -->
<aop:config>
<aop:pointcut id="userServiceMethods"
expression="execution(* users.service.UserMgmtService.*(..))" />
<aop:advisor advice-ref="transactionAdvice"
pointcut-ref="userServiceMethods" />
</aop:config>
<!-- Transaction configuration -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- bean declaring the property map for the entity manager factory bean -->
<bean id="jpaPropertyMap" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
<entry key="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<!-- show the sql code executed -->
<entry key="hibernate.show_sql" value="true"/>
<!-- format the shown sql code -->
<entry key="hibernate.format_sql" value="true"/>
<!-- enables hibernate to create db schemas from classes;
Possible values: validate | update | create | create-drop
with create-drop the schema will be created/dropped for each hibernate sesssion open/close-->
<entry key="hibernate.hbm2ddl.auto" value="update"/>
<!-- sets the hibernate classname for the TransactionManagerLookup;
hibernate wraps and hides the underlying transaction system and needs a reference
to the transaction manager used -->
<entry key="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<entry key="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.BTMTransactionManagerLookup"/>
</map>
</property>
</bean>
<!-- bean declaring the entity manager factory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="ruleEditor.persistence"/>
<property name="dataSource" ref="dataSource" />
<property name="jpaPropertyMap" ref="jpaPropertyMap"/>
</bean>
<!-- The location where Spring scans for interfaces implementing the JPARepository
and creates their implementation -->
<jpa:repositories base-package="users.repository" />
<!-- Persistence annotations for post processing -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<!-- User service implementation bean -->
<bean id="userMgmtService" class="users.service.impl.UserMgmtServiceImpl"/>
</beans>
Repository 实现是一个标准的 JPARepository:
public interface UserRepository extends JpaRepository<User, Long>
{
User findByUsername(String username);
}
并且服务实现只调用存储库:
@Service("userMgmtService")
public class UserMgmtServiceImpl implements UserMgmtService
{
@Autowired
private UserRepository userRepository;
@Override
public User saveUser(User user)
{
User savedUser = userRepository.save(user);
return savedUser;
}
问题是当我执行测试时,它通过了,但没有在数据库中创建用户。我认为这可能是因为回滚行为,所以我在用户测试中设置了 defaultRollback=false。以下是事务框架在设置为 DEBUG 时提供的一些可能相关的信息:
Running UserTest
2013-02-12 13:01:12 INFO XmlBeanDefinitionReader:315 - Loading XML bean definitionsfrom class path resource [tests-context.xml]
2013-02-12 13:01:12 INFO GenericApplicationContext:510 - Refreshing org.springframework.context.support.GenericApplicationContext@7d95609: startup date [Tue Feb 12 13:01:12 CET 2013]; root of context hierarchy
2013-02-12 13:01:12 INFO GenericApplicationContext:1374 - Bean 'dataSource' of type [class bitronix.tm.resource.jdbc.PoolingDataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:12 INFO GenericApplicationContext:1374 - Bean 'jpaPropertyMap' of type [class org.springframework.beans.factory.config.MapFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:12 INFO GenericApplicationContext:1374 - Bean 'jpaPropertyMap' of type [class java.util.LinkedHashMap] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:12 INFO LocalContainerEntityManagerFactoryBean:264 - Building JPA container EntityManagerFactory for persistence unit 'ruleEditor.persistence'
2013-02-12 13:01:13 INFO SchemaUpdate:182 - HHH000228: Running hbm2ddl schema update
2013-02-12 13:01:13 INFO SchemaUpdate:193 - HHH000102: Fetching database metadata
2013-02-12 13:01:13 INFO SchemaUpdate:205 - HHH000396: Updating schema
2013-02-12 13:01:13 INFO TableMetadata:65 - HHH000261: Table found: MySQL_Test_Repository.user
2013-02-12 13:01:13 INFO TableMetadata:66 - HHH000037: Columns: [id, enabled, first_name, username, email, password_hash, last_name]
2013-02-12 13:01:13 INFO TableMetadata:68 - HHH000108: Foreign keys: []
2013-02-12 13:01:13 INFO TableMetadata:69 - HHH000126: Indexes: [id, username, primary]
2013-02-12 13:01:13 INFO SchemaUpdate:240 - HHH000232: Schema update complete
2013-02-12 13:01:13 INFO BitronixTransactionManager:390 - Bitronix Transaction Manager version 2.1.3
2013-02-12 13:01:13 WARN Configuration:649 - cannot get this JVM unique ID. Make sure it is configured and you only use ASCII characters. Will use IP address instead (unsafe for production usage!).
2013-02-12 13:01:13 INFO Recoverer:152 - recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 1 resource(s) [jdbc/MySQL_Test_Repository]
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'entityManagerFactory' of type [class org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0' of type [class org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' of type [class org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'org.springframework.transaction.config.internalTransactionAdvisor' of type [class org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO JtaTransactionManager:470 - Using JTA UserTransaction: a BitronixTransactionManager with 0 in-flight transaction(s)
2013-02-12 13:01:14 INFO JtaTransactionManager:481 - Using JTA TransactionManager: a BitronixTransactionManager with 0 in-flight transaction(s)
2013-02-12 13:01:14 DEBUG NameMatchTransactionAttributeSource:94 - Adding transactional method [*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception]
2013-02-12 13:01:14 DEBUG AnnotationTransactionAttributeSource:106 - Adding transactional method 'createUserTest' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-02-12 13:01:14 DEBUG AnnotationTransactionAttributeSource:106 - Adding transactional method 'createUserTest' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-02-12 13:01:14 DEBUG JtaTransactionManager:365 - Creating new transaction with name [createUserTest]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-02-12 13:01:14 INFO TransactionalTestExecutionListener:279 - Began transaction (1): transaction manager [org.springframework.transaction.jta.JtaTransactionManager@2a3998f8]; rollback [false]
Created userusers.model.User@63aa9dc1[userId=0,first name=jonny,last name=doe,email=user5@domain.com,username=user5,password=1238,enabled=false]
2013-02-12 13:01:14 DEBUG JtaTransactionManager:470 - Participating in existing transaction
2013-02-12 13:01:14 DEBUG JtaTransactionManager:470 - Participating in existing transaction
Saved userusers.model.User@6b38579e[userId=0,first name=jonny,last name=doe,email=user5@domain.com,username=user5,password=1238,enabled=false]
2013-02-12 13:01:14 DEBUG JtaTransactionManager:752 - Initiating transaction commit
2013-02-12 13:01:14 WARN Preparer:69 - executing transaction with 0 enlisted resource
2013-02-12 13:01:14 INFO TransactionalTestExecutionListener:299 - Committed transaction after test execution for test context [TestContext@5a93c236 testClass = UserTest, testInstance = UserTest@1ab395af, testMethod = createUserTest@UserTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@42821db testClass = UserTest, locations = '{classpath:tests-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.029 sec
2013-02-12 13:01:14 INFO GenericApplicationContext:1042 - Closing org.springframework.context.support.GenericApplicationContext@7d95609: startup date [Tue Feb 12 13:01:12 CET 2013]; root of context hierarchy
2013-02-12 13:01:14 INFO BitronixTransactionManager:320 - shutting down Bitronix Transaction Manager
2013-02-12 13:01:14 INFO LocalContainerEntityManagerFactoryBean:441 - Closing JPA EntityManagerFactory for persistence unit 'ruleEditor.persistence'
日志显示 testException=[null] 但我不知道为什么会这样。我什至尝试使用 JPARepository 提供的 saveAndFlush() 方法但是这样做我得到了错误javax.persistence.TransactionRequiredException: no transaction is in progress
所以如果有人知道我我做错了,可以为我指明正确的方向,我将非常感谢您的帮助。