1. 程式人生 > >使用動態代理實現事務管理

使用動態代理實現事務管理

最近在寫一個簡單的web框架,使用動態代理和ThreadLocal實現的事務管理,在這裡和大家分享一下。

關於動態代理有jdk動態代理和cglib動態代理,這裡選用了cglib。

DbHelper類提供資料庫的一些操作。

package com.me.coin.framework.dao;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

/**
 * 提供資料庫的一些操作
 * @author dwl
 *
 */
public class DbHelper {
        
        //執行緒變數
	private static ThreadLocal<Connection> localConn = new ThreadLocal<Connection>();
        //資料庫連線池
	private static DataSource dataSource = DataSourceMaker.getInstance().getDataSource();

	
	/**
	 * 獲取連線
	 * @return
	 */
	public static Connection getConnection() {
		Connection conn;
		try {
			conn = localConn.get();
			if (conn == null) {
				conn = dataSource.getConnection();
				if (conn != null) {
					localConn.set(conn);
				}
			}
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
		return conn;
	}

	
	/**
	 * 開啟事務
	 */
	public static void beginTransaction() {
		Connection conn = getConnection();
		if (conn != null) {
			try {
				conn.setAutoCommit(false);
			} catch (SQLException e) {
				throw new RuntimeException(e);
			} finally {
				localConn.set(conn);
			}
		}
	}

	/**
	 * 提交事務
	 */
	public static void commitTransaction() {
		Connection conn = getConnection();
		if (conn != null) {
			try {
				conn.commit();
				conn.close();
			} catch (SQLException e) {
				throw new RuntimeException(e);
			} finally {
				localConn.remove();
			}
		}
	}

	/**
	 * 回滾事務
	 */
	public static void rollbackTransaction() {
		Connection conn = getConnection();
		if (conn != null) {
			try {
				conn.rollback();
				conn.close();
			} catch (SQLException e) {
				throw new RuntimeException(e);
			} finally {
				localConn.remove();
			}
		}
	}

}

TransactionProxy類獲取代理後的物件

package com.me.coin.framework.tx;

import java.lang.reflect.Method;

import com.me.coin.framework.dao.DbHelper;
import com.me.coin.framework.tx.annotation.Transaction;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 事務代理
 * @author dwl
 *
 */
public class TransactionProxy {
	
	@SuppressWarnings({ "unchecked", "static-access" })
	public static <T> T getProxy(Class<T> clazz){
		return (T)new Enhancer().create(clazz, new MethodInterceptor(){
			@Override
			public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
				Object result = null;
				//沒有@Transaction不進行事務管理
				if(!method.isAnnotationPresent(Transaction.class)){
					result = proxy.invokeSuper(obj, args);
					return result;
				}
				try {
					//開啟事務
					DbHelper.beginTransaction();
					// 通過代理類呼叫父類中的方法
					result = proxy.invokeSuper(obj, args);
					//提交事務
					DbHelper.commitTransaction();
				} catch (Exception e) {
					//回滾
					DbHelper.rollbackTransaction();
				}
				return result;
			}
		});
	}

}

 在ioc初始化時獲取所有需要事務管理的service類

//service類通過動態代理生成
Object bean = TransactionProxy.getProxy(clazz);
		

在service層進行事務管理

package com.dwl.controller;

import java.util.List;

import com.dwl.entity.User;
import com.me.coin.framework.dao.Cnd;
import com.me.coin.framework.dao.Dao;
import com.me.coin.framework.ioc.annotation.Inject;
import com.me.coin.framework.tx.annotation.Service;
import com.me.coin.framework.tx.annotation.Transaction;

@Service//標識service類
public class UserServiceImpl implements UserService{
	
	@Inject//注入
	private Dao dao;

	@Override
	public List<User> getList(Cnd cnd) {
		return dao.query(User.class, cnd);
	}

	@Override
	@Transaction//事務管理,不支援事務傳播
	public long addUser(User user) {
	    return dao.insert(user);
	}

}