Spring(六)声明式事务

在数据访问层,我们经常会使用到事务操作,事务操作都是开启事务,commit和rollback,AOP的本质就是将重复的代码从业务逻辑层独立出来,从而降低代码之间的耦合度。

Spring的确实现了一套事务处理(基于AOP)。

既然涉及到了事务,那么肯定就需要MyBatis,而Spring又是一个容器,所以可以将MyBatis中的核心对象交给Spring来管理。

事务的方式有两种:

  • 编码式事务:纯手动、使用事务模板;
  • 声明式事务:本篇文章所介绍的。

若想了解编码式事务中的纯手动事务和事务模板,就可以不必往下看了,本篇文章没有涉及。

1.注解配置

jar包

既需要Spring的,也需要MyBatis和JDBC的。

与事务相关的需要spring-tx和aspectjweaver。

<dependencies>
    
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
      <groupid>junit</groupid>
      <artifactid>junit</artifactid>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
      <groupid>org.springframework</groupid>
      <artifactid>spring-aop</artifactid>
      <version>5.3.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupid>org.springframework</groupid>
      <artifactid>spring-context</artifactid>
      <version>5.3.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
    <dependency>
      <groupid>javax.annotation</groupid>
      <artifactid>javax.annotation-api</artifactid>
      <version>1.3.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
    <dependency>
      <groupid>org.springframework</groupid>
      <artifactid>spring-aspects</artifactid>
      <version>5.3.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
    <dependency>
      <groupid>org.springframework</groupid>
      <artifactid>spring-test</artifactid>
      <version>5.3.3</version>
      <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
      <groupid>org.mybatis</groupid>
      <artifactid>mybatis</artifactid>
      <version>3.5.3</version>
    </dependency>
        
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
      <groupid>org.mybatis</groupid>
      <artifactid>mybatis-spring</artifactid>
      <version>2.0.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupid>mysql</groupid>
      <artifactid>mysql-connector-java</artifactid>
      <version>8.0.21</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
      <groupid>org.springframework</groupid>
      <artifactid>spring-jdbc</artifactid>
      <version>5.3.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
    <dependency>
      <groupid>org.springframework</groupid>
      <artifactid>spring-tx</artifactid>
      <version>5.3.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupid>org.aspectj</groupid>
      <artifactid>aspectjweaver</artifactid>
      <version>1.9.5</version>
    </dependency>

</dependencies>

配置文件

首先需要准备好数据库及表。

jdbc.properties :

driver = com.mysql.jdbc.Driver
url = jdbc:mysql:///mybatisdb?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
usr = root
password = root

applicationContext.xml :

<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!--    涉及到mybatis,需要数据源-->
    <!--    涉及到参数,需要引入属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${driver}">
        <property name="url" value="${url}">
        <property name="username" value="${usr}">
        <property name="password" value="${password}">
    </property></property></property></property></bean>

    <!--    配置SqlSessionFactory-->
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource">
    </property></bean>

    <!--    扫描mapper-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dh.mapper">
    </property></bean>

    <!--    开启扫描注解-->
        <context:component-scan base-package="com.dh.service">

    <!--    添加事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource">
    </property></bean>

     <!--    开启注解事务管理-->
    <tx:annotation-driven transaction-manager="transactionManager">

</tx:annotation-driven></context:component-scan></context:property-placeholder></beans>

ProductsMapper.xml :

<!--?xml version="1.0" encoding="UTF-8" ?-->


<mapper namespace="com.dh.mapper.ProductsMapper">

    <select id="selectById" parametertype="int" resulttype="com.dh.pojos.Products">
        select * from products where pid = #{pid};
    </select>

    <update id="updateById" parametertype="com.dh.pojos.Products">
        update products set pname = #{pname} where pid = #{pid};
    </update>
</mapper>

ProductsMapper接口 :

package com.dh.mapper;

import com.dh.pojos.Products;

public interface ProductsMapper {

    public Products selectById(int pid);
    public int updateById(Products products);
}

ProductsService :

package com.dh.service;

import com.dh.mapper.ProductsMapper;
import com.dh.pojos.Products;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ProductsService {

    @Autowired
    private ProductsMapper mapper;

    @Transactional
    public void TransactionTest(){
        Products product = mapper.selectById(1);
        product.setPname("111");
        int i = 1/0;
        mapper.updateById(product);
    }
}

测试:

import com.dh.service.ProductsService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration("classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class MyTest01 {

    @Autowired
    private ProductsService productsService;

    @Test
    public void test01(){
        productsService.TransactionTest();
    }
}

结果:发生了异常,事务回滚,没有更新成功。

总结:在配置好mybatis相关内容后,只需要在xml中配置好事务管理器,以及开启注解扫描,然后在所需要开启事务的方法上加上@Transactional注解即可。

2.xml配置

只需要将加了注释的那一行的内容换成下列内容即可,然后去掉方法上的@Transactional注解。

<!--    添加事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource">
    </property></bean>

<!--    <tx:annotation-driven transaction-manager="transactionManager"/>-->

<!--    事务通知-->                                                                         
    <tx:advice transaction-manager="transactionManager" id="interceptor">
        <!--    还可以设置事务的其它属性,如隔离级别--> 
        <tx:attributes>                                                                 
            <tx:method name="*" read-only="false">                                     
        </tx:method></tx:attributes>                                                                
    </tx:advice>                                                                        
                                                                                        
<!--    切点信息-->                                                                         
    <aop:config> 
        <!--    指定切点--> 
        <aop:pointcut id="pointCut" expression="execution(* com.dh.service.*.*(..))">
        <!--    切面信息--> 
        <aop:advisor advice-ref="interceptor" pointcut-ref="pointCut">                 
    </aop:advisor></aop:pointcut></aop:config>                                                                       

3.事务的传播行为

事务具有隔离级别和传播行为。

在mysql中已经提过了事务的隔离级别,在此处不做过多的赘述。

以下为事务支持的传播行为。

posted @ 2021-04-01 10:40  deng-hui  阅读(78)  评论(0编辑  收藏  举报