最近在Java项目中使用到了Spring和hibernate,其中使用到的事务管理,
spring 配置文件 如下
- public static void main(String[] args) {
- ApplicationContext ctx=SpringAppContext.getInstance().getApplicationContext();
- NoticeDao g=ctx.getBean(NoticeDao.class);
- /*****独立执行saveNotice()和saveNotice1()********/
- System.out.println(g.saveNotice());
- g.saveNotice1();
- /*******在saveNotice2()中执行saveNotice()和saveNotice1()*******/
- /*g.saveNotice2();*/
- }
- @Override
- @Transactional(propagation=Propagation.REQUIRED)
- public Session saveNotice() {
- // TODO Auto-generated method stub
- Session session= this.database.getSf().getCurrentSession();
- System.out.println("saveNotice():"+session);
- session.createSQLQuery("insert into notice(content) value('aaa');").executeUpdate();
- //session.createSQLQuery("insert into notice(content) value(bbb);").executeUpdate();
- //session.close();
- return session;
- }
- @Override
- @Transactional(propagation=Propagation.REQUIRED)
- public void saveNotice1() {
- // TODO Auto-generated method stub
- Session session= this.database.getSf().getCurrentSession();
- System.out.println("saveNotice1():"+session);
- //session.createSQLQuery("insert into notice(content) value('aaa');").executeUpdate();
- session.createSQLQuery("insert into notice(content) value(bbb);").executeUpdate();
- //session.close();
- }
- @Override
- @Transactional(propagation=Propagation.REQUIRED)
- public void saveNotice2() {
- saveNotice();
- saveNotice1();
- }
1执行 saveNotice2()
结果如下
- saveNotice():SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2a898881 updates=org.hibernate.engine.spi.ExecutableList@16c63f5 deletions=org.hibernate.engine.spi.ExecutableList@35229f85 orphanRemovals=org.hibernate.engine.spi.ExecutableList@6d3c5255 collectionCreations=org.hibernate.engine.spi.ExecutableList@b1712f3 collectionRemovals=org.hibernate.engine.spi.ExecutableList@6986bbaf collectionUpdates=org.hibernate.engine.spi.ExecutableList@4879dfad collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@4758820d unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
- Hibernate:
- insert
- into
- notice
- (content) value('aaa');
- saveNotice1():SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2a898881 updates=org.hibernate.engine.spi.ExecutableList@16c63f5 deletions=org.hibernate.engine.spi.ExecutableList@35229f85 orphanRemovals=org.hibernate.engine.spi.ExecutableList@6d3c5255 collectionCreations=org.hibernate.engine.spi.ExecutableList@b1712f3 collectionRemovals=org.hibernate.engine.spi.ExecutableList@6986bbaf collectionUpdates=org.hibernate.engine.spi.ExecutableList@4879dfad collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@4758820d unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
- Hibernate:
- insert
- into
- notice
- (content) value(bbb);
- Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute statement
通过分析结果 可知
saveNotice2()加入的事务处理,insert('aaa') 正常执行,insert(bbb)异常,数据库结果显示并没有插入aaa,说明事物遇到异常产生了回滚,事务处理,而通过打印对比session,可以在saveNotice2()拿到的currentsession是相同的,而事实上SaveNotice()和 saveNotice1() 都加入过session,按照getCurrentSession应该是事务执行完自动commit和关闭session,结果应该是两个session不同,且插入’aaa‘和bbb互为独立事务,但实际上回滚了数据,说明并没有已他们的事务执行或者忽略了其各自的事务,我个人猜想应该和事务传播行 (propagation=Propagation.REQUIRED)有关;另外getCurrentSession在同一事务下,拿到的session永远是同一个
2分别执行
- NoticeDao g=ctx.getBean(NoticeDao.class);
- System.out.println(g.saveNotice());
- g.saveNotice1();
结果如下
- saveNotice():SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2a898881 updates=org.hibernate.engine.spi.ExecutableList@16c63f5 deletions=org.hibernate.engine.spi.ExecutableList@35229f85 orphanRemovals=org.hibernate.engine.spi.ExecutableList@6d3c5255 collectionCreations=org.hibernate.engine.spi.ExecutableList@b1712f3 collectionRemovals=org.hibernate.engine.spi.ExecutableList@6986bbaf collectionUpdates=org.hibernate.engine.spi.ExecutableList@4879dfad collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@4758820d unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
- Hibernate:
- insert
- into
- notice
- (content) value('aaa');
- SessionImpl(<closed>)
- saveNotice1():SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2cc3ad05 updates=org.hibernate.engine.spi.ExecutableList@710b18a6 deletions=org.hibernate.engine.spi.ExecutableList@119020fb orphanRemovals=org.hibernate.engine.spi.ExecutableList@3d9f6567 collectionCreations=org.hibernate.engine.spi.ExecutableList@c055c54 collectionRemovals=org.hibernate.engine.spi.ExecutableList@25e2ab5a collectionUpdates=org.hibernate.engine.spi.ExecutableList@35e5d0e5 collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@73173f63 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
- Hibernate:
- insert
- into
- notice
- (content) value(bbb);
- Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute statement
通过结果分析,getCurrentSession中的session在事务完成后会自动commit和close,getCurrentSession在相互独立事务中拿到的session是不同的,另外 getCurrentSession得到的session是和事务绑定的,要用getCurrentSession生产的session,就必须有事务环境,否则会抛出
- org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
一开始使用事务由于使用了 aop捕获了相关运行时异常,导致事务下异常没有被抛出,事务没能拿到运行时异常,并没有回滚数据,对于非运行时异常,事务也不会产生回滚,除非使用Spring的rollback-for配置,指定相关异常执行回滚
- <!-- 切面捕获异常并写入日志 -->
- <!-- <bean id="aspectBean" class="dw.aop.log.Aspect" /> -->
- <!-- Aop配置 expression 表达式 配置dw包下所有类及子类或接口的所有方法 -->
- <!-- <aop:config>
- <aop:aspect id="aspect" ref="aspectBean">
- <aop:pointcut id="logService" expression="execution(* dw..*.*(..))" />
- <aop:before pointcut-ref="logService" method="doBefore" />
- <aop:after pointcut-ref="logService" method="doAfter" />
- <aop:around pointcut-ref="logService" method="doAround" />
- </aop:aspect>
- </aop:config> -->
Aspect.java
- /**
- * 环绕通知:包围一个连接点的通知,可以在方法的调用前后完成自定义的行为,也可以选择不执行
- * 类似Web中Servlet规范中的Filter的doFilter方法。
- *
- * @param pjp
- * 当前进程中的连接点
- * @return
- * @throws Throwable
- */
- public Object doAround(ProceedingJoinPoint pjp){
- Object retVal = null;
- try {
- retVal = pjp.proceed();
- } catch (Throwable e) {
- e.printStackTrace();
- logger.error(pjp.getTarget().getClass().getName() + "类的方法:"
- + pjp.getSignature().getName()+ pjp.getSignature()+"执行出错",e);
- }
- return retVal;
- }
以上纯属个人理解,如有错误,欢迎指正
最近在Java项目中使用到了Spring和hibernate,其中使用到的事务管理,
spring 配置文件 如下
- public static void main(String[] args) {
- ApplicationContext ctx=SpringAppContext.getInstance().getApplicationContext();
- NoticeDao g=ctx.getBean(NoticeDao.class);
- /*****独立执行saveNotice()和saveNotice1()********/
- System.out.println(g.saveNotice());
- g.saveNotice1();
- /*******在saveNotice2()中执行saveNotice()和saveNotice1()*******/
- /*g.saveNotice2();*/
- }
- @Override
- @Transactional(propagation=Propagation.REQUIRED)
- public Session saveNotice() {
- // TODO Auto-generated method stub
- Session session= this.database.getSf().getCurrentSession();
- System.out.println("saveNotice():"+session);
- session.createSQLQuery("insert into notice(content) value('aaa');").executeUpdate();
- //session.createSQLQuery("insert into notice(content) value(bbb);").executeUpdate();
- //session.close();
- return session;
- }
- @Override
- @Transactional(propagation=Propagation.REQUIRED)
- public void saveNotice1() {
- // TODO Auto-generated method stub
- Session session= this.database.getSf().getCurrentSession();
- System.out.println("saveNotice1():"+session);
- //session.createSQLQuery("insert into notice(content) value('aaa');").executeUpdate();
- session.createSQLQuery("insert into notice(content) value(bbb);").executeUpdate();
- //session.close();
- }
- @Override
- @Transactional(propagation=Propagation.REQUIRED)
- public void saveNotice2() {
- saveNotice();
- saveNotice1();
- }
1执行 saveNotice2()
结果如下
- saveNotice():SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2a898881 updates=org.hibernate.engine.spi.ExecutableList@16c63f5 deletions=org.hibernate.engine.spi.ExecutableList@35229f85 orphanRemovals=org.hibernate.engine.spi.ExecutableList@6d3c5255 collectionCreations=org.hibernate.engine.spi.ExecutableList@b1712f3 collectionRemovals=org.hibernate.engine.spi.ExecutableList@6986bbaf collectionUpdates=org.hibernate.engine.spi.ExecutableList@4879dfad collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@4758820d unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
- Hibernate:
- insert
- into
- notice
- (content) value('aaa');
- saveNotice1():SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2a898881 updates=org.hibernate.engine.spi.ExecutableList@16c63f5 deletions=org.hibernate.engine.spi.ExecutableList@35229f85 orphanRemovals=org.hibernate.engine.spi.ExecutableList@6d3c5255 collectionCreations=org.hibernate.engine.spi.ExecutableList@b1712f3 collectionRemovals=org.hibernate.engine.spi.ExecutableList@6986bbaf collectionUpdates=org.hibernate.engine.spi.ExecutableList@4879dfad collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@4758820d unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
- Hibernate:
- insert
- into
- notice
- (content) value(bbb);
- Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute statement
通过分析结果 可知
saveNotice2()加入的事务处理,insert('aaa') 正常执行,insert(bbb)异常,数据库结果显示并没有插入aaa,说明事物遇到异常产生了回滚,事务处理,而通过打印对比session,可以在saveNotice2()拿到的currentsession是相同的,而事实上SaveNotice()和 saveNotice1() 都加入过session,按照getCurrentSession应该是事务执行完自动commit和关闭session,结果应该是两个session不同,且插入’aaa‘和bbb互为独立事务,但实际上回滚了数据,说明并没有已他们的事务执行或者忽略了其各自的事务,我个人猜想应该和事务传播行 (propagation=Propagation.REQUIRED)有关;另外getCurrentSession在同一事务下,拿到的session永远是同一个
2分别执行
- NoticeDao g=ctx.getBean(NoticeDao.class);
- System.out.println(g.saveNotice());
- g.saveNotice1();
结果如下
- saveNotice():SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2a898881 updates=org.hibernate.engine.spi.ExecutableList@16c63f5 deletions=org.hibernate.engine.spi.ExecutableList@35229f85 orphanRemovals=org.hibernate.engine.spi.ExecutableList@6d3c5255 collectionCreations=org.hibernate.engine.spi.ExecutableList@b1712f3 collectionRemovals=org.hibernate.engine.spi.ExecutableList@6986bbaf collectionUpdates=org.hibernate.engine.spi.ExecutableList@4879dfad collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@4758820d unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
- Hibernate:
- insert
- into
- notice
- (content) value('aaa');
- SessionImpl(<closed>)
- saveNotice1():SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2cc3ad05 updates=org.hibernate.engine.spi.ExecutableList@710b18a6 deletions=org.hibernate.engine.spi.ExecutableList@119020fb orphanRemovals=org.hibernate.engine.spi.ExecutableList@3d9f6567 collectionCreations=org.hibernate.engine.spi.ExecutableList@c055c54 collectionRemovals=org.hibernate.engine.spi.ExecutableList@25e2ab5a collectionUpdates=org.hibernate.engine.spi.ExecutableList@35e5d0e5 collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@73173f63 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
- Hibernate:
- insert
- into
- notice
- (content) value(bbb);
- Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute statement
通过结果分析,getCurrentSession中的session在事务完成后会自动commit和close,getCurrentSession在相互独立事务中拿到的session是不同的,另外 getCurrentSession得到的session是和事务绑定的,要用getCurrentSession生产的session,就必须有事务环境,否则会抛出
- org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
一开始使用事务由于使用了 aop捕获了所有运行时异常,导致事务异常没有被抛出,事务没能拿到运行时异常,并没有回滚数据,对于非运行时异常,事务也不会产生回滚,除非使用Spring的rollback-for配置,指定相关异常执行回滚
- <!-- 切面捕获异常并写入日志 -->
- <!-- <bean id="aspectBean" class="dw.aop.log.Aspect" /> -->
- <!-- Aop配置 expression 表达式 配置dw包下所有类及子类或接口的所有方法 -->
- <!-- <aop:config>
- <aop:aspect id="aspect" ref="aspectBean">
- <aop:pointcut id="logService" expression="execution(* dw..*.*(..))" />
- <aop:before pointcut-ref="logService" method="doBefore" />
- <aop:after pointcut-ref="logService" method="doAfter" />
- <aop:around pointcut-ref="logService" method="doAround" />
- </aop:aspect>
- </aop:config> -->
Aspect.java
- /**
- * 环绕通知:包围一个连接点的通知,可以在方法的调用前后完成自定义的行为,也可以选择不执行
- * 类似Web中Servlet规范中的Filter的doFilter方法。
- *
- * @param pjp
- * 当前进程中的连接点
- * @return
- * @throws Throwable
- */
- public Object doAround(ProceedingJoinPoint pjp){
- Object retVal = null;
- try {
- retVal = pjp.proceed();
- } catch (Throwable e) {
- e.printStackTrace();
- logger.error(pjp.getTarget().getClass().getName() + "类的方法:"
- + pjp.getSignature().getName()+ pjp.getSignature()+"执行出错",e);
- }
- return retVal;
- }