最近在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;
}