如何正确使用spring的事务管理

在使用spring进行数据库事务管理时,不管是采用JDBC还是hibernate都必须处理好如何获取链接的问题,不能过简单使用getSession(),和 ds.getConnect()来获取数据连接,否则链接一次请求访问就会耗用多个数据连接.

 

使用HibernateTransactionManager正确的方法是:

xml配置(省略,网上有很多相关的资料)

 

基础DAO

public class GenericDao {

      protected SessionFactory sessionFactory;

        //设置sessionFacotry

@Resource(name = "sessionFactory")

public void setSessionFactory(SessionFactory sessionFactory) {

this.sessionFactory = sessionFactory;

}

       //获得session

protected Session getSession() {

                //使用getCurrentSession(),确保在同一非嵌套型的事务中只消耗一个连接

               //如果在此处直接调用getSession()那么在实际操作中,调用该方法多少次,便会消耗多少个连接

return sessionFactory.getCurrentSession();

}

......

}

 

使用Jdbc Spring事务处理的正确使用方法:

spring Bean 配置文件片段:

org.springframework.jdbc.datasource.DataSourceTransactionManager

 

<bean id="dataSource"

class="org.apache.commons.dbcp.BasicDataSource"

destroy-method="close">

<property name="driverClassName"

value="com.mysql.jdbc.Driver">

</property>

<property name="url" value="jdbc:mysql://localhost/tech_data"></property>

<property name="username" value="root"></property>

<property name="password" value="root"></property>

</bean>

<bean id="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/> 

</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

基础的数据服务层片段:

 

 

public abstract class AbstractServiceBase {

private DataSource ds ;

//此处一定要注意,采用本地线程变量来保存当前线程使用的数据库连接;

       //不要直接使用ds.getConnection()去获得connnection;

        //否则一个请求会耗用多个连接,在高并发的情况下连接池有可能被耗尽

private static ThreadLocal<Connection> conLocal = new ThreadLocal<Connection>();

        //设置数据源,beanName = dataSource

@Resource(name="dataSource")

public void setDataSource(DataSource ds){

this.ds = ds;

}

/**

 * 获取一个默认的数据连接

 * @return

 * @throws SQLException

 */

public Connection getConnection(){

try{

                       //直接从本地线程中获取,避免重复的调用ds.getConnection();

Connection con = conLocal.get();

if(con != null)

return con;

                        // 本地线程不存在连接,则直接获取,并把该连接放到本地变量中

con = ds.getConnection();

conLocal.set(con);

return con;

}catch(Exception ex){

ex.printStackTrace();

return null;

}

}

}

 

 

 

 为什么会发生这样的事情?,那么这个跟spring的事务处理机制 有关系:

 spring事务处理基本原理,主要是通过代理类来完成,以org.springframework.jdbc.datasource.DataSourceTransactionManager.class为例用伪代码进行说明:

1.采用线程本地变量存储要进行事务控制的Connection

class  TransactionContext{
         private static ThreadLocal(List<Connection>) cons = new ThreadLocal(new ArrayList<Connection>);

       //增加一个连接

     public void addConnection(conn){
               cons.get().add(conn);
        }

    public void commint(){..}//关闭线程内的所有连接

 

    public void rollBack(){  }回滚所有连接

 

 

}

2.生成DataSource的代理类

class DataSourceProxy implements  DataSource{
          private DataSource target; //被代理的实际的数据源 DataSource

          //重写getConnection()方法

         //每次调用getConnection()都会把该connection放进ThreadLocal中

        Connection   getConnection(){
             Connect conn =  target.getConnection();

             TransactionContext.addConnection(conn);

            return conn;
        }
}

 

3.对具体的服务类访问使用代理类进行访问

calss ServiceProxy implemens service{
        private service target;

       private Object handleer(Invocation context){
               try{
                      Method.invoke(target , params[]);

                     //反射调用具体的类方法,该方法会调用dataSourceProxy.getConnection()

                   TransactionContext.commit();//统一提交本地线程中的数据库连接
               }catch(Exception ex){
                    TransactionContext.rollback();//统一进行回滚
               }

       }
}

所以,使用spring 事务管理,必须自己去处理数据连接的唯一性。

原创文章,转载请注明出处,个人原创文章:http://www.chlusoft.com/tech/349.jhtml

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值