jdbc事务控制


一、简介:

前面一遍提到了jdbc事务相关的概念。从中了解到事务应具有ACID特性。所以对于javaweb开发来说,某一个service层的方法,应该是一个事务,应该是具有原子性的。特别是当一个service方法中需要调用多次dao层的方法。应该必须要保证,这些多次调用的dao方法必须是要不全部执行成功。要不全部执行失败。比如说银行业务的service方法的转账方法,需要通过dao调用对源转账户信息进行更新减少指定金额,然后调用dao对目标账户信息进行更新增加指定金额。

那么如下保证在跨dao层调用时,必须事务的acid特性呢?


二、解决方法思路:

保证事务的ACID特性,默认情况下对用jdbc对数据库进行操作事务都是自动的commit状态的。必须必须要将事务提交改成手动提交。由程序来控制什么一起向数据库提交。一般来说mysqlsql serveroracle默认的隔离级别是repeatable read级别。可以避免脏读与不可重复读。所以需要重点控制的是事务的提交与回滚。

那么一个service方法跨多个dao方法调用,如何保证是一个事务呢?首先要保证是同一连接Connection才有可能保证是同一事务。接着需要关注的是如何在多个dao层中获取是同一Connection。让整个应用只有个Connection虽然可以解决同一Connection,但是应用就变成了单线程了。肯定不可以。那么多线程情况下,如何保证同一线程内获取的Connection都是同一对象呢?ThreadLocal类来帮忙,它可以提供线程局部变量。放入到此ThreadLocal中的对象,在同一线程都保证都到的对象都是一致的。

解决方法:只需要编写一个TransactionUtils类,此类有一个private staticThreadLocal tl对象。并且静态的getConnction方法体中,先判断tl对象中是否存在Connection对象,存在直接返回tl中的Connection。不存在则先用数据源获取个Connection对象然后放入到tl中,再返回Connection对象。此外TransactionUtils类还需要提供openTransaction方法、Commit方法、rollback方法,openTransactioncommitrollback需要的Connection对象都直接找本类的getConnection方法。

接着后面service层,先调用TransactionUtils类的openTransaction方法,再对所有的dao层调用方法都try ... Catch...finally下。Catch中调用TransactionUtils类的rollback方法。finally里中调用 TransactionUtils类的commit方法。

dao层获取的Connection都直接找TransactionUtils类的getConnection方法,来确认得到的都是同一Connection对象。

三、示例代码如下:

public class TransactionUtil {
	private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
	private static DataSource ds;

	static {
		try {
			InputStream in = DbcpUtil.class.getClassLoader()
					.getResourceAsStream("dbcpconfig.properties");
			Properties props = new Properties();
			props.load(in);
			ds = BasicDataSourceFactory.createDataSource(props);
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	public static DataSource getDataSource() {
		return ds;
	}

	public static Connection getConnection() {
		Connection conn = tl.get(); // 从ThreadLoacl中获取,如果没有再从DataSource中获取
		if (conn == null) {
			try {
				conn = ds.getConnection();
				tl.set(conn); // 存到ThreadLoacl中
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return conn;
	}

	public static void startTransaction() {
		try {
			Connection conn = tl.get();
			if(conn == null) {		//如果ThreadLoacl中没有,就从DataSource中获取
				conn = ds.getConnection();
				tl.set(conn);		//存入
			}
			conn.setAutoCommit(false);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	public static void rollback() { //回滚事务,在service层try下dao层,在catch处调用rollbakc方法
		try {
			Connection conn = tl.get();
			if(conn != null) 
				conn.rollback(); 
		} catch(Exception e) {
			e.printStackTrace();
		}
 	}

	public static void commit() {        //在finally里调用提交commint方法
		try {
			Connection conn = tl.get();
			if(conn != null) 
				conn.commit();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void release() {
		try {
			Connection conn = tl.get();
			if(conn != null) {
				conn.close();
				tl.remove();
			}
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值