什么是事务:

  • 要么都执行 要么都不执行

  • 中途出现问题就全部回滚到开始执行的阶段

  • 事务可以保证一致性和准确性

之前学的事务是try catch的那种

try {
      userMapper.insertUser(user);
    } catch (Exception e) {
      transactionManager.rollback(txStatus);
      throw e;
    }
transactionManager.commit(txStatus);

这一种属于 编程式事务管理

这种事务需要修改源码 这样就违反了OOP原则

而spring有一种 声明式事务管理

利用AOP织入到模块中,这样即不会违反OOP也可以实现事务

测试环境

Spring + Mybatis

UserMapper:

package cn.mianju.mapper;
​
import cn.mianju.pojo.User;
​
import java.util.List;
​
public interface UserMapper {
    List<User> query();
    
    void insert(User user);
}

UserMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.mianju.mapper.UserMapper">
    <select id="query" resultType="cn.mianju.pojo.User">
        select * from user
    </select>
    <insert id="insert" parameterType="cn.mianju.pojo.User">
        insert into user values (#{name},#{age})
    </insert>
</mapper>

UserMapperImpl:

package cn.mianju.mapper;
​
import cn.mianju.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
​
import java.util.List;
​
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
    @Override
    public List<User> query() {
        System.out.println("查询方法中");
        return getSqlSession().getMapper(UserMapper.class).query();
    }
​
    @Override
    public void insert(User user) {
        System.out.println("insert");
        getSqlSession().getMapper(UserMapper.class).insert(new User("aa",2));
        
        //这块的抛异常是来测试事务
        if (user.getAge()>0){
            throw new NullPointerException();
        }
        getSqlSession().getMapper(UserMapper.class).insert(user);
    }
}
  • 首先插入一个对象

  • 然后再抛异常

  • 再插入传入的对象

如果事务生效 那么new User("aa",2) 这个对象是插入不了的

反之则会插入

声明式事务的添加

导包

需要添加声明式事务就要在

applicationContext.xml 文件中配置 因为是AOP织入 所以需要导入对应的包

 <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.17</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.17</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.7</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
​
        <!--千万不能拉下-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.8</version>
        </dependency>
    </dependencies>
​
<!--maven导出问题-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources/</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

applicationContext.xml 头部依赖

导包以后在applicationContext.xml文件中修改头部信息,添加依赖:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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/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">
    
</beans>

xmlns:tx依赖就是事务的依赖

配置Mybatis在Spring中的bean

然后配置:

DataSource:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://192.168.117.100:3306/mybatis?useSSL=false"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</bean>

SqlSessionFactory:

<bean id="sqlSeesionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="mybatis-config.xml"/>
</bean>

UserMapper:

<bean id="userMapper" class="cn.mianju.mapper.UserMapperImpl">
    <property name="sqlSessionFactory" ref="sqlSeesionFactory"/>
</bean>

配置声明式事务的Bean

transactionManager:

<!--    配置声明式事务 固定写法-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--        <constructor-arg ref="dataSource" />-->
        <property name="dataSource" ref="dataSource"/>
</bean>

可以通过构造方法来注入dataSource 也可以通过set 方法来注入

txAdvice:

<!--    tx通知 也就是对怎么样的 、哪一种方法添加事务-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
<!--            对含有add名字的方法添加事务-->
<!--            <tx:method name="add"/>-->
​
<!--            对所有方法添加事务-->
            <tx:method name="*"/>
            
        </tx:attributes>
    </tx:advice>

将什么模块添加到事务中去 在这里来声明

AOP织入:

<!--    利用aop将事务的通知织入进代码-->
<aop:config>
    <!--        切入点-->
    <aop:pointcut id="txPointcut" expression="execution(* cn.mianju.mapper.*.*(..))"/>
    <!--        aop 通知 :织入的是什么-->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

测试

import cn.mianju.mapper.UserMapper;
import cn.mianju.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
​
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
//        System.out.println(userMapper.query());
        userMapper.insert(new User("bb",2));
​
    }
}

如果没有添加事务 我们抛出了一个空指针异常 它会执行

getSqlSession().getMapper(UserMapper.class).insert(new User("aa",2));

这个方法 但是因为异常中断了就不会执行最后的

getSqlSession().getMapper(UserMapper.class).insert(user);

也就是数据库中添加了 name="aa",age=2 的但是没有添加 name="bb",age=2 的数据

但是添加了事务后 抛出了异常

我们会看见两个数据都没有加入进去

如果我们不抛出异常 那么两个数据都加入了数据库中

也就达成了我们事务的 要么都执行 要么都不执行

而且可以看到 我们在添加声明式事务的时候 全程操作的是applicationContext.xml 文件

并没有修改源代码 所以也符合我们的OOP原则

文章作者: 面具
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 MianJu —— 这只是一个 Title 而已~
spring java spring java
喜欢就支持一下吧