事务的基本概念
- 事务是数据库操作的最基本单元,逻辑上一组操作,要么都成功,一旦有一个失败,则所有操作都失败
- 典型场景:银行转账
(1)lucy转账100给Mary
(2)Lucy少100,Mary多100 - 事务的四个特性(ACID)
(1)原子性
(2)一致性
(3)隔离性
(4)持久性
搭建事务操作环境(模拟转账操作)
图解说明结构逻辑
- JavaEE操作的三层结构:Web层(视图层)、Service层(业务逻辑层)、Dao层(数据(库)操作层)
- 初始化数据库的表信息
导入依赖包
同Spring框架(四)JdbcTemplate的依赖包
xml配置文件,同Spring框架(四)JdbcTemplate
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.spring.transaction"></context:component-scan>
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="jdbc:mysql:///user_db?characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="230519" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
<!--JdbcTemplate对象的创建-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
实现Service层和Dao层的功能
- Dao层
public interface UserDao {
public void addMoney();
public void reduceMoney();
}
@Repository
public class UserDaoImpl implements UserDao{
//注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addMoney() {
String sql = "update t_account set money=money+? where username=?";
jdbcTemplate.update(sql,100,"mary");
}
@Override
public void reduceMoney() {
String sql = "update t_account set money=money-? where username=?";
jdbcTemplate.update(sql,100,"lucy");
}
}
- Service层
@Service
public class UserService {
//注入Dao
@Autowired
private UserDao userDao;
public void accountMoney(){
userDao.reduceMoney();
userDao.addMoney();
}
}
- 测试方法
@Test
public void testAccount(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.accountMoney();
}
- 测试结果
事务场景引入(模拟事务的特性)
问题引入
在转账过程中出现异常
结果:
分析:lucy的账户少了100,但由于出现了异常,导致mary的账户没有增加100,由此引入事务的特性
事务的解决方式
- 解决逻辑
- 具体实现事务管理
** 一般将事务添加导Java EE三层结果的Service层(业务逻辑层)**
(1)编程式事务管理(1中的解决逻辑的代码实现)
(2)声明式事务管理(主要使用该方式)
声明式事务管理
** 在Spring进行声明式事务管理时,底层使用导了AOP原理**
- 实现方式
(1)基于注解方式(主要使用)
(2)基于xml配置文件方式(略) - Spring提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
基于注解方式实现过程
- xml配置文件(在原先的xml配置文件内容基础上添加)
(1)引入tx名称空间
(2)创建事务管理器,注入数据库信息
(3)开启事务注解,注入事务管理器
<?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: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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.spring.transaction"></context:component-scan>
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="jdbc:mysql:///user_db?characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="230519" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
<!--JdbcTemplate对象的创建-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--1.创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
- 在Service层的类上面(或类中的方法上面)添加事务注解@Transactional
(1)如果注解在类上面,表示对该类中的所有方法都添加事务
(2)如果注解在方法上面个,表示只对该方法添加事务
@Service
@Transactional
public class UserService {
//注入Dao
@Autowired
private UserDao userDao;
public void accountMoney(){
userDao.reduceMoney();
int i = 10/0;
userDao.addMoney();
}
}
- 测试结果
转账过程出现异常,两个账户都没有改动
@transactional注释的参数配置
- propagation:事务传播行为
(1)多事务方法直接进行调用,这个过程中事务是如何管理的
(1)事务方法:对数据库中数据进行改变的操作
(2)在一个方法中调用另一个方法,且其中一个方法没有事务管理注解
(3)7种事务传播行为
主要使用前两种:
- ioslation:事务隔离级别
(1)事务有特性称为隔离性,多事务操作之间不会产生影响。如果不考虑隔离性会产生很多问题。
(2)三个读的问题:脏读、不可重复读、虚(幻)读
【1】脏读(致命问题):一个未提交事务读到另一个未提交事务的修改数据。一个用户A更改了数据库中的数据,但还未提交,另一个用户B此时读取到的是更改后的数据,但如果用户A进行事务回滚,则用户B实际拿到的数据并不是真正的数据。
【2】不可重复读(现象):一个未提交的事务读到另一个已提交事务修改的数据
【虚读】:未提交事务读到另一个提交事务的添加数据
(3)通过隔离级别的设置解决三个读问题
- timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是-1,表示不回滚。如果设置时,单位时秒 - readOnly:是否只读
(1)读:查询操作;写:添加修改删除操作
(2)readOnly默认值为false,表示可以查询,也可以添加删除修改 - rollbackFor:回滚
(1)设置出现哪些异常进行事务的回滚 - noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务的回滚
完全注解开发
使用配置类代替xml配置文件