Spring的事务管理-tx
事物的简单介绍
事务特性
事务要么整体生效,要么整体失效。在数据库上即使多条SQL语句要么全执行成功,要么全执行失败!
事务的四个原则
-
原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回 滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。
-
一致性(consistency):数据库总数从一个一致性的状态转换到另一个一致性的状态。
-
隔离性(isolation):一个事务所做的操作(添加、修改、删除)在最终提交以前,对其他事务是不可见的。
-
持久性(durability):一旦事务提交,则其所做的操作(添加、修改、删除)就会永久保存到数据库中。此时即使系统崩溃,修改 的数据也不会丢失。
事务并发问题
- 脏读:读取到别人未提交的修改内容
- 不可重复读:读取到别人提交后的修改数据内容
- 幻读:读取到别人提交后的新增或删除的数据内容
Spring事务传播策略
Spring中的事务分为:编程式事务(手动编写代码)和声明式事务(xml配置;注解)。
propagation 控制事务传播行为
-
REQUIRED (默认值): 如果当前有事务,就在事务中执行,如果当前没有事务,新建一个事务.适用于:增,删,改方法
-
SUPPORTS:如果当前有事务就在事务中执行,如果当前没有事务,就在非事务状态下执行.适用于:查询方法。
Xml配置声明式事务
1.事务的分类:
编程式事务
编程式事务: 整个事务的管理都是程序员自己书写的代码进行的控制 如:获取事务对象,设置事务隔离级别,传播策略,开启,提交,回滚等。
声明式事务
声明式事务: 现在整个事务管理已经做好了,如果我们想要使用事务,只要在我们自己的程序中进行声明配置即可
声明式事务分类–两种
-
Xml配置声明式事务
-
注解配置声明式事务
2.事务传播策略使用的条件:
在一个业务中执行两条或者两条以上的增删改操作的时候
3.事务的配置
A) 切点:增加事务的方法
B) 切面:事务的传播策略
C) 织入切面(xml;注解)
代码实现–xml方式
1.修改mapper接口和mapper映射文件
2.修改service接口和实现类
3.编写applicationContext.xml配置文件
4.编写测试类
注意: 我们使用Spring 中的声明式事务的时候一定注意,不要自己捕捉异常
Dept实体类
package com.jr.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
@Component/*等价bean标签*/
@Data/*自动生成get、set、toString*/
@AllArgsConstructor/*自动全参构造器*/
@NoArgsConstructor/*自动无参构造器*/
public class Dept {
private Integer deptno;
private String dname;
private String loc;
}
1.修改mapper接口和mapper映射文件
mapper接口:
public interface DeptMapper {
// 添加部门信息
int insertDept(Dept dept);
// 删除部门信息
int deleteDept(int deptno);
// 修改部门信息
int updateDept(Dept dept);
// 查询全部部门信息
List<Dept> selectDepts();
}
mapper.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">
<!-- namespace的值是 对应接口的“全局限定名”-->
<mapper namespace="com.jr.mapper.DeptMapper">
<insert id="insertDept" parameterType="dept" keyProperty="deptno" useGeneratedKeys="true">
insert into db_dept(deptno,dname,loc) values(#{deptno},#{dname},#{loc})
</insert>
<delete id="deleteDept" parameterType="int" >
delete from db_dept where deptno=#{deptno}
</delete>
<update id="updateDept" parameterType="dept" >
update db_dept set dname=#{dname},loc=#{loc} where deptno=#{deptno}
</update>
<select id="selectDepts" resultType="dept">
select * from db_dept
</select>
</mapper>
2.修改service接口和实现类
service接口
public interface DeptService {
// 添加部门信息
boolean addDept(Dept dept);
// 删除部门信息
boolean removeDept(int deptno);
// 修改部门信息
boolean updateDept(Dept dept,String loc);
// 查询全部部门信息
List<Dept> findAll();
}
service接口实现类
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Override
public boolean addDept(Dept dept) {
return deptMapper.insertDept(dept)==1?true:false;
}
@Override
public boolean removeDept(int deptno) {
return deptMapper.deleteDept(deptno)==1?true:false;
}
@Override
public boolean updateDept(Dept dept,String loc) throws UncategorizedSQLException {
/*此处模拟两个操作(添加和修改),用于测试类中测试事务*/
int i=0;
i = deptMapper.insertDept(dept);
dept.setLoc(loc);
i += deptMapper.updateDept(dept);
return i==2?true:false;
}
@Override
public List<Dept> findAll() {
return deptMapper.selectDepts();
}
}
3.编写applicationContext.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd ">
<!--1.声明事务管理的对象-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2.配置事务的传播策略 规范:传播策略都是配置在service层
name属性值是 service实现类中的方法前缀;
propagation 属性值 设置事务的传播策略;REQUIRED 有事务就加入;没有就创建(增,删,改)
SUPPORTS 有事务就加入,没有也不创建(查询)
事务的隔离级别,Spring框架采用默认方式,自动识别
-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!--3.配置声明式事务的下xml方式: -->
<aop:config>
<aop:pointcut id="servicePointcut" expression="execution(* com.jr.service.impl.DeptServiceImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>
</aop:config>
4.编写测试类
public class DeptTest {
@Test
public void test01(){
ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
DeptService DeptService=context.getBean("deptServiceImpl", DeptService.class);
Dept dept=context.getBean("dept",Dept.class);
dept.setDeptno(21);
System.out.println("请输入要修改的部门新地址:");
String loc=(new Scanner(System.in)).next();
try {
DeptService.updateDept(dept,loc);
}catch (UncategorizedSQLException e){
System.out.println("失败。。。。");
System.exit(1);
}finally {
System.out.println("成功,,,,");
}
}
}
代码实现–注解方式
1.编写applicationContext.xml配置文件
2.修改ServiceImpl实现类代码
3.其他位置代码没有改动!
1.编写applicationContext.xml配置文件
将上面的 2 和 3 配置换为 4 配置事务通知,保留配置 1 。
<!--1.声明事务管理的对象-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--4.事务的通知-->
<tx:annotation-driven transaction-manager="txManager"/>
2.修改ServiceImpl实现类代码:
@Service/*等价于添加bean*/
@Transactional(propagation= Propagation.REQUIRED)
/*
设置当前业务类下, 所有业务方法,都遵守REQUIRED 传播策略;
REQUIRED :有事务就加入,没事务就开启
*/
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Override
public boolean addDept(Dept dept) {
return deptMapper.insertDept(dept)==1?true:false;
}
@Override
public boolean removeDept(int deptno) {
return deptMapper.deleteDept(deptno)==1?true:false;
}
@Override
public boolean updateDept(Dept dept,String loc) throws UncategorizedSQLException {
/*此处模拟两个操作(添加和修改),用于测试类中测试事务*/
int i=0;
i = deptMapper.insertDept(dept);
dept.setLoc(loc);
i += deptMapper.updateDept(dept);
return i==2?true:false;
}
@Override
public List<Dept> findAll() {
return deptMapper.selectDepts();
}
}