IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring基础学习之声明式事务 -> 正文阅读

[Java知识库]Spring基础学习之声明式事务

前言

小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java半年多时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师。
这个Spring基础学习系列是用来记录我学习Spring框架基础知识的全过程 (这个系列是参照B站狂神的Spring5最新教程来写的,由于是之前整理的,但当时没有发布出来,所以有些地方可能有错误,希望大家能够及时指正!)
之后我将会以一天一更的速度更新这个系列,还没有学习Spring5框架的小伙伴可以参照我的博客学习一下;当然学习过的小伙伴,也可以顺便跟我一起复习一下基础。
最后,希望能够和大家一同进步吧!加油吧!少年们!
废话不多说,让我们开始今天的学习内容吧,今天我们来到了Spring基础学习的第十三站:声明式事务

13.声明式事务

13.1 回顾事务

13.1.1 事务注意要点

  • 把一组业务当成一个业务来做:要么都成功,要么都失败!
  • 事务在项目开发中,十分的重要,涉及到数据的一致性问题,不能马虎!
  • 确保数据的完整性和一致性

13.1.2 事务ACID原则

  • 原子性要么都成功,要么都失败

  • 一致性事务提交前后的数据要保持一致,资源和状态不能改变,即最终一致性;其实还是要么都成功,要么都失败

  • 隔离性多个业务操作同一个资源,防止数据损坏,即事务之间要隔离

  • 持久性事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化的写到存储器中

13.2 声明式事务的使用

13.2.1 编写实体类、接口和接口实现类

1.编写User实体类

package com.kuang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data // 引入无参构造,get和set方法以及toString方法
@AllArgsConstructor // 引入有参构造
@NoArgsConstructor // 再次引入无参构造,防止引入有参构造时覆盖无参构造
public class User {
    
    private int id;
    private String name;
    private String pwd;
}

2.编写UserMapper接口

package com.kuang.mapper;

import com.kuang.pojo.User;
import java.util.List;

public interface UserMapper {
    
    //获取所有用户信息
    public List<User> getUsers();
    
    //增加一个用户
     public int insertUser(User user);
    
    //删除一个用户
     public int deleteUser(int id);

}

3.编写UserMapper.xml配置文件

3-1 SQL语句正确编写
<?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">
<!-- namespace等同于绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="com.kuang.mapper.UserMapper">
    
    <!-- 查询所有用户信息 -->
    <!-- 当通过包起别名后,resultType(结果类型)直接使用对应实体类名即可,不需要写全类名 -->
    <select id="getUsers" resultType="user">
        Select * from mybatis.user
    </select>
    
    <!-- 增加用户信息 -->
    <insert id="insertUser" parameterType="user">
        Insert into mybatis.user(id, name, pwd)
        values(#{id} ,#{name}, #{pwd})
    </insert>
    
    <!-- 删除用户信息 -->
    <delete id="deleteUser" parameterType="int">
        Delete from mybatis.user where id = #{id}
    </delete>
    
</mapper>
3-2 SQL语句错误编写
  • 把删除用户的SQL语句中间加个 * 号,故意让SQL语句出错
<?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">
<!-- namespace等同于绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="com.kuang.mapper.UserMapper">
    
    <!-- 查询所有用户信息 -->
    <!-- 当通过包起别名后,resultType(结果类型)直接使用对应实体类名即可,不需要写全类名 -->
    <select id="getUsers" resultType="user">
        Select * from mybatis.user
    </select>
    
    <!-- 增加用户信息 -->
    <insert id="insertUser" parameterType="user">
        Insert into mybatis.user(id, name, pwd)
        values(#{id} ,#{name}, #{pwd})
    </insert>
    
    <!--删除用户信息-->
    <delete id="deleteUser" parameterType="int">
        <!--Delete from mybatis.user where id = #{id}-->
        Delete * from mybatis.user where id = #{id}
    </delete>
    
</mapper>

4.编写UserMapperImpl2接口实现类

package com.kuang.mapper;

import com.kuang.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;

// 继承SqlSessionDaoSupport对象并且实现UserMapper接口
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    
    // 查询所有的用户信息
    public List<User> getUsers() {
        User user = new User(4,"钟兴民","zxm123456");
        // 获取sqlSession对象,获取Mapper接口对象
        UserMapper userMapper = getSqlSession().getMapper(UserMapper.class);
        userMapper.insertUser(user);
        userMapper.deleteUser(3);
        // 调用接口的getUsers方法
        return userMapper.getUsers();
    }
    
    // 增加用户信息
    public int insertUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).insertUser(user);
    }
    
    // 通过id删除用户信息
    public int deleteUser(int id) {
        return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
    }
    
}

