spring 集成mybatis(二)-aop注解实现事务管理

概述

本文通过 aop注解,实现对事务的管理

注意: 真实项目中,spring集成mybatis,并不是这样的

本文根据 spring IoC 集成mybatis 中的工程做修改

修改pom.xml

增加依赖

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

全部依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>

    <version>5.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.1</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

实现 ServiceProxy 类

@Component
@Aspect
public class ServiceProxy {
    @Resource
    private SqlSession sqlSession;

    @Pointcut("execution(* top.malaoshi.service.*.save*(..))")
    public void ptSave(){

    }
    @Pointcut("execution(* top.malaoshi.service.*.update*(..))")
    public void ptUpdate(){

    }
    @Pointcut("execution(* top.malaoshi.service.*.delete*(..))")
    public void ptDelete(){

    }
    @Pointcut("execution(* top.malaoshi.service.*.query*(..))")
    public void ptQuery(){

    }
    //凡是query、save、update、delete开头的方法,都执行session.close()关闭连接
    @After("ptQuery() || ptSave() || ptUpdate() || ptDelete()")
    public void close(){
        System.out.println("======ServiceProxy.close()");
        sqlSession.close();
    }
    //凡是save、update、delete开头的方法,都执行事务管理
    @Around("ptSave() || ptUpdate() || ptDelete()")
    public Object tranactional(ProceedingJoinPoint pjp) throws Throwable {
        Object res=null;
        try{
            res=pjp.proceed(pjp.getArgs());
            System.out.println("======ServiceProxy.commit()");
            sqlSession.commit();
        } catch (Throwable throwable) {
            sqlSession.rollback();
            System.out.println("======ServiceProxy.rollback()");
            throw throwable;
        }

        return res;
    }
}

注意:

  1. @Around 注解先执行,所以让其处理 提交事务、回滚事务
  2. @After注解在 @Around 后面执行,且一定会执行,所以让其处理关闭连接

注意:这里容易犯错

这里不能使用 @AfterReturning 注解处理事务提交、@AfterThrowing 注解处理事务回滚,因为 @After 在这两个注解前执行,即:先关闭session,然后再 提交事务或 回滚事务,会报错

修改 ApplicationConfig 类

增加 @EnableAspectJAutoProxy 注解

测试-save 成功

主启动类如下:

public class Main {
    public static void main(String[] args) throws Exception {

        ApplicationContext ac=new AnnotationConfigApplicationContext(ApplicationConfig.class);
        IUserService srv=(IUserService)ac.getBean("userSrvImpl");

        User user=new User();
        user.setId(UUID.randomUUID().toString().replace("-",""));
        user.setUsername("李现");
        user.setPassword("123456");
        srv.save(user);
    }
}

执行结果:

======ServiceProxy.commit()
======ServiceProxy.close()

提交事务、并关闭session

测试-save报错

修改 UserSrvImpl类的 save() 方法

public int save(User user) throws Exception {
    int i= mapper.save(user);
    i=1/0;//除以0,故意报错
    return i;
}

执行结果:

======ServiceProxy.rollback()
======ServiceProxy.close()

报错后回滚事务

测试-query

修改主启动类

public class Main {
    public static void main(String[] args) throws Exception {

        ApplicationContext ac=new AnnotationConfigApplicationContext(ApplicationConfig.class);
        IUserService srv=(IUserService)ac.getBean("userSrvImpl");

        List<User> list=srv.queryByName("李%");
        for(User user:list){
            System.out.println(user.getUsername());
        }
    }
}

执行结果:

======ServiceProxy.close()
李雷
李四
李娜

执行关闭session


原文出处:/show_1IX3BNHxSy8.html