使用ThreadLocal与JDK动态代理 实现事务AOP管理

来源:互联网 发布:网络测速器在线测网速 编辑:程序博客网 时间:2024/05/20 05:10

数据库创建两张表进行测试

mysql> create table student(id int , name varchar(50));

mysql> create table classroom(id int , name varchar(50));


首先写从数据库获取连接的ConnectionUtil.java 

package com.zf.util;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;public final class ConnectionUtil {private final static String username = "root";private final static String password = "root";private final static String url = "jdbc:mysql:///threadlocal";private ConnectionUtil(){}static{try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {  e.printStackTrace();}}public static Connection openConnection(){Connection conn = null ;try {conn = DriverManager.getConnection(url, username, password);} catch (SQLException e) {e.printStackTrace();}return conn ;}}


然后写管理Connection的SessionManager  类似于hibernate 的 SessionFactory

package com.zf.util;import java.sql.Connection;import java.sql.SQLException;/** * 单例实现 * @author zhoufeng * */public final class SessionManager { private static ThreadLocal<Connection> session = new ThreadLocal<Connection>();private static final SessionManager sessionManager = new SessionManager() ;private SessionManager(){} ;/** * 在获取SessionManager时 ,就绑定Connection到ThreadLocal中 * @return */public static SessionManager newInstance(){try {if(session.get() == null || session.get().isClosed()){session.set(ConnectionUtil.openConnection()) ;}} catch (SQLException e) {e.printStackTrace(); }return sessionManager; }public Connection getCurrentSession(){return session.get() ;}public void beginTransaction(){try {session.get().setAutoCommit(false);} catch (SQLException e) {e.printStackTrace();}}public void rollback(){try {session.get().rollback() ;session.get().close();} catch (SQLException e) {e.printStackTrace();}}public void commit(){try {session.get().commit() ;session.get().close();} catch (SQLException e) {e.printStackTrace();}}}


然后是操作数据库两张表的Dao

package com.zf.dao;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import com.zf.util.SessionManager;public class ClassRoomDao {public boolean addClassRoom(int id , String name) throws SQLException{String sql = "insert into classroom values(? , ?)";Connection conn = SessionManager.newInstance().getCurrentSession() ;System.out.println(Thread.currentThread().getId() + " addClassRoom " + conn);PreparedStatement ps = conn.prepareStatement(sql);ps.setInt(1, id);  ps.setString(2, name);int count = ps.executeUpdate();return count > 0 ;  }}

package com.zf.dao;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import com.zf.util.SessionManager;public class StudentDao {public boolean addStudent(int id , String name) throws SQLException{String sql = "insert into student values(? , ?)";Connection conn = SessionManager.newInstance().getCurrentSession() ;System.out.println(Thread.currentThread().getId() + " addStudent " + conn);PreparedStatement ps = conn.prepareStatement(sql);ps.setInt(1, id);ps.setString(2, name);int count = ps.executeUpdate();return count > 0 ;  }}


接下来就定义Service接口 并实现

package com.zf.service;import java.sql.SQLException;public interface SCService {void addStudent(int id , String name) throws SQLException;}


package com.zf.service;import java.sql.SQLException;import com.zf.dao.ClassRoomDao;import com.zf.dao.StudentDao;import com.zf.util.SessionManager;public class SCServiceImpl implements SCService{public void addStudent(int id , String name) throws SQLException{StudentDao sd = new StudentDao() ;ClassRoomDao cr = new ClassRoomDao() ;sd.addStudent(id, name); if(id > 8)  //测试是否会回滚事务throw new RuntimeException("my exception");cr.addClassRoom(id, name);  }}

接下来的就是实现AOP事务管理的关键了。 使用JDK动态代理,为Service加入事务

package com.zf.util;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 用该类来代理Service , 为需要代理的Service加入事务  。 * 实现AOP事务管理  * @author zhoufeng * */public class ServiceFactory {public static Object proxyService(final Object obj , final Class<?>[] inf){Object proxyService = Proxy.newProxyInstance(obj.getClass().getClassLoader(), inf , new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {SessionManager sm = SessionManager.newInstance();Object result = null ;try {sm.beginTransaction() ;result = method.invoke(obj, args);sm.commit();} catch (Exception e) {sm.rollback();e.printStackTrace();}return result;}}) ;return proxyService ;}}



测试

package com.zf.test;import java.sql.SQLException;import com.zf.service.SCService;import com.zf.service.SCServiceImpl;import com.zf.util.ServiceFactory;public class Test01 {public static void main(String[] args) {final SCService ss = (SCService) ServiceFactory.proxyService(new SCServiceImpl() , new Class[]{SCService.class});/** * 用两条线程分别执行service方法 * 结果会看到同一条线程中 各个Dao中获取的Connection是相同的  * 第二条线程发生了异常,并且事务回滚了 */new Thread(new Runnable() {@Overridepublic void run() {try {ss.addStudent(8, "name8");} catch (SQLException e) {e.printStackTrace();}}}).start();new Thread(new Runnable() {@Override  public void run() {try {ss.addStudent(9, "name9");} catch (SQLException e) {e.printStackTrace();}}}).start();}}


原创粉丝点击