不能吧,最后一次它又来了--整合Mybatis和事务管理(“最易懂得Spring学习”)(三)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 十三、声明式事务1. 回顾事务2. 一个案例3.Spring中的事务管理

十三、声明式事务


1. 回顾事务


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


事务的ACID原则:


  • 原子性
  • 一致性
  • 隔离性
  • 多个业务可能同时操作同一个资源,防止数据损坏
  • 持久性
  • 事务一旦提交,无论系统发生什么问题,结果都不会再影响,被持久化的写到存储器中


2. 一个案例


我们把前面的一个案例给拿下来


为了防止错误,这里再把代码以及步骤整一下:


  1. pom.xml导入包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Spring-Study</artifactId>
        <groupId>com.hxl</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>spring-11-transaction</artifactId>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.11</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.11</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
    </dependencies>
    <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>
            </resource>
        </resources>
    </build>
</project>

2.实体类

package com.hxl.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

3.接口

package com.hxl.mapper;
import com.hxl.pojo.User;
import java.util.List;
public interface UserMapper {
    public List<User> selectUser();
    //添加一个用户
    public int addUser(User user);
    //删除一个用户
    public int deleteUser(int id);
}

4.mybatis-config.xml

<?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>
    <!--别名管理-->
    <typeAliases>
        <package name="com.hxl.pojo"/>
    </typeAliases>
    <!--设置-->
    <!--比如说日志开启-->
    <!--<environments default="development">
        <environment id="development">
            &lt;!&ndash;事务管理&ndash;&gt;
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>-->
    <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册-->
<!--    <mappers>
        &lt;!&ndash;用class的话需要mapper的两个名字相同并且在同一个包下&ndash;&gt;
        <mapper resource="com/hxl/mapper/UserMapper.xml"/>
    </mappers>-->
</configuration>

5.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:context="http://www.springframework.org/schema/context"
       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/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--DataSource:使用Spring的数据源替换Mybatis的配置:c3p0  dbcp  druid
    这里使用Spring提供的JDBC.
    这里使用了之后我们就可以把mybatis-config.xml中的去掉了
    -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--绑定上方所写数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--绑定mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--这样的话原来的注册mapper也就不需要了-->
        <property name="mapperLocations" value="classpath:com/hxl/mapper/*.xml"/>
    </bean>
    <!--SqlSessionTemplate就是我们使用的sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
</beans>

6.UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hxl.mapper.UserMapper">
    <!--resultType:主要用于从数据库中提取数据-->
    <select id="selectUser" resultType="user">
        select * from user
    </select>
    <insert id="addUser" parameterType="user">
        insert into user(id,name,pwd) values (#{id},#{name},#{pwd})
    </insert>
    <delete id="deleteUser" parameterType="int">
        deletes from user where id=#{id}
    </delete>
</mapper>

7.UserMapperImpl

package com.hxl.mapper;
import com.hxl.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
    public List<User> selectUser() {
        User user = new User(5, "老五", "123456");
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        mapper.addUser(user);
        mapper.deleteUser(5);
        return mapper.selectUser();
    }
    public int addUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).addUser(user);
    }
    public int deleteUser(int id) {
        return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
    }
}

8.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:context="http://www.springframework.org/schema/context"
       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/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <import resource="spring-dao.xml"/>
    <!--注入到spring中-->
    <bean id="userMapper" class="com.hxl.mapper.UserMapperImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

9.测试

import com.hxl.mapper.UserMapper;
import com.hxl.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        for (User user : userMapper.selectUser()) {
            System.out.println(user);
        }
    }
}

这里是为了重现数据库的错误:我们编写的delete语句是错误的,我们运行发现数据库中加入了增加的数据。这个是不对的,因为我们的删除语句失败了,结果插进去了,不符合我们的原则。ACID


3.Spring中的事务管理


  • 声明式事务:AOP


  • 编程式事务:需要在代码中,进行事务的管理


在spring-dao中增加下面这段代码就可以实现上面的问题,delete报错,add也不会加入


<!--结合aop实现事务的织入:需要找到一个切入点或切面这个东西-->
<!--1.配置事务通知:-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--给方法配置事务;
        配置事务的传播特性:new propagation="REQUIRED"默认就是它,可以不写
        -->
    <tx:attributes>
        <tx:method name="add" propagation="REQUIRED"/>
        <tx:method name="delete" propagation="REQUIRED"/>
        <tx:method name="update" propagation="REQUIRED"/>
        <tx:method name="query" read-only="true"/>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>
<!--2.配置事务切入-->
<aop:config>
    <aop:pointcut id="txPointCut" expression="execution(* com.hxl.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>


:


为什么需要事务?


  • 如果不配置事务,可能存在数据提交不一致的情况


  • 如果我们不在spring中去配置声明式事务,我们就需要在代码中手动配置事务,


  • 事务在开发中十分重要,涉及到数据的一致性和完整性问题。
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1天前
|
Java 关系型数据库 数据库连接
MyBatis-Plus介绍及Spring Boot 3集成指南
MyBatis-Plus是一个MyBatis扩展工具,旨在简化Java开发中的CRUD操作。它具有无侵入性、低损耗、强大的CRUD功能、Lambda表达式支持、主键自动生成、ActiveRecord模式、全局操作和内置代码生成器等特点。在Spring Boot 3中集成MyBatis-Plus,需在pom.xml添加依赖,排除特定版本的mybatis-spring,并用@MapperScan注解指定Mapper接口路径。此外,还介绍了如何使用MyBatis-Plus代码生成器自动生成Mapper、Model、Service和Controller层代码,以加速开发。
34 2
MyBatis-Plus介绍及Spring Boot 3集成指南
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp微信小程序的智能学习平台系统的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的智能学习平台系统的详细设计和实现
|
2天前
|
Java 关系型数据库 MySQL
SpringBoot整合JUnit、MyBatis、SSM
SpringBoot整合JUnit、MyBatis、SSM
11 4
|
2天前
|
Java 数据库连接 数据库
Spring整合Mybatis、Spring整合JUnit
Spring整合Mybatis、Spring整合JUnit
11 1
Spring整合Mybatis、Spring整合JUnit
|
2天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp微信小程序的在线考试与学习交流网页平台的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的在线考试与学习交流网页平台的详细设计和实现
|
2天前
|
安全 前端开发 Java
学习从Struts迁移到Spring的策略概述
从Struts框架迁移到Spring框架是一个常见的升级路径,主要是为了利用Spring框架提供的更多功能、更好的模块化支持以及更广泛的社区资源。
11 3
|
2天前
|
XML Java 数据格式
Spring框架学习 -- Bean的生命周期和作用域
Spring框架学习 -- Bean的生命周期和作用域
15 2
|
2天前
|
存储 XML Java
Spring框架学习 -- 读取和存储Bean对象
Spring框架学习 -- 读取和存储Bean对象
13 0
Spring框架学习 -- 读取和存储Bean对象
|
2天前
|
XML Java Maven
Spring框架学习 -- 创建与使用
Spring框架学习 -- 创建与使用
14 0
|
2天前
|
存储 Java 应用服务中间件
Spring框架学习 -- 核心思想
Spring框架学习 -- 核心思想
15 0