我有一个问题。我使用Spring + Hibernate,我无法处理标记为 @Transactional 的方法中的异常。以前,当我使用Spring JDBC时,一切工作都很好。
DAO类标有@Repository
这是我旧代码的摘要
在服务中
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, rollbackFor = {Exception.class})
public boolean bookTickets(Integer userId, List<Integer> ticketsId) throws TicketsServiceException {
Integer currId = null;
try {
for (Integer ticketId : ticketsId) {
currId = ticketId;
Ticket ticket = ticketDAO.getTicketById(ticketId);
bookingDAO.bookTicket(ticket, userId);
}
} catch (DuplicateKeyException e) {
throw new TicketsServiceException(String.format(MESSAGE_TICKET_ALREADY_BOOKED, currId));
} catch (EmptyResultDataAccessException e) {
throw new TicketsServiceException(String.format(MESSAGE_NO_SUCH_TICKET, currId));
}
return true;
in dao:
@Transactional(propagation = Propagation.MANDATORY)
public void bookTicket(Ticket ticket, final int userId) {
MapSqlParameterSource map = new MapSqlParameterSource();
map.addValue(Constants.TABLE_BOOKING.FIELD_TICKET_ID, ticket.getId());
map.addValue(Constants.TABLE_BOOKING.FIELD_USER_ID, userId);
int rowsAffected = template.update(QUERY_INSERT_BOOKING, map);
if (LOG.isTraceEnabled()) {
LOG.trace("Affected " + rowsAffected + " rows.");
}
}
现在我将我的DAO从Spring JDBC移到hibernate 3上。
这就是我现在拥有的。
在服务中
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, rollbackFor = {Exception.class})
public boolean bookTickets(Integer userId, List<Integer> ticketsId) throws TicketsServiceException {
Integer currId = null;
try {
for (Integer ticketId : ticketsId) {
currId = ticketId;
Ticket ticket = ticketDAO.getTicketById(ticketId);
bookingDAO.bookTicket(new Booking(ticketId, userId));
}
} catch (Exception e) {
throw new TicketsServiceException(String.format(MESSAGE_THERE_IS_NO_SUCH_TICKET_OR_ALREADY_BOOKED, currId));
}
return true;
}
dao中的 :
@Override
public void bookTicket(Booking booking) {
getHibernateTemplate().save(booking);
}
问题是我无法在服务方法中处理try-catch块内的异常。他们直接投入我的控制器。
我认为Spring JDBC中的事务管理器 org.springframework.jdbc.datasource.DataSourceTransactionManager 与 org.springframework.orm.hibernate3.HibernateTransactionManager 之间存在差异。休眠,但我没有任何想法如何克服这个问题,所以我需要你的帮助。
更新后。增加例外情况。
2013-10-21 14:51:17 ERROR BookingController:89 - Unhandled exception
org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [insert into booking (ticket_id, user_id, booking_id) values (?, ?, ?)]; constraint ["CONSTRAINT_INDEX_2 ON PUBLIC.BOOKING(TICKET_ID) VALUES ( /* key:1 */ 2, 1, 1)"; SQL statement:
insert into booking (ticket_id, user_id, booking_id) values (?, ?, ?) [23505-173]]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:643)
at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:793)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:664)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at cdp.tarasenko.springmvc.task3.service.TicketsService$$EnhancerByCGLIB$$fabdc899.bookTickets(<generated>)
at cdp.tarasenko.springmvc.task3.controller.BookingController.bookTickets(BookingController.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:755)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:594)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:486)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:119)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1065)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:413)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:192)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:999)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:250)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
at org.eclipse.jetty.server.Server.handle(Server.java:351)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:454)
at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:900)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:954)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:857)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:77)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:609)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:45)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:599)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:534)
at java.lang.Thread.run(Thread.java:662)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:237)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
... 51 more
Caused by: org.h2.jdbc.JdbcBatchUpdateException: Нарушение уникального индекса или первичного ключа: "CONSTRAINT_INDEX_2 ON PUBLIC.BOOKING(TICKET_ID) VALUES ( /* key:1 */ 2, 1, 1)"
Unique index or primary key violation: "CONSTRAINT_INDEX_2 ON PUBLIC.BOOKING(TICKET_ID) VALUES ( /* key:1 */ 2, 1, 1)"; SQL statement:
insert into booking (ticket_id, user_id, booking_id) values (?, ?, ?) [23505-173]
at org.h2.jdbc.JdbcPreparedStatement.executeBatch(JdbcPreparedStatement.java:1167)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 59 more
有没有办法处理服务层内的异常?
谢谢。
答案 0 :(得分:1)
看看休眠FlushMode
默认HiberanateTemplate
FlushMode
为FlusMode.AUTO
,因此会在提交时或某些查询之前进行会话同步,以防止过时状态。
您可以将HibernateTemplate刷新模式更改为FlushMode.ALWAYS,效率低且不推荐(但会按预期工作),或者在某些时候调用Session.flush()。
请参阅HiberanateTemplate.setFlushMode()
和Session.flush()
答案 1 :(得分:1)
在提交TX和TX在事务管理器中提交之前,您不会遇到像约束违规一样的数据库异常。最好的解决方案是使用afterThrowing
方面(AOP)处理TX管理器异常。或者,您可以在服务中的另一个非事务性方法中调用@Transactional
方法,并使其捕获异常。就个人而言,我不喜欢后者,因为你必须为你的所有服务创建一个包装方法。
答案 2 :(得分:1)
或者您可以在显式事务模式下调用事务代码。
E.g。
void