hibernate学习笔记3--事务管理

1、只涉及到简单的业务流程(每个业务只涉及一个dao操作)
此时不需要service层,只要dao就够了。
例子:

    public void insertUser(Users user) {  
        Session session=SessionFactory.openSession();  
        Transaction ts=session.beginTransaction();  
        session.save(user);  
        ts.commit();  
        session.close();  
    }  

这里的SessionFactory.openSession()每次都打开一个新的session。session的关闭也可以配置为事务提交后自动关闭:

    <property name="hibernate.transaction.auto_close_session">true</property>  

2、业务流程复杂,一个业务中涉及多个dao操作,此时可使用绑定到JDBC事务的方法,还可以使用JTA事务(依赖于容器),也可以选择spring事务拦截器,由spring管理更好,可以从session、事务的管理中解脱出来。
1)将session绑定到JDBC事务上实现:
若一个事务中涉及多个dao操作,就需要将session绑定到JDBC事务,使得当前事务中获取的session都是同一个session,保证事务完整。
使用SessionFactory.getCurrentSession()取得与当前JDBC事务关联的session。
session的打开与关闭无需关心,由hibernate管理。
注意需要配置:

    <property name="current_session_context_class">thread</property>  

而且在查询时也必须开启一个事务,否则报错。
这样在一个事务中调用多个dao操作,各个dao中的session都是同一个session。
一个包含了多个dao操作的业务层代码如下:

    //模拟转账  
    public void transfer(){  
        Transaction ts=SessionFactory.getCurrentSession().beginTransaction();  
        accoutDao.add("accout_A",100);  
        accoutDao.add("accout_B",-100);  
        ts.commit();  
    }  

上面是基于配置方式绑定session到JDBC事务,也可以使用局部线程变量,达到共用同一个session的目的,实现多dao操作的事务管理。此时getSession()方法如下:

    public static Session getSession() throws HibernateException {  
            Session session = (Session) threadLocal.get();  
            if (session == null || !session.isOpen()) {  
                if (sessionFactory == null) {  
                    rebuildSessionFactory();  
                }  
                session = (sessionFactory != null) ? sessionFactory.openSession()  
                        : null;  
                threadLocal.set(session);  
            }  
            return session;  
        }  

这样,在一个事务里面不同dao中拿到的session其实是一个session(与当前事务关联),而且查询时不需要开启事务,不需要配置<property name="current_session_context_class">thread</property>
Demo:
dao层

    public void add(String id,double number) {  
        Session s = SessionFactory.getSession();  
        Account acc=s.get(Account.Class,id);  
        acc.setBalance(acc.getBalance()+number);  
        s.update(acc);  
    }  

业务层:

    public void transfer(){  
        Transaction ts=SessionFactory.getSession().beginTransaction();  
        accoutDao.add("accout_A",100);  
        accoutDao.add("accout_B",-100);  
        ts.commit();  
    }  

两个dao操作任何一个失败,事务都不会提交(提交之前就发生了异常),保持数据一致。
这样将事务管理放在业务层,dao层只需做原始的CRUD即可,无需关心事务和session。

但是这样有一个明显的缺点:事务失败后需要手动关闭session,因为session配置为自动关闭是当事务正确提交时或者失败回滚时才会自动关闭session(使用getCurrentSession()的不需要这样,但查询也要开启事务)。
2)使用Spring实现:
spring配置:

    <bean id="dataSource"  
        class="org.springframework.jndi.JndiObjectFactoryBean" destroy-method="close">  
            <property name="jndiName">  
                <value>java:comp/env/jdbc/pingshen</value>  
            </property>  
    </bean>   

    <bean id="sessionFactory"       class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
            <property name="dataSource">  
                <ref bean="dataSource" />  
            </property>  
            <property name="hibernateProperties">  
                <props>  
                    <prop key="hibernate.dialect">  
                        org.hibernate.dialect.SQLServerDialect  
                    </prop>  
                </props>  
            </property>  
            <property name="mappingResources">  
    <list>  
             <value>com/cjlu/vo/Users.hbm.xml</value>  
    </list>  
            </property>  
        </bean>  
        <bean id="hibernateTemplate"            class="org.springframework.orm.hibernate3.HibernateTemplate" abstract="true">  
            <property name="sessionFactory">  
                <ref bean="sessionFactory" />  
            </property>  
        </bean>  

        <bean id="transactionManager"            class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
            <property name="sessionFactory">  
                <ref bean="sessionFactory" />  
            </property>  
        </bean>  

        <!-- 配置事务拦截器 -->  
        <bean id="txInterceptor"            class="org.springframework.transaction.interceptor.TransactionInterceptor">  
            <property name="transactionManager" ref="transactionManager" />  
            <property name="transactionAttributes">  
                <!-- 定义事务传播属性 -->  
                <props>  
    key="get*">PROPAGATION_REQUIRED,readOnly</prop>  
                    <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>  
                    <prop key="*">PROPAGATION_REQUIRED</prop>  
                </props>  
            </property>  
        </bean>  
        <!-- 配置自动代理 -->  
        <bean  
            class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
            <property name="beanNames">  
                <list>  
                    <!-- 这里可以新增要代理的业务bean-->  
                    <value>userService</value>  
                </list>  
            </property>  
            <property name="interceptorNames">  
                <list>  
                    <value>txInterceptor</value>  
                </list>  
            </property>  
        </bean>  
    <bean id="userService"  
            class="com.cjlu.service.impl.UserServiceImpl">  
            <property name="userDao">  
                <bean class="com.cjlu.dao.impl.UserDaoImpl" parent="hibernateTemplate">  
                </bean>  
            </property>  
        </bean>  

注意:此时需要spring的IOC(依赖注入),即每个DaoImpl实现类需要继承HibernateDaoSupport类,并在spring配置文件注入hibernateTemplate,为HibernateDaoSupport中的hibernateTemplate属性绑定hibernate模板。

另外,Action中需要注入Service以便调用,不要在DaoImpl中lookup(datasource),以保证事务的完整性。

DaoImpl中从父类HibernateDaoSupport中继承了getSession()方法,只要使用了Spring声明式事务,用完后不需要关闭,DaoImpl只负责原始的数据操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值