spring事物(2)-----手写spring注解事务&&事务传播行为

一,spring事务的注解

1.1,spring自带的@Transactional例子

package com.qingruihappy1.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void add(String name, Integer age) {
        String sql = "INSERT INTO t_users(NAME, age) VALUES(?,?);";
        int updateResult = jdbcTemplate.update(sql, name, age);
        System.out.println("updateResult:" + updateResult);
    }

}
package com.qingruihappy1.service;

//user 服务层
public interface UserService {

    public void add();

}
package com.qingruihappy1.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.qingruihappy1.dao.UserDao;
import com.qingruihappy1.service.UserService;



//user 服务层
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

     //声明:@Transactional 或者XML方式
     //方法执行开始执行前,开启提交事务
     @Transactional
     public void add() {
     userDao.add("test001", 20);
     int i = 1 / 0;
     System.out.println("################" + i);
     userDao.add("test002", 21);
     
         //注意下面的代码是不会回滚的,因为异常给吃掉了,所以是不会回滚的。
     //因为回滚的机制在异常中的,现在吃掉异常之后就不会进入异常的方法中,所以自然而然的不会回滚的。
/*     try {
        userDao.add("test001", 20);
         int i = 1 / 0;
         System.out.println("################" + i);
         userDao.add("test002", 21);
    } catch (Exception e) {
        e.printStackTrace();
    }*/
    
     }
    // 方法执行完毕之后,才会提交事务



}
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
          http://www.springframework.org/schema/tx/spring-tx.xsd">
    <context:component-scan
        base-package="com"></context:component-scan>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 开启事物注解 -->
    <!-- 1. 数据源对象: C3P0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>


    <!-- 2. JdbcTemplate工具类实例 -->
    <bean id="jdbcTemplate"
        class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 3.配置事务 -->
    <bean id="dataSourceTransactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 开启注解事务 注意自定义注解的时候把它注释掉,用spring自带的话则加上 -->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
</beans>

测试:

package com.qingruihappy1.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.qingruihappy1.service.UserService;


public class Test001 {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
        userService.add();
    }

}
扫描二维码关注公众号,回复: 4152933 查看本文章

1.2,自定义注解案例

package com.qingruihappy2.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Target(value = ElementType.METHOD) 设置注解权限<br>
 * @author qingruihappy
 *
 */
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
// @interface 定义注解
public @interface AddAnnotation {

    // 手写Spring事务注解
    int userId() default 0;

    String userName() default "默认名称";

    String[]arrays();
}
package com.qingruihappy2.annotation;

import java.lang.reflect.Method;

public class User {

    @AddAnnotation(userName = "张三", userId = 18, arrays = { "1" })
    public void add() {

    }

    public void del() {

    }

