手写@Transactional注解


  

1、自定义注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtTransactional {
}

2、配置类

//使用Spring的事务要开启此注解,才可以使用@Transactional注解
@EnableTransactionManagement
//自定义事务必须开启此注解,表示开启AOP
@EnableAspectJAutoProxy
@ComponentScan("tx")
@Configuration
public class Txconfig {


    @Bean
    public DataSource dataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("a123456");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        return jdbcTemplate;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
        //Spring对Configuration会做特殊处理,给容器中加组件的方法,多次调用都只是从容器中找组件
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }

    @Bean
    public PlatformTransactionManager transactionManager() throws PropertyVetoException {
        return new DataSourceTransactionManager(dataSource());
    }
}

3、定义切面类

@Component
@Aspect
public class Aop {

    @Autowired
    TransactionUtils transactionUtils;

    @AfterThrowing("execution(* tx.UserService.*(..))")
    public void afterThrowing(){
        //将当前事务进行回滚
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }


    @Around("execution(* tx.UserService.*(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        //1、判断当前代理对象的方法时候开启了ExtTransactional注解
        ExtTransactional extTransactional = getExtTransactional(proceedingJoinPoint);
        TransactionStatus transactionStatus = null;

        //2、开启事务
        transactionStatus = begin(transactionStatus, extTransactional);

        //3、执行目标方法
        proceedingJoinPoint.proceed();

        //4、提交事务
        if (transactionStatus != null) {
            transactionUtils.commit(transactionStatus);
        }

        System.out.println("我是环绕通知-后");
    }

    /*
     * 判断方法是否开启ExtTransactional注解
     */
    public ExtTransactional getExtTransactional(ProceedingJoinPoint proceedingJoinPoint) throws NoSuchMethodException {
        //获取代理对象的方法名称
        String methodName = proceedingJoinPoint.getSignature().getName();
        //获取目标对象类型
        Class<?> classTarget = proceedingJoinPoint.getTarget().getClass();
        //获取参数类型
        Class[] parameterTypes = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterTypes();
        //获取目标对象方法
        Method method = classTarget.getMethod(methodName, parameterTypes);
        ExtTransactional declaredAnnotation = method.getDeclaredAnnotation(ExtTransactional.class);
        return declaredAnnotation;
    }

    public TransactionStatus begin(TransactionStatus transactionStatus, ExtTransactional extTransactional) {
        if (extTransactional == null) {
            return null;
        }
        return transactionUtils.begin();
    }
}

4、事务工具类

@Component
public class TransactionUtils {

    // 事物管理器
    @Autowired
    private PlatformTransactionManager dataSourceTransactionManager;

    public TransactionStatus begin() {
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
        return transactionStatus;
    }
    public void commit(TransactionStatus transaction) {
        dataSourceTransactionManager.commit(transaction);
    }
    public void rollback(TransactionStatus transaction) {
        dataSourceTransactionManager.rollback(transaction);
    }
}

5、Service层

@Component
public class UserService {
    @Autowired
    private UserDao userDao;

    @ExtTransactional
    public void add() {
        userDao.insertUser();
        int i = 1 / 0;
    }

}

6、Dao层

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void insertUser(){
        String username = UUID.randomUUID().toString().substring(5);
        String sql = "INSERT INTO user(username,age)VALUES(?,?)";
        jdbcTemplate.update(sql,username,19);
    }
}

7 测试类

public class TxTest {

    @Test
    public void test1() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Txconfig.class);
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.add();
    }
}

8 思考与问题

  在切面类中,提交与回滚均需要传入TransactionStatus变量,可否将TransactionStatus定义为成员变量作为提交和回滚方法的共享变量,如果可以,是否存在线程安全问题?
  因为在Spring的AOP中,是在实例bean创建的时候,将AOP中的切面方法织入到目标方法中的,形成执行链,并生产代理对象,最终由代理对象链式调用通知方法和目标方法实现AOP,那么在AOP中定义成员变量是否存在线程安全问题?
  请大神留言解答疑惑。。。。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值