前言:
小伙伴们,大家好,我是狂奔の蜗牛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
@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">
<mapper namespace="com.kuang.mapper.UserMapper">
<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">
<mapper namespace="com.kuang.mapper.UserMapper">
<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>
4.编写UserMapperImpl2接口实现类
package com.kuang.mapper;
import com.kuang.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
public List<User> getUsers() {
User user = new User(4,"钟兴民","zxm123456");
UserMapper userMapper = getSqlSession().getMapper(UserMapper.class);
userMapper.insertUser(user);
userMapper.deleteUser(3);
return userMapper.getUsers();
}
public int insertUser(User user) {
return getSqlSession().getMapper(UserMapper.class).insertUser(user);
}
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>
<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>
<?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">
<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=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
</beans>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath*:com/kuang/mapper/*.xml"/>
</bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<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">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
</bean>
<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约束
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
<?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数据源事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
3-3 结合AOP实现事务的织入
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<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"/>
<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>
<aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper..*.*(..))"/>
<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 {
@Test
public void getUsers3() {
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper2",UserMapper.class);
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版通俗易懂)
|