事務的注解實現


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;
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM