自己实现一个简单的数据库事务

原理:通过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);
        }
        
    }
}

 

posted on 2019-10-24 15:54  swave  阅读(334)  评论(0编辑  收藏  举报

导航