事务操作
一、事务概念
1. 什么是事务
- 事务是数据库操作最基本的单元,逻辑上一组的操作,要么同时成功,要么同时失败。
2. 事务的特效(ACID)
- 原子性
- 一致性
- 隔离性
- 持久性
二、事务操作的环境搭建
1. 建表
CREATE TABLE t_account(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20),
money INT
);
INSERT INTO t_account VALUE(NULL,'lucy',100);
INSERT INTO t_account VALUE(NULL,'mary',100);
2. 目录结构
3. 相关类的创建
- UserService类
@Service
//@Transactional(propagation = Propagation.MANDATORY,isolation = Isolation.REPEATABLE_READ,timeout = 1000)
public class UserService {
@Autowired
private UserDao userDao;
//转账的方法
public void accountMoney(){
//try{
//第一步 开启事务
//第二步 进行业务操作
userDao.add();
//模拟异常
//int i = 10 / 0;
userDao.reduce();
//第三步 无异常发生提交事务
//}catch (Exception e){
//第四步 出现异常回滚事务
//}
}
}
- UserDao类
public interface UserDao {
public void add();
public void reduce();
}
- UserDaoImpl类
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add() {
String sql = "update t_account set money = money + ? where username = ?";
jdbcTemplate.update(sql,100,"lucy");
}
@Override
public void reduce() {
String sql = "update t_account set money = money - ? where username = ?";
jdbcTemplate.update(sql,100,"mary");
}
}
- 测试类
public class UserServiceTest extends TestCase {
public void testAccountMoney() {
//基于注解的测试方法
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}
public void testAccountMoney1() {
//基于配置文件的测试方法
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}
}
三、Spring事务管理介绍
- 事务添加到service层。
- 事务分为编程式事务管理和声明式事务管理,一般使用声明式事务管理。
- 声明式事务管理,基于注解方式和基于xml配置文件方式。
- 在Spring进行声明式事务管理,底层使用AOP原理。
1. 注解声明式事务管理
- 在spring配置文件配置事务管理器
在这里插入代码片
- 在spring配置文件,开启事务注解
在这里插入代码片
2. 事务参数
① propagation:事务传播行为
@Transactional(propagation = Propagation.REQUIRES)
② ioslation:事务隔离级别
-
事务的隔离性,使得多事务之间不会产生影响。
-
常见的三种隔离性的问题,脏读、不可重复读、幻读。
脏读:读取到未提交的数据。 不可重复读:一个未提交的事务读取到另一个提交事务修改的数据。 幻读:一个未提交的事务读取到另一个提交事务添加的数据。 事务的隔离级别; 脏读 不可重复读 幻读 read uncommitted ✓ ✓ ✓ read committed ✓ ✓ repeatable read ✓ serializable
@Transactional(isolation = Isolation.REPEATABLE_READ)
③ timeout:超时时长
- 事务需要在一定时间内进行提交,如果不提交则回滚。
- 默认值-1,不设置超时时长,设置时间已秒为单位。
④ readOnly:是否只读
- 读-查询操作,写-增删改操作。
- readOnly默认值为false,可写可读。
- 设置为true,只能进行查询操作
⑤ rollbackFor:回滚
- 设置出现哪些异常进行回滚。
⑥ noRollbackFor:不回滚
- 设置出现哪些异常不进行回滚。
3. 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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
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/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启扫描-->
<context:component-scan base-package="com.znb.spring5"></context:component-scan>
<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 获取properties文件内容,根据key获取,使用spring表达式获取 -->
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/usedb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT"></property>
<property name="username" value="root"></property>
<property name="password" value="2550"></property>
</bean>
<!--JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSourse-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--1.创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2.配置通知-->
<tx:advice id="txadvice">
<!--配置事务相关参数-->
<tx:attributes>
<!--指定那种规则的方法上面添加事务-->
<tx:method name="account*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--3.配置切入点和切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.znb.spring5.service.UserService.*(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
</aop:config>
</beans>