13.2.2 编写核心配置文件

1.编写mybatis的核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- configuration:核心配置文件 -->
<configuration>
    <!-- 在spring核心配置文件中绑定mybatis的配置文件后,
         一般情况下可以选择只把设置和别名放在mybatis的配置文件中
         注意:setting要放在typeAliases标签前面使用 -->
    <!-- 设置标准日志输出 -->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!-- 使用别名:通过包起别名 -->
    <typeAliases>
        <package name="com.kuang.pojo"/>
    </typeAliases>

</configuration>

2.编写spring的dao配置文件和spring的主配置文件

2-1 编写spring-dao.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"
       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">
    
</beans>    
  • 配置DataSource数据源
<?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"
       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">
    <!-- 配置DataSource:使用Spring的数据源替换Mybatis的配置:例如C3P0 DBCP Druid等 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        
        <!-- 设置dataSource对象的属性:driverClassName-数据库驱动 url-数据库链接
              username-数据库登录名,password-数据库密码 -->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url"
                  value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        
    </bean>
</beans>
  • 注入sqlSessionFactory工厂对象
<!-- 注入sqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    
    <!-- 设置sqlSessionFactory对象属性,引用dataSource数据源 -->
    <property name="dataSource" ref="dataSource"/>
    
    <!-- 绑定Mybatis的核心配置文件 -->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    
    <!-- 在核心配置文件中注册Mapper.xml文件,并且使用resource资源路径绑定注册 -->
    <property name="mapperLocations" value="classpath*:com/kuang/mapper/*.xml"/>
    
</bean>
  • 注入sqlSessionTemplate对象
<!-- 注入SqlSessionTemplate对象:就是我们使用的sqlSessio n-->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    
    <!-- 只能使用构造器注入sqlSessionFactory:因为它没有set方法 -->
    <constructor-arg index="0" ref="sqlSessionFactory"/>
    
</bean>
2-2 编写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"
       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">

    <!-- 在主配置文件中导入spring-dao.xml配置文件 -->
    <import resource="spring-dao.xml"/>
    
    <!-- 注入userMapperImpl实现类
         方式一:将sqlSessionTemplate对象私有化 -->
    <bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
        <property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
    </bean>
    
    <!-- 注入userMapperImpl实现类
         方式二:继承sSqlSessionDaoSupport对象 -->
    <bean id="userMapper2" class="com.kuang.mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

</beans>

3.修改spring-dao.xml配置文件

3-1导入spring-tx约束
  • 在beans标签中加入以下的spring-tx约束
<!--引入spring-tx约束:-->
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
  • 加入spring-tx约束后如下
<?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>
3-2 配置声明式事务
  • 注入DataSourceTransactionManager数据源事务管理器
<!-- 配置声明式事务 -->
<!-- 注入DataSourceTransactionManager对象 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
3-3 结合AOP实现事务的织入
<!-- 结合AOP实现事务的织入 -->
<!-- 配置事务的通知:Spring帮忙做了 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--给那些方法配置事务-->
    <!--配置事务的传播特性:propagation
            在声明式事务中,要配置一个切面,其中用到了propagation类 -->
    <tx:attributes>
        
        <!-- 分别给插入、删除和修改用户的方法,配置propagation事务属性,其值为REQUIRED
             即支持当前事务,如果当前没有事务,就新建一个事务 -->
        <tx:method name="insert" propagation="REQUIRED"/>
        <tx:method name="delete" propagation="REQUIRED"/>
        <tx:method name="update" propagation="REQUIRED"/>
        
        <!-- 给查询用户方法设置只读 -->
        <tx:method name="select" read-only="true"/>
        
        <!-- 给所有方法(*指所有方法)配置propagation事务属性,值也设为REQUIRED -->
        <tx:method name="*" propagation="REQUIRED"/>
        
    </tx:attributes>
