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);
            }
            
        }
    }
  • 相关阅读:
    使用FormData,进行Ajax请求并上传文件
    oracle视图详解
    Unicode和UTF-8之间的关系
    如何访问tomcat所在服务器的其他盘符的资源。
    React首次渲染过程
    react知识点总结
    WebSocket基础
    gulp 批量添加类名 在一个任务中使用多个文件来源
    Chrome浏览器取消INPUT自动记忆下拉框
    Angular7 Drag and Drop
  • 原文地址:https://www.cnblogs.com/swave/p/11732680.html
Copyright © 2011-2022 走看看