zoukankan      html  css  js  c++  java
  • 自己实现一个简单的数据库事务

    原理:通过Spring提供的BeanPostProcessor来对使用了事务注解的类进行动态代理,通过spring提供的获取数据库连接工具类DataSourceUtils来获取连接。

    只有两个类 MyTransactional 和 TransactionBeanPostProcessor,MyTransactional 为自定义的事务方法注解,TransactionBeanPostProcessor生成动态代理。

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface MyTransactional {
    
    }
    @Component
    public class TransactionBeanPostProcessor implements BeanPostProcessor{
        
        
        private static final Logger logger = LoggerFactory.getLogger(TransactionBeanPostProcessor.class);
        
        @Autowired
        private DataSource datasource;
        
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (!getNeedTransactionMethods(bean).isEmpty()) {
                //jdk原生动态代理只支持实现接口的类做代理.
                bean = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), 
                        bean.getClass().getInterfaces(), new TransactionInvocationHandler(bean));
                logger.info("generate transaction proxy for "+bean.getClass());
            }
            return bean;
        }
        
        private static List<Method> getNeedTransactionMethods(Object bean) {
            Method[] methods = bean.getClass().getMethods();
            List<Method> transactionMethods = new ArrayList<>();
            for(Method method : methods) {
                if (method.isAnnotationPresent(MyTransactional.class)) {
                    transactionMethods.add(method);
                }
            }
            return transactionMethods;
        }
        
        
        /**
         * 使用动态代理来植入数据库事务逻辑
         * Created by 01385234 on 2019年10月23日.
         */
        public class TransactionInvocationHandler implements InvocationHandler{
            
            private Object proxyObject;
            
            
            public TransactionInvocationHandler(Object proxyObject) {
                super();
                this.proxyObject = proxyObject;
            }
    
    
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Method objMethod = proxyObject.getClass().getMethod(method.getName(), method.getParameterTypes());
                if (objMethod.isAnnotationPresent(MyTransactional.class)) {
                    TransactionSynchronizationManager.initSynchronization();
                    //统一用spring提供的工具类DataSourceUtils来获取数据库连接,该connection放入threadlocal中,
                    //mybatis中使用的connection也从该threadlocal中取,从而保证了同一个事务中使用同一个connection。
                    Connection connection = DataSourceUtils.doGetConnection(datasource);
                    connection.setAutoCommit(false);
                    try {
                        method.invoke(proxyObject, args);
                        connection.commit();
                    }catch(Exception e) {
                        logger.error("事务方法:{},args:{}出现异常,方法回滚",method,args);
                        connection.rollback();
                        throw e;
                    }
                }
                
                return method.invoke(proxyObject, args);
            }
            
        }
    }
  • 相关阅读:
    我的openwrt学习笔记(四):OpenWrt源码下载
    算法系列之“汉若塔”
    尖峰在线Oracle OCM实战 --开创国内Dtrace先河!
    Android开发屏幕适配知识点
    【cocos2d-js官方文档】十九、Cocos2d-JS单文件引擎使用指引
    PHP重载
    作为一个在城市打拼的人。
    关于马云最帅的照片是哪一张?!你们感受下!哈哈哈哈!(10P)
    Banana PI (香蕉派) 安装 ubuntu-core-14 最小核心的操作步骤
    (转载)偏序集的Dilworth定理学习
  • 原文地址:https://www.cnblogs.com/swave/p/11732680.html
Copyright © 2011-2022 走看看