动态代理实现数据库事务 + 多线程

本文介绍了动态代理在数据库事务管理中的应用。通过自定义的Handler类实现InvocationHandler接口,确保业务操作在同一连接下进行,实现事务的提交或回滚。此外,还创建了一个简易的数据库连接池ConnectionsPool,并提供了JDBCUtils工具类,以线程ID管理连接。通过ProxyFactory工厂模式生成代理类,完成动态代理实现的事务控制。
摘要由CSDN通过智能技术生成

1. 通往ssm的桥梁


我们学习了java基础,javaweb,会使用ajax调用一些servlet的接口后。

掌握mysql,事务的相关内容。

对于掌握上面这些,我们就可以往框架方向发展了。

然而,想要彻底掌握框架!首先,就要了解什么是动态代理,动态代理实现数据库事务,多线程方式实现动态代理数据库事务!

因为,这些框架的底层原理就是多线程动态代理实现数据库事务。

简而言之,多线程动态代理实现数据库事务是通往ssm,spring boot 的桥梁。

2. 动态代理实现数据库事务


首先,我们实现数据库事务。

一般我们业务中,经常遇到要求是这一个业务要么里面的增删改全部都成功,要么全部都失败。

换句话说,就是让这些增删改都公用一个connection连接,这样成功就都commit提交,失败就都rollback回滚。


因此,一般需要数据库池,这里我们可以自己创建一个简易版的数据库池:

ConnectionsPool类:

package com.itholmes.utils;

import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;

public class ConnectionsPool {
	
	//我们使用map来操作!!实现线程id作为标识的数据库连接池。
	static Map<Long,Connection> pool = new HashMap<Long,Connection>();

	//往连接池中放入连接connection
	public static void putConnection(Connection con) {
		pool.put(Thread.currentThread().getId(), con);
	}
	
	//依据线程id,在连接池中取连接connection
	public static Connection getConnection() {
		return pool.get(Thread.currentThread().getId());
	}
	
	//将线程从数据库池中移除
	public static Connection remove(Connection con) {
		 return pool.remove(Thread.currentThread().getId());
	}
	
}

创建JDBCUtils类:

  • 在jdbcUtils类中,我们通过线程id从ConnectionsPool类中获取connection连接。
package com.itholmes.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;

public class JDBCUtils {
	
	private static String driver = null;
	private static String url = null;
	private static String username = null;
	private static String password = null;
	
	static {
		ResourceBundle bundle = ResourceBundle.getBundle("db");
		driver = bundle.getString("driver");
		url = bundle.getString("url");
		username = bundle.getString("username");
		password = bundle.getString("password");
		try {
			Class.forName(driver);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static Connection getConnection() {
		
		Connection connection = ConnectionsPool.getConnection();
		
		//如果connection不为null,说明已经有当前线程id相同的连接,直接获取返回就可以。
		if(connection != null) {
			return connection;
		}else {
			try {
				connection = DriverManager.getConnection(url,username,password);
				//创建的连接放入到数据库池中。
				ConnectionsPool.putConnection(connection);
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		return connection;
	}
	
	public static void release(Connection con,Statement pre,ResultSet rs) {
		if(con!=null) {
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(pre!=null) {
			try {
				pre.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(rs!=null) {
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
}

创建一个Handler类,让它实现InvocationHandler接口,从而实现动态代理。

  • 这样我们从JDBCUtils获取的连接,通过线程id拿到的都是同一个conneciton连接。无论是代理类还是委托人,使用的都是同一个connection连接。
package com.itholmes.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;

public class Handler implements InvocationHandler{

	Object obj;
	
	public Handler(Object obj) {
		this.obj = obj;
	}
	
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		
		//这样我们从JDBCUtils获取的连接,通过线程id拿到的都是同一个conneciton连接。
		Connection connection = JDBCUtils.getConnection();
		connection.setAutoCommit(false);
		Object rs = null;
		
		try {
			rs = method.invoke(obj, args);
			connection.commit();
		}catch (Exception e) {
			// TODO: handle exception
			connection.rollback();
		}finally {
			JDBCUtils.release(connection, null, null);
			ConnectionsPool.remove(connection);
		}
		
		return rs;
	}
	
}

我们可以通过工厂模式来生产代理类,创建爱你ProxyFactory类:

package com.itholmes.utils;

import java.lang.reflect.Proxy;


public class ProxyFactory {
	
	//工厂模式生产代理类
	public static Object getProxy(Class c) {
		
		Object o = null;
		try {
			o = c.newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Handler handler = new Handler(o);
		
		Object obj = Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), handler);
		
		return obj;
	}
	
}

这样我们就相当于完成了动态代理实现数据库的事务的效果。总结起来就是通过动态代理来实现了这个业务中所有的增删改都是通过一个connection来操作,这样提交就一起提交,失败就一起回滚。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xupengboo

你的鼓励将是我创作最大的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值