如何正确使用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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值