zoukankan      html  css  js  c++  java
  • 事务的注解实现

    https://www.cnblogs.com/pickKnow/p/11138118.html

    在这一篇博客中,已经通过AOP 思想了事务的功能,通过环绕通知,以及异常通知,实现能够在指定的方法前后调用开启事务,提交事务,回滚事务的功能。

    在Spring中,已经通过注解@Transactional 实现了这一功能,具体spring.xml如下:

    <!-- 配置事务 -->
        <bean id="dataSourceTransactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
       
    <!-- 开启事务 -->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

    代码上只需在方法上加上:@Transactional

        @Transactional
        public void addUser() {
            // 添加到数据库
            System.out.println("开始添加");
            userDao.add(1, "tom", "12");
            int i = 1 / 0;
        }

    2,注解

    分类:内置注解(也成为元注解 jdk 自带注解)、自定义注解(Spring框架)
    什么是内置注解
    (1) @SuppressWarnings   再程序前面加上可以在javac编译中去除警告--阶段是SOURCE
    (2) @Deprecated   带有标记的包,方法,字段说明其过时----阶段是SOURCE
    (3)@Overricle   打上这个标记说明该方法是将父类的方法重写--阶段是SOURCE
    @Overricle 案例演示
    @Override
    public String toString() {
    return null;
    }
    @Deprecated案例演示
    new Date().parse("");

    @SuppressWarnings  案例演示
    @SuppressWarnings({ "all" })
    public void save() {
    java.util.List list = new ArrayList();
    }


    实现自定义注解
    元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
    @Target
    @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
    1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

    2.@Retention
    表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
    3.@Documented
    4.@Inherited

    实现一个注解:

    @Target({ElementType.METHOD})   //范围
    @Retention(RetentionPolicy.RUNTIME)  //运行时候   要加 反射需要用到
    @Inherited
    @Documented
    public @interface User {
        String username() default "tom";
    
        int age() default 18;
    
        String[] arrays();
    }
    public class App {
    
        @User(username = "Jim", arrays = { "basketball" }, age = 20)
        public void addUser() {
            System.out.println("Annotation");
        }
    
        public static void main(String[] args) throws ClassNotFoundException {
            // 获取到class信息
            Class<?> clazz = Class.forName("com.hella.thread.annotation.App");
            // 获取方法
            Method[] methods = clazz.getDeclaredMethods();
            // 循环遍历每个方法上@User 的注解
            for (Method method : methods) {
                User annotation = method.getDeclaredAnnotation(User.class);
                if (annotation != null) {
                    System.out.println(annotation.age());
                    System.out.println(annotation.username());
                }
            }
        }
    
    }

    3,通过自定义注解来实现@Transactional 的功能

    1,自定义注解

    @Target({ ElementType.METHOD }) // 范围
    @Retention(RetentionPolicy.RUNTIME) // 运行时候 要加 反射需要用到
    @Inherited
    @Documented
    public @interface DefTransactional {
    
    }

    2,通过AOP 在每个方法调用前通过反射区获取方法上是否有指定的自定义注解,如果有开启事务,异常回滚事务

    Component
    @Aspect // 这是一个切面类,用来监测方法的调用,调用前判断是有@DefTransactional 注解
    @Scope("prototype") // 保证事务的隔离性,让每个对象都是一个新的对象,保证线程安全
    public class AopDefTransactional {
    
        @Autowired
        private TransactionUtils transactionUtils;
    
        // 环绕通知
        @Around("execution (* com.hella.thread.aoptransaction.service.UserService.*(..) )")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            // 1 找到对应的方法,通过方法名和参数类型 因为会有重载
            TransactionStatus transactionStatus = begin(proceedingJoinPoint);
            proceedingJoinPoint.proceed();
            // 4 提交事务
            commit(transactionStatus);
        }
    
        // 异常通知
        @AfterThrowing("execution (* com.hella.thread.aoptransaction.service.UserService.addUser(..) )")
        public void afterThrowing() {
            System.out.println("####自定义注解事务回滚");
            transactionUtils.rollback();
        }
    
        private void commit(TransactionStatus transactionStatus) {
            if (transactionStatus != null) {
                // 提交事务
                System.out.println("####自定义注解事务提交");
                transactionUtils.commit(transactionStatus);
            }
        }
    
        private TransactionStatus begin(ProceedingJoinPoint proceedingJoinPoint)
                throws NoSuchMethodException, SecurityException {
            DefTransactional annotation = findMethodByProceedingJoinPoint(proceedingJoinPoint);
            if (annotation == null) {
                // 开启事务
                System.out.println("方法上没有注解");
                return null;
            }
            System.out.println("####自定义注解事务开启");
            TransactionStatus transactionStatus = transactionUtils.begin();
            return transactionStatus;
        }
    
        private DefTransactional findMethodByProceedingJoinPoint(ProceedingJoinPoint proceedingJoinPoint)
                throws NoSuchMethodException, SecurityException {
            // 获取到字节码信息
            Class<?> clazz = proceedingJoinPoint.getTarget().getClass();
            // 获取到方法名称
            String methodName = proceedingJoinPoint.getSignature().getName();
            // 获取参数
            Class<?>[] par = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterTypes();
            // 获取到正在执行的方法
            Method method = clazz.getDeclaredMethod(methodName, par);
    
            DefTransactional annotation = method.getDeclaredAnnotation(DefTransactional.class);
    
            if (annotation == null) {
                System.out.println("没有注解");
                return null;
            }
    
            return annotation;
        }
    
    }

    最后在方法上添加事务

    @DefTransactional
        public void addUser() {
            // 添加到数据库
            System.out.println("开始添加");
            userDao.add(1, "tom", "12");
            int i = 1/0;
        }
  • 相关阅读:
    实验一、DOS使用命令实验
    实验三、进程调度模拟程序
    实验四、存储管理
    实验二、作业调度模拟程序
    简单的DOS命令
    结构化方法和面向对象方法的比较
    jstree 取消选中父节点
    T4 模板代码生成
    基于Open XML 导出数据到Excel
    菜单(列存储转为行存储)
  • 原文地址:https://www.cnblogs.com/pickKnow/p/11143486.html
Copyright © 2011-2022 走看看