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来操作,这样提交就一起提交,失败就一起回滚。