</tx:advice>

Propagation类表示对这些方法怎样使用事务,使用还是不用

Propagation类有七种事务配置属性,默认是REQUIRED

  • REQUIRED支持当前事务,如果当前没有事务,就新建一个事务,则是常见的选择
  • SUPPORTS支持当前事务,如果当前没有事务,就以非实物方式执行
  • MANDATORY支持当前事务,如果当前没有事务,就抛出异常
  • REQUIRED_NEW新建事务,如果当前存在事务,把当前事务挂起
  • NO_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
  • NEVER以非事务方式执行,如果当前存在事务,则抛出异常
  • NESTED支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务
3-4 配置业务切入
<!-- 配置业务切入 -->
<aop:config>
    <!-- 设置切入点,增强com.kuang.mapper包及其子包下的类所有类型的全部方法 -->
    <!-- 使用pointcut:设置切面通知执行的“地点”
         使用expression:定义切入点表达式,execution(* com.kuang.mapper..*.*(..))-->
    <aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper..*.*(..))"/>
    <!-- 执行环绕增加(把txAdvice(事务通知)与txPointCut(切入点的方法)相结合)-->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
  • pointcut切入点,切面通知执行的“地点”
  • expression定义切入点表达式,execution(* com.kuang.mapper….(…))
  • execution()表达式主体
  • 第一个 * 号表示返回类型,*号表示所有的类型
  • com.kuang.mapper…表示要拦截的包名,后面的两个.号表示当前包和当前包的所有子包
  • 第二个 * 号表示类名,*号表示所有的类
  • * ( … )最后这个*号表示方法名,*号表示所有的方法,后面的()表示方法的参数,两个.号表示任何参数

13.2.3 编写MyTest测试类

package com.kuang.dao;

public class MyTest { 
    
		// 获取所有的用户信息:使用继承SqlSessionDaoSupport方式
        @Test
        public void getUsers3()  {
            // 获取上下文信息,得到Spring的IOC容器
            ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
            // 从IOC容器中获取UserMapper的Bean信息(说明类型后就不需要强制转换了)
            UserMapper userMapper = context.getBean("userMapper2",UserMapper.class);
            // 调用getUsers获取所有用户,然后进行遍历
            for (User user : userMapper.getUsers()) {
                System.out.println(user);
            }
       }
    
}

13.2.4 测试结果

1.未配置声明式事务且SQL语句编写错误

  • 查看控制台输出

在这里插入图片描述

  • 查看数据库信息

在这里插入图片描述

结果报错,删除用户的SQL语句出错,删除id为3的用户失败,但是id为4的用户仍然插入成功了

分析

这两组事务同时执行,删除用户的事务失败了,但插入用户的事务却执行成功了,这显然不符合事务的ACDI原则:即要么都成功,要么都失败!

2.配置声明式事务后且SQL语句编写正确

  • 查看控制台输出

在这里插入图片描述

  • 查看数据库信息

在这里插入图片描述

结果增加id为4用户,删除id为6的用户成功!两组事务共同执行,都执行成功了!

好了,今天的有关声明式事务的学习就到此结束啦,欢迎小伙伴们积极学习和讨论,喜欢的可以给蜗牛君点个关注,顺便来个一键三连,我们下期见,拜拜啦!


参考视频链接:https://www.bilibili.com/video/BV1WE411d7Dv(【狂神说Java】Spring5最新教程IDEA版通俗易懂)

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-19 11:44:20  更:2021-10-19 11:46:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/26 6:15:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码