参考文章:
package csdn;
import java.io.PrintWriter;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
import javax.sql.DataSource;
/**
* 手写事务管理器
*/
public class TranscationalManager {
/**
* 开启事务
*/
final static ThreadLocal<Boolean> transcational = new ThreadLocal<Boolean>();
/**
* 数据库连接
*/
final static ThreadLocal<Connection> currentConnection = new ThreadLocal<Connection>();
static DataSource dataSource=new DataSource() {
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Connection getConnection() throws SQLException {
Connection conn = null;
String driverClass = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password = "denglintao";
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
conn = DriverManager.getConnection(url, user, password);
return conn;
}
};
static class ConnectionProxy implements InvocationHandler {
Connection targetConn;
public Connection proxyConnection(Connection targetConn) {
this.targetConn = targetConn;
Connection proxyConn = (Connection) Proxy.newProxyInstance(targetConn.getClass().getClassLoader(),
new Class[] { Connection.class }, this);
return proxyConn;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("close")) {
// 清除当前的数据库连接
if (isOpenTranscational()) {
// 若开启事务的 连接将不做操作
return null;
}
targetConn.setAutoCommit(true);
targetConn.close();
return null;
}
Object result = method.invoke(targetConn, args);
return result;
}
public Connection getTargetConn() {
return targetConn;
}
}
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
String value() default "";
}
static class TranscationalInvocationHandler implements InvocationHandler {
public static Object proxyTranscational(Object service) throws InstantiationException, IllegalAccessException {
// 此处若有 @Transactional 代理
Class<? extends Object> clazz = service.getClass();
Class<?>[] interfaces = clazz.getInterfaces();
boolean isProxy = false;
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Transactional.class)) {
isProxy = true;
break;
}
}
if (isProxy) {
return Proxy.newProxyInstance(clazz.getClassLoader(), interfaces,
new TranscationalInvocationHandler(service));
} else {
return service;
}
}
Object traget;
public TranscationalInvocationHandler(Object bean) {
this.traget = bean;
}
public Object getTraget() {
return traget;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = null;
Method declaredMethod = traget.getClass().getDeclaredMethod(method.getName(), method.getParameterTypes());
// 不需要事务
if (!declaredMethod.isAnnotationPresent(Transactional.class)) {
try {
return method.invoke(traget, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} finally {
// 原本不存在事务时候 才释放资源
if (!TranscationalManager.isOpenTranscational()) {
TranscationalManager.closeConnection();// 防止开发者在dao层面拿取数据库连接 没有关闭导致连接泄漏
TranscationalManager.release();
}
}
}
// 如果原本存在事务,那么加入事务
if (TranscationalManager.isOpenTranscational()) {
try {
// 数据库连接处理
return invoke = method.invoke(traget, args);
} catch (InvocationTargetException e) {
TranscationalManager.rollback();
throw e.getTargetException();
}
}
// 需要开启事务
try {
// 有事务注解的开启事务
TranscationalManager.openTranscational();
// 数据库连接处理
invoke = method.invoke(traget, args);
TranscationalManager.commit();
} catch (InvocationTargetException e) {
TranscationalManager.rollback();
throw e.getTargetException();
} finally {
// 关闭连接 释放资源
TranscationalManager.closeConnection();
TranscationalManager.release();
}
return invoke;
}
}
/**
* 代理service层的事务控制
*/
@SuppressWarnings("unchecked")
public static <T> T proxyTranscationalService(T serviceBean) {
try {
return (T) TranscationalInvocationHandler.proxyTranscational(serviceBean);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 测试接口类
* @Description:</p>
* @author 邓霖涛
* @date 2020年12月23日
*/
public interface UserService{
void modifyUsers() throws Exception;
}
public static class UserServiceImpl implements UserService{
/**
* 加上事务注解
*/
@Transactional
@Override
public void modifyUsers() throws Exception {
//操作1与操作2 同属于一个事务,
//模拟dao操作1
Connection conn = TranscationalManager.getConnection();
PreparedStatement pst = conn.prepareStatement(" insert into user(user_name,password) values('姓名1','123' ) ");
pst.executeUpdate();
pst.close();
conn.close();
if(true) {
// throw new RuntimeException("强制异常,让后面的执行不了,会发现前者并没有插入到数据库库中");
}
//模拟dao操作2
Connection conn1 = getConnection();
PreparedStatement pst1 = conn1.prepareStatement(" insert into user(user_name,password) values('姓名2','123' ) ");
pst1.executeUpdate();
pst1.close();
conn1.close();
if(true) {
throw new RuntimeException("强制异常,让后面的执行不了,会发现前者并没有插入到数据库库中");
}
}
}
/**
* 主函数测试
*/
public static void main(String[] args) {
//原本的service层的
UserService userService = new UserServiceImpl();
//事务管理代理
userService = proxyTranscationalService(userService);
try {
//执行更新
userService.modifyUsers();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接
*/
public static Connection getConnection() throws SQLException {
if (currentConnection.get() != null) {
return currentConnection.get();
}
Connection conn = dataSource.getConnection();
ConnectionProxy connectionProxy = new ConnectionProxy();
Connection proxyConnection = connectionProxy.proxyConnection(conn);
currentConnection.set(proxyConnection);
if(TranscationalManager.isOpenTranscational()){
conn.setAutoCommit(false);
}else{
conn.setAutoCommit(true);
}
return proxyConnection;
}
/**
* 事务开启
*/
static void openTranscational() {
transcational.set(true);
}
/**
* 是否开启事务 true开启/false未开启
*/
static boolean isOpenTranscational() {
boolean result = false;
if (transcational.get() == null) {
result = false;
} else {
result = transcational.get();
}
return result;
}
/**
* 事务关闭
*/
static void closeTranscational() {
transcational.set(false);
}
/**
* 事务提交
*/
static void commit() throws SQLException {
Connection conn = currentConnection.get();
if (conn != null) {
conn.commit();
}
}
/**
* 回滚
*/
static void rollback() throws SQLException {
Connection conn = currentConnection.get();
if (conn != null) {
conn.rollback();
}
}
/**
* 关闭连接,需要先关闭事务在调用此方法
*/
static void closeConnection() throws SQLException {
closeTranscational();
Connection conn = currentConnection.get();
if (conn != null) {
conn.close();
}
}
/**
* 释放资源
*/
static void release() {
transcational.remove();
currentConnection.remove();
}
}