在我的Spring托管类(@Transactional
和@Service
注释)中,我有以下方法:
@Transactional
@Service
public class Foo {
@Autowired
private MyService service; // MyService has @Service and @Transactional annotations
public void save(...) {
try {
service.save(...); // gets a Hibernate Session & calls `merge(...)`
} catch(DataIntegrityViolationException e) {
logMessage("save failed with exception: " + e);
}
}
在我的相应表格中(Foo#save
执行了保存工作),我有一个unique constraint
。
当上述Foo#save
代码以违反唯一约束的方式执行时,我在日志中看到抛出了DataIntegrityViolationException
,但它没有被我抓住Foo#save
' catch
阻止。
org.springframework.orm.jpa.JpaTransactionManager 891 doRollbackOnCommitException -
Initiating transaction rollback after commit exception
org.springframework.dao.DataIntegrityViolationException: Could not execute
JDBC batch update; SQL [insert into MY_TABLE ...; constraint
[MY_CONSTRAINT]; nested exception is
org.hibernate.exception.ConstraintViolationException: Could not execute
JDBC batch update
感到困惑的是DataIntegrityViolationException
未被捕获,我为所有RuntimeException
添加了另一个捕获:
public save(...) {
try {
service.save(...); // `service` is marked with
// @Service and @Transactional
} catch(DataIntegrityViolationException e) {
logMessage("save failed with exception: " + e);
} catch(RuntimeException e) {
logMesssage("runtime exception e: " + e);
}
}
但是,当我运行违反唯一约束违规的相同代码时,我没有看到来自catch(RuntimeException e)
块的日志消息。
我的不完全理解是,由于我使用@Transactional
,Foo
(由Spring创建)的代理将执行save
方法调用。
但是,我有可能抓住DataIntegrityViolationException
调用的service.save(...)
吗?
答案 0 :(得分:1)
方法session.merge(...)
不会立即执行插入/更新SQL查询,而是将此操作放入队列中。会话刷新时将执行SQL查询。在您的情况下,在您的方法执行后,会话将在事务性建议中刷新,并且异常将被抛出。
因此,要在方法中捕获异常,请在session.flush()
之后添加session.merge(...)
,如下所示:
public class MyService {
public void save(Object o) {
Session session = //get session somehow
session.merge(o);
session.flush(); // In case of data integrity violation Exception will be thrown here
}
}