简体   繁体   中英

How can I catch exceptions from with Spring $$EnhancerBySpringCGLIB$$?

I have the same problem as this person. I get that stack trace, due to the fact that I put a new record that violates bound of unique fields:

Exception in thread "main" org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.hibernate5.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:241)
at org.springframework.orm.hibernate5.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:755)
at org.springframework.orm.hibernate5.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:594)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656)
at sistema.database.manager.BookManager$$EnhancerBySpringCGLIB$$d46d6805.create(<generated>)
at tests.unatantum.migration.InactiveBookMigration.migrate(InactiveBookMigration.java:53)
at tests.unatantum.migration.InactiveBookMigration.main(InactiveBookMigration.java:42)

when I call this method (in a manager), it has a generic variable T and the @Transactional was put in the whole class, not on each single method:

public void create(T value) {
    try{
        System.out.println(value);
        getDao().create(value);
        System.out.println("good");
    } catch (DataIntegrityViolationException dive){
        throw new SistemaRuntimeException(dive.getMessage() + ": " + value);
    }   
}

The System.out.println are just for debugging reasons.
The point is that I'd like to be able to catch that exception directly within the manager. But in the stack trace only the unknown class seems to work. How can I catch the exception within the manager (same method, if possible)?
It seems to throw the exception when it commits at the end of the method which calls the one shown (which is in the same manager). Do I really need to put the check before I call the dao, doesn't it make me waste time while I just should be able to wait for the exception?

I think the behavior has to do with the transaction interceptor. If you put @Transactional on the class, Spring creates a dynamic proxy (a subclass of your manager) and basically the call looks like

create(t) -> proxy.handle(methodCall) -> open transaction -> call real method (your manager.create(..), where the catch block is) -> commit transaction (this is where the exception happens) -> return result from proxy.create(t)

So BookManager$$EnhancerBySpringCGLIB$$d46d6805 is a subclass that adds behavior BEFORE and AFTER your method call. The catch happens WITHIN your method call. And the exception occurs on commit. Thus the exception happens within the proxy, outside of your catch. If you want to catch that exception, you need to make sure the transaction is committed before you leave your catch block (eg by making dao.create(..) to be executed in its own transaction).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM