SSM_Spring_Day02( AOP 简介、基于 XML 的 AOP 开发、基于注解的AOP的使用、spring对于持久层及事务的支持、基于 XML 的声明式事务控制)

SSM_Spring_Day02( AOP 简介、基于 XML 的 AOP 开发、基于注解的AOP的使用、spring对于持久层及事务的支持、基于 XML 的声明式事务控制)

1. Spring 的 AOP 简介

1.1. 什么是AOP

AOPAspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

1.2. AOP 的作用及其优势

  • 作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
  • 优势:减少重复代码,提高开发效率,并且便于维护

1.3. AOP 的底层实现

实际上,AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。

1.4. AOP 的动态代理技术

常用的动态代理技术

  • JDK 代理 : 基于接口的动态代理技术
  • cglib 代理:基于父类的动态代理技术

在这里插入图片描述

1.5. JDK 的动态代理

代理接口

public interface TargetInterface {
    public void save();
}

代理目标对像

/**
 * @author Mr.Hu
 * @create 2021/04/25
 */
public class TargetImpl  implements TargetInterface {
    @Override
    public void save() {
        System.out.println("代理接口的实现类.....");
    }
}

增强类

//增强类
public class Advice {
    public  void before(){
        System.out.println("在目标方法执行之前执行。。。。。");
    }
    public  void  after(){
        System.out.println("在目标方法执行之后执行。。。。。");
    }
}

代理对象的生成

public class TagetProxyTest {
    public static void main(String[] args) {
        //代理的目标对象
        final TargetImpl target = new TargetImpl();
        final  Advice advice = new Advice();
        //生成代理对象
        TargetInterface targetInterface = (TargetInterface) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                advice.before();
                Object invoke = method.invoke(target,args);//执行目标方法
                advice.after();
                return invoke;
            }
        });
        targetInterface.save();
    }
}

1.6.CGLib的动态代理

目标对像

public class Target {
    public void save() {
        System.out.println("代理接口的实现类.....");
    }
}

增强类

//增强类
public class Advice {
    public  void before(){
        System.out.println("在目标方法执行之前执行。。。。。");
    }
    public  void  after(){
        System.out.println("在目标方法执行之后执行。。。。。");
    }
}

使用cglib去代理目标对象

/**
 * @author Mr.Hu
 * @create 2021/04/25
 */
public class CGLibpProxyTest {
    public static void main(String[] args) {
        //目标对像
        final  Target target = new Target();
        //增强类
        final  Advice advice = new Advice();
        Enhancer enhancer = new Enhancer();
        //设置代理对象的父类  父类就是目标对像自己的class
        enhancer.setSuperclass(Target.class);
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                advice.before();
               Object invoke =  method.invoke(target,args);
                advice.after();
                return invoke;
            }
        });
        //生成代理对象
       Target proxy = (Target) enhancer.create();
        proxy.save();
    }
}

1.7. AOP 相关概念

Spring 的 AOP 实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强

在正式讲解 AOP 的操作之前,我们必须理解 AOP 的相关术语,常用的术语如下:

  • Target(目标对象):代理的目标对象
  • Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
  • Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
  • Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
  • Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
  • Aspect(切面):是切入点和通知(引介)的结合
  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入

1.8.AOP 开发明确的事项

1. 需要编写的内容

  • 编写核心业务代码(目标类的目标方法)
  • 编写切面类,切面类中有通知(增强功能方法)
  • 在配置文件中,配置织入关系,即将哪些通知与哪些连接点进行结合

2. AOP 技术实现的内容

Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

3. AOP 底层使用哪种代理方式

在 spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

1.9. 知识要点

  • aop:面向切面编程
  • aop底层实现:基于JDK的动态代理 和 基于Cglib的动态代理
  • aop的重点概念:

​ Pointcut(切入点):被增强的方法

​ Advice(通知/ 增强):封装增强业务逻辑的方法

​ Aspect(切面):切点+通知

​ Weaving(织入):将切点与通知结合的过程

  • 开发明确事项:

​ 谁是切点(切点表达式配置)

​ 谁是通知(切面类中的增强方法)

​ 将切点和通知进行织入配置

2. 基于 XML 的 AOP 开发

2.1. 快速入门

①导入 AOP 相关坐标

      <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- aspectj的织入 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>

创建目标接口及其实现类

public interface TargetInterface {
    public void  save();
}
public class Target  implements TargetInterface {
    @Override
    public void save() {
        System.out.println("AOP的代理的目标对像执行.....");
    }
}

创建配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
        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/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">


</beans>

配置通知

<!--    配置切点表达式和前置增强的织入关系-->
    <aop:config>
<!--        配置切面-->
        <aop:aspect ref="advice">
            <!--        配置切入点-->
            <aop:pointcut id="mypointcut" expression="execution(* cn.lanqiao.aop.*.*(..))"/>
            <aop:before  method="before" pointcut-ref="mypointcut"/>
            <aop:after method="after" pointcut-ref="mypointcut"/>
        </aop:aspect>
    </aop:config>

2.2. XML 配置 AOP 详解

1. 切点表达式的写法

表达式语法:

execution([修饰符] 返回值类型 包名.类名.方法名(参数))

  • 访问修饰符可以省略
  • 返回值类型、包名、类名、方法名可以使用星号* 代表任意
  • 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
  • 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表

例如:

execution(public void com.ssm.aop.Target.method())  
execution(void com.ssm.aop.Target.*(..)) 
execution(* com.ssm.aop.*.*(..)) 
execution(* com.ssm.aop..*.*(..)) 
execution(* *..*.*(..))

2. 通知的类型

通知的配置语法:

<aop:通知类型 method=“切面类中方法名” pointcut=“切点表达式"></aop:通知类型>

名称标签说明
前置通知aop:before用于配置前置通知。指定增强的方法在切入点方法之前执行
后置通知aop:after-returning用于配置后置通知。指定增强的方法在切入点方法之后执行
环绕通知aop:around用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行
异常抛出通知aop:throwing用于配置异常抛出通知。指定增强的方法在出现异常时执行
最终通知aop:after用于配置最终通知。无论增强方式执行是否有异常都会执行

后置通知:

    public String update();
        @Override
    public String update() {
        System.out.println("执行方法更新..........");
        return "更新成功";
    }

增强方法

  public void afterReturn(Object res){//res来接收返回值 在增强方法中对返回值做一个处理
        System.out.println("后置通知....." + res);
    }

配置后置通知

<aop:after-returning method="afterReturn" pointcut-ref="mypointcut" returning="res"></aop:after-returning>

returning="res"参数名称必须和增强方法中的形参的名称一致

测试

在这里插入图片描述
在这里插入图片描述

环绕通知

就是在目标方法执行之前和之后 对目标方法的执行做一些相应的处理

    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("删除之前.....");//在目标方法执行之前执行的相应的处理
        Object res= point.proceed();//调用执行目标方法
        System.out.println("删除之后....");//在目标方法执行之后做相应的处理
    }
<aop:around method="around" pointcut-ref="mypointcut" />

异常通知

目标方法

   @Override
    public void query() throws IndexOutOfBoundsException {
        int[] arr = new int[2];

        System.out.println("查询成功....." + arr[2]);
    }

异常通知

  public void exct(Exception e){
        System.out.println(e);
    }

配置

 <aop:after-throwing method="exct" pointcut-ref="mypointcut" throwing="e"/>

测试

在这里插入图片描述

3.基于注解的AOP的使用

3.1.快速入门

开启spring对于注解的支持

    <context:component-scan base-package="cn.lanqiao.aop"/>

将我们所使用到的目标对象 和增强类 纳入到spring容器中

//增强类
@Component
public class Advice {
@Component
public class Target  implements TargetInterface {

在切面类中使用注解配置织入关系

@Component
@Aspect//表明这是一个切面类 通知 + 切入点
public class Advice {
    @Before("execution(* cn.lanqiao.aop.*.*(..))")//配置前置通知及其切入点表达式
    public  void before(){
        System.out.println("在目标方法执行之前执行。。。。。");
    }

开启AOP的自动代理

<!--    实现AOP的自动代理-->
    <aop:aspectj-autoproxy/>
@Component
@Aspect//表明这是一个切面类 通知 + 切入点
public class Advice {
    @Before("execution(* cn.lanqiao.aop.*.*(..))")//配置前置通知及其切入点表达式
    public  void before(){
        System.out.println("在目标方法执行之前执行。。。。。");
    }
    @After("execution(* cn.lanqiao.aop.*.*(..))")//最终通知是在方法最终执行完成之后 才会执行的通知
    public  void  after(){
        System.out.println("在目标方法执行之后执行。。。。。");
    }
    @AfterReturning(value = "execution(* cn.lanqiao.aop.*.*(..))",returning = "res")
    public void afterReturn(Object res){
        System.out.println("后置通知....." + res);
    }

抽取切入点表达式

@Component
@Aspect//表明这是一个切面类 通知 + 切入点
public class Advice {
    //抽取出来的切入点表达式 
    @Pointcut("execution(* cn.lanqiao.aop.*.*(..))")
    public  void myPoint(){

    }
    @Before("Advice.myPoint()")//配置前置通知及其切入点表达式
    public  void before(){
        System.out.println("在目标方法执行之前执行。。。。。");
    }
    @After("Advice.myPoint()")//最终通知是在方法最终执行完成之后 才会执行的通知
    public  void  after(){
        System.out.println("在目标方法执行之后执行。。。。。");
    }
    @AfterReturning(value = "Advice.myPoint()",returning = "res")
    public void afterReturn(Object res){
        System.out.println("后置通知....." + res);
    }

3.2. 知识要点

  • 注解aop开发步骤

①使用@Aspect标注切面类

②使用@通知注解标注通知方法

③在配置文件中配置aop自动代理<aop**:aspectj-autoproxy/**>

  • 通知注解类型
前置通知@Before用于配置前置通知。指定增强的方法在切入点方法之前执行
后置通知@AfterReturning用于配置后置通知。指定增强的方法在切入点方法之后执行
环绕通知@Around用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行
异常抛出通知@AfterThrowing用于配置异常抛出通知。指定增强的方法在出现异常时执行
最终通知@After用于配置最终通知。无论增强方式执行是否有异常都会执行

4.spring对于持久层及事务的支持

JdbcTemplate基本使用

4.1.JdbcTemplate基本使用-概述(了解)

JdbcTemplate是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和HibernateTemplate,操作nosql数据库的RedisTemplate,操作消息队列的JmsTemplate等等。

4.2.引入相关依赖

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.36</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>

创建数据库表
在这里插入图片描述

创建实体
在这里插入图片描述

JDBCTemplate的基本使用

   @Test
    public void templateTest(){
        //创建数据源
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/lanqiao");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        //获取连接
        //创建JDBCTemplate
        JdbcTemplate template = new JdbcTemplate(dataSource);
        String sql = "insert into account(accname,balance) values(?,?)";
        Account account = new Account("admin",10000);
        template.update(sql,account.getAccname(),account.getBalance());
    }

结合spring来管理数据源和JdbcTemplate

<!--    配置数据源-->
    <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/lanqiao"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
<!--    配置JDBCTemplate-->
    <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="datasource"/>
    </bean>

获取JdbcTemplate对象

   @Test
    public void templateTest2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
       JdbcTemplate template =  context.getBean(JdbcTemplate.class);
        String sql = "insert into account(accname,balance) values(?,?)";
        Account account = new Account("lucy",20000);
        template.update(sql,account.getAccname(),account.getBalance());
    }
<!--    将数据库的链接属性单独配置在属性文件中-->
    <context:property-placeholder location="classpath*:jdbc.properties"/>
<!--    配置数据源-->
    <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

使用JdbcTemplate完成对数据的 CRUD操作

定义dao接口

public interface AccountDao {
    void insert(Account account);
    void update(Account account);
    void delete(int id);
    Account selelctOne(int id);
    List<Account> selectAll();
}

实现接口

public class AccountDaoImpl implements  AccountDao{
    private JdbcTemplate template;

    public void setTemplate(JdbcTemplate template) {
        this.template = template;
    }

    @Override
    public void insert(Account account) {
        String sql = "insert into account(accname,balance) values(?,?)";
        template.update(sql,account.getAccname(),account.getBalance());
    }

    @Override
    public void update(Account account) {
        String sql = "update account set balance=? where id=?";
        template.update(sql,account.getBalance(),account.getId());
    }

    @Override
    public void delete(int id) {
        String sql = "delete from account where id= ?";
        template.update(sql,id);
    }

    @Override
    public Account selelctOne(int id) {
        String sql = "select * from account where id= ?";
        return  template.queryForObject(sql, new RowMapper<Account>() {
            @Override
            public Account mapRow(ResultSet resultSet, int i) throws SQLException {
                Account acc = new Account();
                acc.setId(resultSet.getInt("id"));
                acc.setAccname(resultSet.getString("accname"));
                acc.setBalance(resultSet.getInt("balance"));
                return acc;
            }
        },id);
    }

    @Override
    public List<Account> selectAll() {
        String sql = "select * from account";
        return template.query(sql, new RowMapper<Account>() {
            @Override
            public Account mapRow(ResultSet resultSet, int i) throws SQLException {
                Account acc = new Account();
                acc.setId(resultSet.getInt("id"));
                acc.setAccname(resultSet.getString("accname"));
                acc.setBalance(resultSet.getInt("balance"));
                return acc;
            }
        });
    }
}

    @Override
    public Integer count() {
        String sql = "select count(*) from account";
        return template.queryForObject(sql,Integer.class);
    }

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TemplateTest {
    @Autowired
    private AccountDao dao ;
    @Test
    public void templateTest(){
        //创建数据源
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/lanqiao");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        //获取连接
        //创建JDBCTemplate
        JdbcTemplate template = new JdbcTemplate(dataSource);
        String sql = "insert into account(accname,balance) values(?,?)";
        Account account = new Account("admin",10000);
        template.update(sql,account.getAccname(),account.getBalance());
    }
    @Test
    public void templateTest2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
       JdbcTemplate template =  context.getBean(JdbcTemplate.class);
        String sql = "insert into account(accname,balance) values(?,?)";
        Account account = new Account("lucy",20000);
        template.update(sql,account.getAccname(),account.getBalance());
    }

    @Test
    public void insertTest(){
        Account account = new Account("tom",2000);
       dao.insert(account);
    }
    @Test
    public void updatetTest(){
        Account account = new Account(3,"tom",20000);
        dao.update(account);
    }
    @Test
    public void deleteTest(){
        dao.delete(3);
    }
    @Test
    public void selectOneTest(){
         
       Account acc =  dao.selelctOne(1);
        System.out.println("acc = " + acc);
    }
    @Test
    public void selectListTest(){
        List<Account> list = dao.selectAll();
        System.out.println(list);
    }
    @Test
    public void countTest(){

        System.out.println(dao.count());
    }
}

5. 基于 XML 的声明式事务控制

5.1 什么是声明式事务控制

Spring 的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。

声明式事务处理的作用

  • 事务管理不侵入开发的组件。具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策略的话,也只需要在定义文件中重新配置即可
  • 在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便

注意:Spring 声明式事务控制底层就是AOP。

使用的步骤

1 引入spring对于支持

      <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>

2 在配置文件中 引入tx的约束

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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/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/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

事务的使用场景

转账的操作

dao

@Override
    public void updateBalance(String accname,Integer money) {
        String sql = "update account set balance=balance+? where accname=?";
        template.update(sql,money,accname);
    }

定义service

public interface AccountService {
    public  void transfer(String inMan,String outMan,Integer money);
}

public class AccountServiceImpl implements AccountService {
    private AccountDao dao;
    @Override
    public void transfer(String inMan, String outMan, Integer money) {
        // 从转账者的账户减去响应的金额
        dao.updateBalance(outMan,-money);
        // 向被转账者的账户增加响应的金额
        dao.updateBalance(inMan ,money);

    }
}

5.2. 编程式事务控制相关对象

5.2.1 PlatformTransactionManager

PlatformTransactionManager 接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法。

在这里插入图片描述

注意:

PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类,例如:Dao 层技术是jdbc 或 mybatis 时:org.springframework.jdbc.datasource.DataSourceTransactionManager

Dao 层技术是hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager

5.2.2 TransactionDefinition

TransactionDefinition 是事务的定义信息对象,里面有如下方法:
在这里插入图片描述

1. 事务隔离级别

设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读。

  • ISOLATION_DEFAULT
  • ISOLATION_READ_UNCOMMITTED
  • ISOLATION_READ_COMMITTED
  • ISOLATION_REPEATABLE_READ
  • ISOLATION_SERIALIZABLE

2. 事务传播行为

  • REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
  • MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
  • REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
  • NEVER:以非事务方式运行,如果当前存在事务,抛出异常
  • NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作
  • 超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置
  • 是否只读:建议查询时设置为只读

5.2.3 TransactionStatus

TransactionStatus 接口提供的是事务具体的运行状态,方法介绍如下。

在这里插入图片描述

事务管理的配置

<!--    配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>
<!--    配置事务的增强-->
    <tx:advice transaction-manager="transactionManager" id="transactionInterceptor">
        <tx:attributes>
<!--            name 表示事务管理的方法名称 * 表示管理所有方法-->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
<!--    aop增强 将事务管理织入到我么你的业务逻辑中-->
    <aop:config>
        <aop:pointcut id="tran" expression="execution(* cn.lanqiao.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="transactionInterceptor" pointcut-ref="tran"></aop:advisor>
    </aop:config>

其中,tx:method 代表切点方法的事务参数的配置,例如:

<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
  • name:切点方法名称
  • isolation:事务的隔离级别
  • propogation:事务的传播行为
  • timeout:超时时间
  • read-only:是否只读

基于注解的事务管理
在这里插入图片描述

在这里插入图片描述

配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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/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/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">
    <context:component-scan base-package="cn.lanqiao"/>
<!--    实现AOP的自动代理-->
    <aop:aspectj-autoproxy/>
<!--    将数据库的链接属性单独配置在属性文件中-->
    <context:property-placeholder location="classpath*:jdbc.properties"/>
<!--    开启spring对于事务的注解的支持-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
<!--    配置数据源-->
    <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
<!--    配置JDBCTemplate-->
    <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="datasource"/>
    </bean>
<!--    配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>
</beans>

Spring声明式事务管理的全注解形式

@Configuration
@ComponentScan("cn.lanqiao")
@EnableAspectJAutoProxy
@EnableTransactionManagement
@PropertySource("classpath:jdbc.properties")
public class SpringConfiguration {
    @Value("${jdbc.driverClassName}")
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Bean
    public DataSource getDatasource(){
        DruidDataSource dataSource= new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
    @Bean
    public JdbcTemplate getJdbcTemplate(){
        return  new JdbcTemplate(getDatasource());
    }
    @Bean
    public TransactionManager getTransactionManager(){
        return new DataSourceTransactionManager(getDatasource());
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})
public class TemplateTest {
    @Autowired
    private AccountService service;
@Test
    public void transferTest(){
        service.transfer("admin","lucy",1000);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值