    public static void main(String[] args) throws ClassNotFoundException {
        // 怎么样获取到方法上注解信息 反射机制
        Class<?> forName = Class.forName("com.qingruihappy2.annotation.User");
        // 获取到当前类(不包含继承)所有的方法
        Method[] declaredMethods = forName.getDeclaredMethods();
        for (Method method : declaredMethods) {
            // 获取该方法上是否存在注解
            System.out.println("####方法名称" + method.getName());
            AddAnnotation addAnnotation = method.getAnnotation(AddAnnotation.class);
            if (addAnnotation == null) {
                // 该方法上没有注解
                System.out.println("该方法上没有加注解..");
                continue;
            }
            // 在该方法上查找到该注解
            System.out.println("userId:" + addAnnotation.userId());
            System.out.println("userName:" + addAnnotation.userName());
            System.out.println("arrays:" + addAnnotation.arrays());
            System.out.println();
        }
    }

}
####方法名称add
userId:18
userName:张三
arrays:[Ljava.lang.String;@18760838

####方法名称main
该方法上没有加注解..
####方法名称del
该方法上没有加注解..

1.3,手写spring注解事务

步骤

package com.qingruihappy3.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoa {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void add(String name, Integer age) {
        String sql = "INSERT INTO t_users(NAME, age) VALUES(?,?);";
        int updateResult = jdbcTemplate.update(sql, name, age);
        System.out.println("updateResult:" + updateResult);
    }

}
package com.qingruihappy3.service;

//user 服务层
public interface UserService {

    public void add();

    public void del();
}
package com.qingruihappy3.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.qingruihappy3.annotation.ExtTransaction;
import com.qingruihappy3.dao.UserDaoa;
import com.qingruihappy3.service.UserService;

//user 服务层
@Service
public class UserServiceImpla implements UserService {
    @Autowired
    private UserDaoa userDao;

    /*
     * 声明:@Transactional 或者XML方式 方法执行开始执行前,开启提交事务
     */
    @ExtTransaction
    public void add() {
        userDao.add("test001", 20);
         int i = 1 / 0;
         System.out.println("################" + i);
        userDao.add("test002", 21);
        // 获取当前事务,手动进行回滚
    }

    // 方法执行完毕之后,才会提交事务
    public void del() {
        System.out.println("del");
    }

}

注解:

package com.qingruihappy3.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 事务注解 设置传播行为
@Target({ ElementType.METHOD })//只在方法上起作用
@Retention(RetentionPolicy.RUNTIME)//运行时的注解
public @interface ExtTransaction {

}

 工具类

package com.qingruihappy3.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

// 编程事务(需要手动begin 手动回滚 手都提交)
@Component
@Scope("prototype") // 每个事务都是新的实例 目的解决线程安全问题 多例子 prototype就是多例的。
public class TransactionUtils {

    // 全局接受事务状态 TransactionStatus声明为全局的原因就是让每个事务都创建一个实例,防止出现线程安全的问题
    private TransactionStatus transactionStatus;
    // 获取事务源
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    // 开启事务
    public TransactionStatus begin() {
        System.out.println("开启事务");
        transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
        return transactionStatus;
    }

    // 提交事务
    public void commit(TransactionStatus transaction) {
        System.out.println("提交事务");
        dataSourceTransactionManager.commit(transaction);
    }

    // 回滚事务
    public void rollback() {
        System.out.println("回滚事务...");
        dataSourceTransactionManager.rollback(transactionStatus);
    }

}

切面类:

package com.qingruihappy3.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import com.qingruihappy3.annotation.ExtTransaction;
import com.qingruihappy3.transaction.TransactionUtils;



//  自定义事务注解具体实现
@Aspect
@Component
public class AopExtTransaction {
    // 一个事务实例子 针对一个事务
    @Autowired
    private TransactionUtils transactionUtils;

    // 使用异常通知进行 回滚事务
    @AfterThrowing("execution(* com.qingruihappy3.service.*.*.*(..))")
    public void afterThrowing() {
        // 获取当前事务进行回滚
        // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        transactionUtils.rollback();
    }

    // 环绕通知 在方法之前和之后处理事情
    @Around("execution(* com.qingruihappy3.service.*.*.*(..))")
    public void around(ProceedingJoinPoint pjp) throws Throwable {

        // 1.获取该方法上是否加上注解
        ExtTransaction extTransaction = getMethodExtTransaction(pjp);
        TransactionStatus transactionStatus = begin(extTransaction);
        // 2.调用目标代理对象方法
        pjp.proceed();
        // 3.判断该方法上是否就上注解
        commit(transactionStatus);
    }

    private TransactionStatus begin(ExtTransaction extTransaction) {
        if (extTransaction == null) {
            return null;
        }
        // 2.如果存在事务注解,开启事务
        return transactionUtils.begin();
    }

    private void commit(TransactionStatus transactionStatus) {
        if (transactionStatus != null) {
            // 5.如果存在注解,提交事务
            transactionUtils.commit(transactionStatus);
        }

    }

    // 获取方法上是否存在事务注解
    private ExtTransaction getMethodExtTransaction(ProceedingJoinPoint pjp)
            throws NoSuchMethodException, SecurityException {
        String methodName = pjp.getSignature().getName();
        // 获取目标对象
        Class<?> classTarget = pjp.getTarget().getClass();
        // 获取目标对象类型
        Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
        // 获取目标对象方法
        Method objMethod = classTarget.getMethod(methodName, par);
        ExtTransaction extTransaction = objMethod.getAnnotation(ExtTransaction.class);
        return extTransaction;
    }

}
package com.qingruihappy3;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.qingruihappy3.service.UserService;


public class Test001 {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) applicationContext.getBean("userServiceImpla");
        userService.add();
    }

}

二:事务的传播行为

我们通过一张图引入

 这个怎么实现呢?

我们来看这7中传播行为

Propagation(key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要的部份是传播行为。)有以下选项可供使用:

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。 

PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。 

PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 

PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

我们通过代码来看:

package com.qingruihappy4.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class LogDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void add(String name) {
        String sql = "INSERT INTO t_log(log_name) VALUES(?);";
        int updateResult = jdbcTemplate.update(sql, name);
        System.out.println("##LogDao##updateResult:" + updateResult);
    }

}
package com.qingruihappy4.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoc {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void add(String name, Integer age) {
        String sql = "INSERT INTO t_users(NAME, age) VALUES(?,?);";
        int updateResult = jdbcTemplate.update(sql, name, age);
        System.out.println("updateResult:" + updateResult);
    }

}
package com.qingruihappy4.service;

public interface LogService {

    public void addLog();

}
package com.qingruihappy4.service;

//user 服务层
public interface UserService {

    public void add();

    public void del();
}
package com.qingruihappy4.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.qingruihappy4.dao.LogDao;
import com.qingruihappy4.service.LogService;



@Service
public class LogServiceImpl implements LogService {
    @Autowired
    private LogDao logDao;

    @Transactional(propagation = Propagation.REQUIRES_NEW)关键就是这一行代码
    public void addLog() {
        logDao.add("addLog" + System.currentTimeMillis());
    }

}
package com.qingruihappy4.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.qingruihappy4.dao.UserDaoc;
import com.qingruihappy4.service.LogService;
import com.qingruihappy4.service.UserService;



//user 服务层
@Service
public class UserServiceImplc implements UserService {
    @Autowired
    private UserDaoc userDao;
    @Autowired
    private LogService logService;
    
    @Transactional
    public void add() {
        // 调用接口的时候 接口失败 需要回滚,但是日志记录不需要回滚。
        logService.addLog(); // 后面程序发生错误,不能影响到我的回滚### 正常当addLog方法执行完毕,就应该提交事务
        userDao.add("test001", 20);
        int i = 1 / 0;
        System.out.println("################");
        userDao.add("test002", 21);

    }
    // 方法执行完毕之后,才会提交事务

    public void del() {
        System.out.println("del");
    }

}
package com.qingruihappy4;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.qingruihappy4.service.UserService;


public class Test001 {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = (UserService) applicationContext.getBean("userServiceImplc");
        userService.add();
    }

}

 关键就是上面标红的代码。定义一个两套事务互不影响的。

猜你喜欢

转载自www.cnblogs.com/qingruihappy/p/9986834.html
今日推荐