单独使用hibernate处理事务
本来只用hibernate开发,从而可以省了DAO层实现数据库访问和跨数据库,也可以对代码进行更好的封装,当我们web中单独使用hibernate时,我们需要单独的处理hibernate的事务,我是使用filter来对事务进行控制的:
单独使用hibernate使用filter进行事务控制:
02
03 public void destroy() {
04
05 }
06
07 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
08 ServletException {
09 Session session = HibernateUtils.openSession();
10 Transaction tx = null;
11 try {
12 tx = session.beginTransaction();
13 chain.doFilter(request, response);
14 tx.commit();
15 } catch (Exception e) {
16 if (tx != null) {
17 tx.rollback();
18 }
19 throw new RuntimeException(e);
20 } finally {
21 HibernateUtils.closeAndRemoveSession();
22 }
23 }
24
25 public void init(FilterConfig arg0) throws ServletException {
26 }
27
28 }
web.xml
02 <filter-name>hibernateSessionFilter</filter-name>
03 <filter-class> syx.jpkc.filter.HibernateSessionFilter</filter-class>
04 </filter>
05 <filter-mapping>
06 <filter-name>hibernateSessionFilter</filter-name>
07 <url-pattern>*.syx</url-pattern>
08 <url-pattern>*.jsp</url-pattern>
09 <url-pattern>*.eve</url-pattern>
10 </filter-mapping>
我主要在servlet(*.syx,*.eve)和jsp页面(没用struts)需要和数据库操作,所以需要使用事务处理。
上面我们还用到了一个 HibernateUtils的小工具类,主要为了获取Session对象和一点优化:
HibernateUitls.java
28 Session session = sessionMap.remove(Thread.currentThread());
29 if (session != null) {
30 session.close();
31 }
32 }
33 }
hibernate整合进spring后的事务处理
spring事物处理的方式有很多,详见:http://www.blogjava.net/robbie/archive/2009/04/05/264003.html
介绍常用的:
spring annotation声明式的事务管理
事物处理层?
比如保存一个User,可以在Service层和DAOImpl层实现:
07 Session s = sessionFactory.openSession();
08 s.beginTransaction();
09 s.save(u);
10 s.getTransaction().commit();
11 s.close();
12 }
假如我们还有个日志记录,没保存一个User对象,要写入日志进入数据库。
而save(log) 和 save(user)必须处在同一事务中,所以不能放在DAOImpl层,事务处理在Service层。
一般的事务处理
02 Transaction tx;
03 try {
04 tx = sess.beginTransaction();
05 //do some work
06 //save(user);
07 //save(log);
08 ...
09 tx.commit();
10 } catch (Exception e) {
11 if (tx!=null) tx.rollback();
12 throw e;
13 } finally {
14 sess.close();
15 }
并且要在实现层中的save()方法中也要加入事务处理,如果出出现异常要throws给上级处理!
并且实现层中的session必须使用openCurrentSession()得到。
2 s.save(u);
spring annotation事务处理
Beans.xml中引入相应的xml命名空间和相应配置:
67 public void setUserDAO(UserDAO userDAO) {
68 this.userDAO = userDAO;
69 }
70 }
@Transactional详解
什么时候rollback
运行期异常,非运行期异常不会触发rollback
必须uncheck (没有catch)
不管什么异常,只要你catch了,spring就会放弃管理
事务传播特性:propagation_required
propagation 默认是 REQUIRED ,意思是有我们就用现成的,没的我们就创造一个,其他详细见文档
spring xml声明式的事务管理
配置环境和annotation版本一致,只是在用@Transactional处注释调用,在beans.xml中加入如下配置:
12 </tx:attributes>
13 </tx:advice>
hibernateTemplate.getSessionFactory().getCurrentSession()
我们使用spring和hibernate结合,操作数据库最常用可能是HibernateTemplate,HibernateTemplate中集成了很多使用的方法,可惜的是没的createQuery方法,也许我们使用hibernate的时候喜欢使用Query,我们可能会封装hibernateTemplate.getSessionFactory().getCurrentSession()方法得到Session,session创建Query,这是一个方法,但你应该会得到异常 “createQuery without an active transaction”,因为使用hibernateTemplate.getSessionFactory().getCurrentSession(),你是使用的hibernate的事务管理,而你指望spring管理的事务是hibernateTemplate,所以你会提示没有打开事务的异常,解决方法:1)使用hibernate事务处理,就像上面单独使用hibernate一样,但这也许不是你想要的。2)使用hibernateTemplate的HibernateCallBack回调:
8 }
实际上hibernateTemplate中封装的find方法也很强大,如果熟练使用完全可以替代createQuery的。
备注:
如果出现异常:对同一个集合处理不能使用2个session,这是因为getCurrentSession方法出错,导致打开一个新的session,检查配置文件,如果使用tomcat+spring+hibernate 配置hibernate.current_session_context_class 最好为thread,虽然支持jta,配置比较麻烦,而且jta支持多个sessionFactory,即可以跨数据库,比较强大!
如果hibernate+spring出现session没有提交情况,应该是你让spring负责事务处理,而你有使用了hibernate的session,从而脱离spring事务处理,即没的begintransaction和commit之类的操作了。