[英]Hibernate trying to persist the wrong object
我在Spring Boot項目中的一個單元測試類中遇到了一個我無法解釋的問題。 這是我的測試方法:
// This test creates a record with callback id 5a6775ab4b0af8693ba97c5b
@Test
public void testCreate() throws Exception {
Callback callback = fixtures.getCallback(TestFixtureFactory.EMAILS_SUCCESS);
boolean created = createCallbackDao.createCallback(callback);
assertThat(created).as("Check create callback succeeded").isTrue();
}
// This test creates a record with callback id 5a6775ab4b0af8693ba97c5x and then tries to create it again,
// which is expected to fail with a unique constraint violation.
@Test
public void testAlreadyExists() throws Exception {
Callback callbackA = fixtures.getCallback(TestFixtureFactory.EMAILS_DUPLICATE);
boolean a = createCallbackDao.createCallback(callbackA);
assertThat(a).as("Check first create callback succeeded").isTrue();
assertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> {
Callback callbackB = fixtures.getCallback(TestFixtureFactory.EMAILS_DUPLICATE);
boolean b = createCallbackDao.createCallback(callbackB);
});
}
發生的情況是,首先執行testAlreadyExists()測試並按預期方式通過,但是第二次執行的testCreate()失敗,並發生唯一約束沖突。
我試過分別運行每個測試,並且按預期通過兩個測試。
這是運行兩個測試時testCreate()的日志輸出:
2018-03-19 13:00:21.347 INFO 10646 --- [ main] c.y.p.apicallback.dao.impl.CallbackDao : Create callback for callback id = 5a6775ab4b0af8693ba97c5b
2018-03-19 13:00:21.347 INFO 10646 --- [ main] c.y.p.apicallback.dao.impl.CallbackDao : Callback=Callback [id=13, callbackId=5a6775ab4b0af8693ba97c5b, ...]
2018-03-19 13:00:21.349 DEBUG 10646 --- [ main] org.hibernate.SQL : insert into api_callback (created, last_modified, callback_id, last_update, message, request_source, state, id) values (?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into api_callback (created, last_modified, callback_id, last_update, message, request_source, state, id) values (?, ?, ?, ?, ?, ?, ?, ?)
2018-03-19 13:00:21.350 TRACE 10646 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [TIMESTAMP] - [Mon Mar 19 13:00:21 GMT 2018]
2018-03-19 13:00:21.350 TRACE 10646 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [TIMESTAMP] - [2018-03-19 13:00:21.311]
2018-03-19 13:00:21.350 TRACE 10646 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [VARCHAR] - [5a6775ab4b0af8693ba97c5x]
2018-03-19 13:00:21.350 TRACE 10646 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [TIMESTAMP] - [Tue Jan 23 17:49:31 GMT 2018]
2018-03-19 13:00:21.350 TRACE 10646 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [5] as [VARCHAR] - [Send email request completed.]
2018-03-19 13:00:21.350 TRACE 10646 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [8] as [BIGINT] - [7]
2018-03-19 13:00:21.350 WARN 10646 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23505, SQLState: 23505
2018-03-19 13:00:21.351 ERROR 10646 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Unique index or primary key violation: "API_CALLBACK_U1_INDEX_4 ON API_CALLBACK(CALLBACK_ID) VALUES ('5a6775ab4b0af8693ba97c5x', 1)"; SQL statement:
insert into api_callback (created, last_modified, callback_id, last_update, message, request_source, state, id) values (?, ?, ?, ?, ?, ?, ?, ?) [23505-196]
2018-03-19 13:00:21.351 INFO 10646 --- [ main] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
2018-03-19 13:00:21.351 ERROR 10646 --- [ main] c.y.p.apicallback.dao.impl.CallbackDao : Error creating Callback, time(ms)=4!
org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:112) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
這是被調用的DAO方法的代碼:
@Override
public boolean createCallback(Callback callback) throws Exception {
LOG.info("Create callback for callback id = {}", callback.getCallbackId());
Stopwatch timer = Stopwatch.createStarted();
Session session = null;
Transaction txn = null;
try {
session = sessionFactory.getCurrentSession();
txn = session.getTransaction();
LOG.info("Callback={}", callback);
session.persist(callback);
session.flush();
txn.commit();
LOG.info("CallbackDao.createCallback: company={}, callbackId={}, id={}, time(ms)={}",
callback.getRequest().getUser(), callback.getCallbackId(), callback.getId(), timer.elapsed(TimeUnit.MILLISECONDS));
return true;
} catch (Exception e) {
LOG.error(String.format("Error creating Callback, time(ms)=%d!", timer.elapsed(TimeUnit.MILLISECONDS)), e);
if (txn.getStatus() == TransactionStatus.ACTIVE || txn.getStatus() == TransactionStatus.MARKED_ROLLBACK) {
txn.rollback();
}
throw e;
}
}
API_CALLBACK表具有一個生成的主鍵值(ID)和CALLBACK_ID列上的唯一索引。 ID值是在調用DAO方法以保留記錄之前從數據庫序列派生的。
問題在於應插入數據庫的回調記錄是如下記錄的:
2018-03-19 13:00:21.347 INFO 10646 --- [ main] c.y.p.apicallback.dao.impl.CallbackDao : Callback=Callback [id=13, callbackId=5a6775ab4b0af8693ba97c5b, ...]
但是,根據Hibernate記錄的綁定變量,實際上是在嘗試插入具有不同id和callback id值的記錄:
2018-03-19 13:00:21.350 TRACE 10646 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [VARCHAR] - [5a6775ab4b0af8693ba97c5x] (should be 5a6775ab4b0af8693ba97c5b)
2018-03-19 13:00:21.350 TRACE 10646 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [8] as [BIGINT] - [7] (should be 13)
在testAlreadyExists()測試期間,將ID為7和Callback ID為5a6775ab4b0af8693ba97c5x的記錄插入到本地(H2)數據庫中。
我不知道為什么DAO類顯示它正在處理一個對象實例,但是Hibernate試圖持久化另一個對象實例。 有人可以幫忙嗎?
感謝kirinya (請參見上面的注釋),解決方案是使用注釋javax.transaction.Transactional
使測試類具有事務性。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { TestDatabaseConfiguration.class })
@Transactional
public class TestCreateCallbackDao {
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.