前言:

本文内容:事务回顾、Spring声明式事务

推荐免费Spring5基础教程视频:【狂神说Java】Spring5最新完整教程IDEA版通俗易懂_哔哩哔哩_bilibili

Spring5笔记代码下载地址:

蓝奏云:下载地址 密码:joker

百度云:下载地址 提取码:aidp

事务回顾

回顾

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

事务ACID原则

  • 原子性

  • 一致性

  • 隔离性

    多个业务可能操作同一个资源,防止数据损坏

  • 持久性

    事务一旦提交,无论系统发生什么问题,结果都不会在被影响

搭建事务测试环境

UserMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.jokerdig.mapper;

import com.jokerdig.pojo.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
* @author Joker大雄
* @data 2022/5/23 - 13:25
**/
public interface UserMapper {
public List<User> selectUser();
// 添加一个用户
public int add(User user);
// 删除一个用户
public int delete(int id);
}

UserMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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="com.jokerdig.mapper.UserMapper">

<!-- 查询用户 来测试缓存-->
<select id="selectUser" resultType="user">
select * from user
</select>
<!-- 添加-->
<insert id="add" parameterType="user">
insert into user (id,name,pwd) value (#{id},#{name},#{pwd})
</insert>
<!-- 删除 这里delete写错为了测试事务是否生效 不配置事务,即使删除报错,也没影响数据插入-->
<delete id="delete" parameterType="int">
deletes from user where id=#{id}
</delete>
</mapper>

UserMapperImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.jokerdig.mapper;

import com.jokerdig.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

/**
* @author Joker大雄
* @data 2022/5/23 - 14:06
**/
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{

// 查询所有
public List<User> selectUser() {
User user = new User(4, "小王", "123123");
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
mapper.add(user);
mapper.delete(4);
return mapper.selectUser();
}

//添加
public int add(User user) {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.add(user);
}

// 删除
public int delete(int id) {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.delete(id);
}
}

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?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数据源-
DriverManagerDataSource
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;serverTimezone=UTC"/>
<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"/>
<property name="mapperLocations" value="classpath:com/jokerdig/mapper/*.xml"/>
</bean>
<!-- 引入UserMapperImpl2 使用SqlSessionDaoSupport -->
<bean id="userMapper" class="com.jokerdig.mapper.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
</beans>

mybatis-config.xml

1
2
3
4
5
6
7
8
9
10
11
<?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.jokerdig.pojo"/>
</typeAliases>
<!-- 设置-->
</configuration>

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.jokerdig.pojo;

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

/**
* @author Joker大雄
* @data 2022/5/23 - 13:03
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}

SpringTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.jokerdig.test;

import com.jokerdig.mapper.UserMapper;
import com.jokerdig.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

/**
* @author Joker大雄
* @data 2022/5/25 - 11:25
**/
public class SpringTest {
@Test
public void test12(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

UserMapper userMapper = context.getBean("userMapper", UserMapper.class);

List<User> users = userMapper.selectUser();

for (User user : users) {
System.out.println(user);
}
}
}

Spring声明式事务

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

添加事务

在上方代码的基础上添加事务

pom.xml添加事务需要的依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<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.22</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.19</version>
</dependency>
<!-- 连接spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.8</version>
</dependency>
<!-- mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<!-- 使用事务需要的依赖-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</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>
<filtering>true</filtering>
</resource>
</resources>
<!-- junit测试必须的插件 否则会报错-->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?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">


<!-- datasource 使用spring数据源代替mybatis数据源-
DriverManagerDataSource
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;serverTimezone=UTC"/>
<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"/>
<property name="mapperLocations" value="classpath:com/jokerdig/mapper/*.xml"/>
</bean>
<!-- 引入UserMapperImpl2 使用SqlSessionDaoSupport -->
<bean id="userMapper" class="com.jokerdig.mapper.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<!-- 配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 结合AOP植入事务-->
<!-- 配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- propagation="REQUIRED" 为默认选择 也可以不写-->
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete"/>
<tx:method name="update"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.jokerdig.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>

运行结果

1
2
3
4
5
6
User(id=1, name=admin, pwd=123)
User(id=2, name=abc, pwd=123)
User(id=3, name=def, pwd=123)
User(id=4, name=小王, pwd=123123)

Process finished with exit code 0

为什么需要事务

  • 如果不配置事务,可能存在数据不一致的情况
  • 如果我们不在Spring中去配置声明事务,就需要在代码中手动配置事务
  • 事务在项目开发中十分重要,涉及到数据的一致性和完整性

总结导图 【JavaWeb】JavaWeb 从入门到实战 (16)