参考文章:
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() {@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {// TODO Auto-generated method stubreturn null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {// TODO Auto-generated method stubreturn false;}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {// TODO Auto-generated method stub}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {// TODO Auto-generated method stub}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {// TODO Auto-generated method stubreturn null;}@Overridepublic int getLoginTimeout() throws SQLException {// TODO Auto-generated method stubreturn 0;}@Overridepublic PrintWriter getLogWriter() throws SQLException {// TODO Auto-generated method stubreturn null;}@Overridepublic Connection getConnection(String username, String password) throws SQLException {// TODO Auto-generated method stubreturn null;}@Overridepublic 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 blocke.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;}@Overridepublic 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@Documentedpublic @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;}@Overridepublic 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@Overridepublic void modifyUsers() throws Exception {//操作1与操作2 同属于一个事务,//模拟dao操作1Connection 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操作2Connection 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();}}
