我现在有点困惑:-S
我正在开发一个使用JPA2,Spring 3.0.5,Hibernate 3.6.0 Final的项目。我们有以下代码(仅相关类)
@Entity
public class User extends AbstractEntity implements Serializable {
@Id
@Column(name = "ID", nullable = false, insertable = true, updatable = true, length = 36)
protected String id;
@NotNull
@Size(min = 1, max = 30)
@Column(name = "NAME", length = 30, nullable = false)
private String name;
protected User() {
id = java.util.UUID.randomUUID().toString();
}
@Override
public boolean equals(Object object) {
if (!(object instanceof User)) {
return false;
}
User other = (User) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
}
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@PersistenceContext
private EntityManager em;
public void create(User user) throws PreexistingEntityException, Exception {
try {
em.persist(user);
} catch (EntityExistsException ex) {
logger.error("User " + user + " already exists.", ex);
throw new PreexistingEntityException("User " + user + " already exists.", ex);
} catch (Exception ex) {
logger.error("Exception occurred:", ex);
throw ex;
}
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/testDaoContext.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public class UserDaoTest {
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Test
public void testInsertUserExistingID() {
User user = User.valueOf("1");
user.setFirstname("DUMMY");
user.setName("CRASH");
logger.debug(user);
try {
userDao.create(user);
sessionFactory.getCurrentSession().flush();
} catch (PreexistingEntityException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
logger.debug("id = " + user.getId());
User retrieved = userDao.find(user.getId());
Assert.assertEquals(user.getId(), retrieved.getId());
Assert.assertEquals("DUMMY", retrieved.getFirstname());
Assert.assertEquals("CRASH", retrieved.getName());
}
}
现在,当我将rollback设置为false运行测试(我知道,这不是一个真正的单元测试)时,我得到以下堆栈跟踪:
org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [insert into PV_UMDB.USERS (CREATION_DT, CREATION_USR, MODIFICATION_USR, MODIFICATION_DT, VERSION, BIRTHDAY, EMAIL, FAX, FIRSTNAME, INTERNAL, MOBILE, NAME, PHONE, PICTURE, STAFF_NO, STAFF_NO_KBC, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; constraint [PV_UMDB.USERS_PK]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:637)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:102)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:471)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:515)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:290)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:183)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:406)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:90)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
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:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
... 25 more
Caused by: java.sql.BatchUpdateException: ORA-00001: unique constraint (PV_UMDB.USERS_PK) violated
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10768)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 34 more
如果我使用回滚,则测试通过,这当然是不正确的。
现在,有一个很好的解决方案吗?
感谢您的帮助
BB 彼得
答案 0 :(得分:1)
您不能依赖EntityExistsException
抛出的persist()
。
来自javadoc:
EntityExistsException
- 如果是实体 已经存在。 (如果实体已经 存在,EntityExistsException
可能 持续操作时抛出 被调用,或者EntityExistsException
或其他PersistenceException
可能被抛出 刷新或提交时间。)
在您的情况下,您将在提交时抛出另一个异常。如果你替换
sessionFactory.getCurrentSession().flush();
与
em.flush();
你可以在刷新时捕获PersistenceException
(我不确定为什么它与SessionFactory
的工作方式不同。)
答案 1 :(得分:0)
测试是看用户是否有 存储现有ID, 抛出PreexistingEntityException。
检查例外的一般模式是:
JUnit3的psydocode
try {
invokeExceptionThrowingMethod();
fail("ExceptionX expected");
} catch(ExcpectedException e) {
//expected - do nothing
}
我强烈相信,如果您更清楚地编写测试用例,那么您将发现错误。
<强>编辑强>
在您的情况下,您需要第二个变体,因为测试不能接受第一个用户创建的异常。
@Test
public void testInsertUserExistingID()
//(See my comment to your question about throwing Exception)
throws Exception{
User user = User.valueOf("1");
user.setFirstname("DUMMY");
user.setName("CRASH");
try {
userDao.create(user);
sessionFactory.getCurrentSession().flush();
fail("PreexistingEntityException expected");
} catch (PreexistingEntityException e) {
//Thats what is execpected
}
}
无论如何:axtavt是对的