• Hibernate整合进spring使用hibernateTemplate.getSessionFactory().getCurrentSession()理解


    1 单独使用hibernate处理事务

    本来只用hibernate开发,从而可以省了DAO层实现数据库访问和跨数据库,也可以对代码进行更好的封装,当我们web中单独使用hibernate时,我们需要单独的处理hibernate的事务,我是使用filter来对事务进行控制的:

    单独使用hibernate使用filter进行事务控制:

    HibernateSessionFilter.java

    public class HibernateSessionFilter implements Filter {
    
    	public void destroy() {
    		
    	}
    
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
    			ServletException {
    		Session session = HibernateUtils.openSession();
    		Transaction tx = null;
    		try {
    			tx = session.beginTransaction();
    			chain.doFilter(request, response);
    			tx.commit();
    		} catch (Exception e) {
    			if (tx != null) {
    				tx.rollback();
    			}
    			throw new RuntimeException(e);
    		} finally {
    			HibernateUtils.closeAndRemoveSession();
    		}
    	}
    
    	public void init(FilterConfig arg0) throws ServletException {
    	}
    
    }

    web.xml

      <filter>
      	<filter-name>hibernateSessionFilter</filter-name>
      	<filter-class> syx.jpkc.filter.HibernateSessionFilter</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>hibernateSessionFilter</filter-name>
      	<url-pattern>*.syx</url-pattern>
      	<url-pattern>*.jsp</url-pattern>
      	<url-pattern>*.eve</url-pattern>
      </filter-mapping>

    我主要在servlet(*.syx,*.eve)和jsp页面(没用struts)需要和数据库操作,所以需要使用事务处理。

    上面我们还用到了一个 HibernateUtils的小工具类,主要为了获取Session对象和一点优化:

    HibernateUitls.java

    public class HibernateUtils {
    	private static Map<Thread, Session> sessionMap;
    	private static SessionFactory sessionFactory;
    	static {
    		sessionMap = new HashMap<Thread, Session>();
    		sessionFactory = new Configuration().configure().buildSessionFactory();
    	}
    
    	/**
    	 * can only use in web filter, beause it should remove and clear resources
    	 * @return
    	 */
    	public static Session openSession() {
    		System.out.println(Thread.currentThread().getStackTrace()[1] + " run in " + new Date());
    		Session session = sessionMap.get(Thread.currentThread());
    		if (session == null) {
    			session = sessionFactory.openSession();
    			sessionMap.put(Thread.currentThread(), session);
    		}
    		return session;
    	}
    	public static Session getCurrentSession() {
    		return sessionMap.get(Thread.currentThread());
    	}
    
    	public static void closeAndRemoveSession() {
    		System.out.println(Thread.currentThread().getStackTrace()[1]+ " run in " + new Date());//
    		Session session = sessionMap.remove(Thread.currentThread());
    		if (session != null) {
    			session.close();
    		}
    	}
    }

    2 hibernate整合进spring后的事务处理

    spring事物处理的方式有很多,详见:http://www.blogjava.net/robbie/archive/2009/04/05/264003.html

    介绍常用的:

    spring annotation声明式的事务管理

    1) 事物处理层?

    比如保存一个User,可以在Service层和DAOImpl层实现:

    public void save(User u) {
    	userDAO.save(u);
    }
    
    public void save(User u) {
    	System.out.println("save user from:" + this);
    	Session s = sessionFactory.openSession();
    	s.beginTransaction();
    	s.save(u);
    	s.getTransaction().commit();
    	s.close();
    }

    假如我们还有个日志记录,没保存一个User对象,要写入日志进入数据库。

    而save(log) 和 save(user)必须处在同一事务中,所以不能放在DAOImpl层,事务处理在Service层。

    2) 一般的事务处理

     Session sess = factory.openSession();
     Transaction tx;
     try {
         tx = sess.beginTransaction();
         //do some work
         //save(user);
         //save(log);
         ...
         tx.commit();
     } catch (Exception e) {
         if (tx!=null) tx.rollback();
         throw e;
     } finally {
         sess.close();
     }

    并且要在实现层中的save()方法中也要加入事务处理,如果出出现异常要throws给上级处理!

    并且实现层中的session必须使用openCurrentSession()得到。

            Session s = sessionFactory.getCurrentSession();
            s.save(u);

    3) spring annotation事务处理

    Beans.xml中引入相应的xml命名空间和相应配置:

    	xmlns:tx="http://www.springframework.org/schema/tx"
    	http://www.springframework.org/schema/tx 
    	http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    	<tx:annotation-driven transaction-manager="txManager"/>
    	<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    	  <property name="sessionFactory" ref="sessionFactory" />
    	</bean>
    	<bean id="dataSource"
    		class="org.apache.commons.dbcp.BasicDataSource"
    		destroy-method="close">
    		<property name="driverClassName"
    			value="${jdbc.driverClassName}" />
    		<property name="url" value="${jdbc.url}" />
    		<property name="username" value="${jdbc.username}" />
    		<property name="password" value="${jdbc.password}" />
    	</bean>
    	<bean id="sessionFactory"
    		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="annotatedClasses">
    			<list>
    				<value>com.syx.model.User</value>
    				<value>com.syx.model.Log</value>
    			</list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    				<prop key="hibernate.show_sql">true</prop>
    				<prop key="current_session_context_class">thread</prop>
    			</props>
    		</property>
    	</bean>
    	Save方法:
    	public void save(User u) {
    		Session s = sessionFactory.getCurrentSession();
    		s.save(u);
    	}
    	public void save(Log log) {
    		Session s = sessionFactory.getCurrentSession();
    		s.save(log);
    	}
    	Service层处理:
    	@Component("userService")
    	public class UserService {
    		UserDAO userDAO = null;
    		LogDAO logDAO = null;
    		
    		public LogDAO getLogDAO() {
    			return logDAO;
    		}
    		@Resource(name="logDAOMySQLImpl")
    		public void setLogDAO(LogDAO logDAO) {
    			this.logDAO = logDAO;
    		}
    		@Transactional
    		public void save(User u) {
    			userDAO.save(u);
    			Log log = new Log();
    			log.setMsg(u.getName() + " saved in " + new Date());
    			logDAO.save(log);
    		}
    		public UserDAO getUserDAO() {
    			return userDAO;
    		}
    		@Resource(name="userDAOMySQLImpl")
    		public void setUserDAO(UserDAO userDAO) {
    			this.userDAO = userDAO;
    		}
    	}

    4) @Transactional详解

    什么时候rollback

    运行期异常,非运行期异常不会触发rollback

    必须uncheck (没有catch)

    不管什么异常,只要你catch了,spring就会放弃管理

    事务传播特性:propagation_required

    image

    propagation 默认是 REQUIRED ,意思是有我们就用现成的,没的我们就创造一个,其他详细见文档

    spring xml声明式的事务管理

    配置环境和annotation版本一致,只是在用@Transactional处注释调用,在beans.xml中加入如下配置:

    <!-- spring tranception xml config -->
    	<aop:config>
    		<aop:pointcut id="serviceOperation"
    			expression="execution(* com.syx.service..*.*(..))" />
    		<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" />
    	</aop:config>
    
    	<tx:advice id="txAdvice"  transaction-manager="txManager">
    		<tx:attributes>
    			<tx:method name="getUser" read-only="true" />
    			<tx:method name="save" /><!-- 相当于在上面切面pointcut@Transactional效果 -->
    		</tx:attributes>
    	</tx:advice>

    3 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回调:

    return hibernateTemplate.executeWithNativeSession(
    	new HibernateCallback<List<T>>() {
    	public  List<T> doInHibernate(Session session) 
    	throws HibernateException, SQLException {
    		return session.createQuery
    		("FROM " + entityClass.getName() + " WHERE id IN (:ids)")//
    		.setParameterList("ids", idList).list();
    	}

    实际上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之类的操作了。

  • 相关阅读:
    电脑出现的问题以及解决方法
    [2] 立方体(Box)图形的生成算法
    [1] 平面(Plane)图形的生成算法
    [0] 各类图形的数据大小获得
    3D几何图形的生成算法
    3D几何图形生成的DEMO
    花了两天时间为我的引擎实现了性能分析的界面显示
    游戏:贪吃虫(GreedyMaggot)
    相声段子:求爱总动员
    三维体数据分割算法
  • 原文地址:https://www.cnblogs.com/syxchina/p/2265031.html
Copyright © 2020-2023  润新知