• Hibernate事务管理-HibernateTransactionManager-对hibernate session的管理


    由于对SSH还停留在比较初级的应用水平上,今天在遇到一个疑惑时折腾了很久,具体问题是这样的,

    有这么一个测试方法,

    1     public static void test1() {
    2         ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml","daoContext.xml");
    3         MgrManager mgr = (MgrManager)ctx.getBean("mgrManager");
    4         List<EmpBean> emps = mgr.getEmpsByMgr("weblogic");
    5         for (EmpBean empBean : emps) {
    6             System.out.println(empBean.getEmpName());
    7         }
    8     }

    其中的MgrManager是一个业务类, 提供一个根据名字查询员工的功能, 以上方法执行完全没有问题,

    然后又有下面这个测试方法,

        public static void test2() {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml","daoContext.xml");
            EmployeeDao empDao = (EmployeeDao)ctx.getBean("employeeDao");
            Employee emp = empDao.findByName("oracle");
            System.out.println(emp.getSalary());
        }

    test1是使用业务类间接得查询数据库,得到结果,而test2是通过dao直接查询数据库, 但是test2始终报错说没有数据库session。

    百思不得其解,按理说所有的bean是通过spring管理的,既然spring为业务类注入了sessionFactory, 为何dao类就没有呢?

    然后通过手工在test2中写了如下代码,发现是可以通过测试的,

        public static void test3() {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml","daoContext.xml");
            SessionFactory sf = (SessionFactory)ctx.getBean("sessionFactory");
            Session session = sf.openSession();
            List<Employee> emps = session.createQuery("select e from Employee e where e.name = 'oracle'").list();
        }

    也就是说,问题不在于Spring容器中没有sessionFactory, 而是sessionFactory没有被open!那为什么test1的例子中的sessionFaction又open了呢?

    看了配置文件半天,发现有这么关键的一行配置,

    <aop:pointcut id="leePointcut" expression="bean(empManager)||bean(mgrManager))" />

    另外,通过面向切面编程原理,Spring通过AOP机制为dao对象的数据操作提供事务管理,有如下配置,

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 配置详细的事务语义 -->
        <tx:attributes>
            <!-- 所有以get开头的方法是只读的 -->
            <tx:method name="get*" read-only="true" />
            <!-- 其他方法使用默认设置 -->
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>
    <aop:config>
    <!-- 配置一个切入点,用来匹配empManager和mgrManager两个Bean的所有方法的执行 -->
    <aop:pointcut id="leePointcut" expression="bean(empManager)||bean(mgrManager)||bean(employeeDao)" />
    <!-- 指定在leePointcut切入点应用txAdvice事务增强 -->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="leePointcut" />
    </aop:config>

    而下面这段配置是用来配置真正的事务管理类, 正是通过上面的切面配置, 将业务类与增强处理关联起来, 同时通过下面的事务管理类进行事务管理

    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"
        p:sessionFactory-ref="sessionFactory" />

    那么重点就在上面的transactionManager这个bean了, 通过查询资料,初步了解到, HibernateTransactionManager这个类提供 sessionFactory的管理,为了实现数据同步,在HibernateTransactionManager内部会进行Hibernate session的open和close,并将打开的Hibernaate sesion关联到当前的Application session,在Application中则通过getCurrentSession方式获取争取的打开的Hibernate session,  从而解决某些方面的线程安全及同步问题。

    由此可见,由于上面配置事务管理的切面类仅仅只是针对了业务类,即默认情况下只有业务类才用于打开的session, 由此可以理解上面的test2为什么报“没有打开的session”错误了。

    针对上面的配置, 我做了如下修改,

    <bean id="TestManager" class="service.impl.TestManagerImpl" p:empDao-ref="employeeDao"/>

    果然修改之后test2就能正常执行了。

    以上仅仅涉及非常非常小的问题, 主要还是对HibernateTransactionManager的理解不够深入造成的。

  • 相关阅读:
    优雅高效的MyBatis-Plus工具快速入门使用
    mybatis中#{}和${}的区别
    异常处理com.sun.image.codec.jpeg.JPEGImageEncoder
    图片压缩之-JPEGCodec失效替换方案
    Bugly实现app全量更新
    MyBatis下MySqL用户口令不能为空
    java.lang.OutOfMemoryError: PermGen space及其解决方法
    Hibernate or 的用法
    如何理解<base href="<%=basePath%>"
    小程序 wx.request ajax示例
  • 原文地址:https://www.cnblogs.com/fysola/p/6719800.html
Copyright © 2020-2023  润新知