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);
            }
            
        }
    }
  • 相关阅读:
    UVA 10618 Tango Tango Insurrection
    UVA 10118 Free Candies
    HDU 1024 Max Sum Plus Plus
    POJ 1984 Navigation Nightmare
    CODEVS 3546 矩阵链乘法
    UVA 1625 Color Length
    UVA 1347 Tour
    UVA 437 The Tower of Babylon
    UVA 1622 Robot
    UVA127-"Accordian" Patience(模拟)
  • 原文地址:https://www.cnblogs.com/swave/p/11732680.html
Copyright © 2011-2022 走看看