概念
- 事务是指数据库中的一个操作序列,它由一系列的SQL指令组成。在Java EE程序开发中,事务管理是一个影响范围较广的领域,在程序与数据库交互时,保证事务的正确执行尤为重要。由于实际开发中事务管理存在的诸多弊端,Spring框架针对事务管理提供了自己的解决方案。
- 对于事务管理,Spring采用的方式是通过在高层次建立事务抽象,然后在此基础上提供一个统一的编程模型,这意味着,Spring具有在多种环境中配置和使用事务的能力,无论是Spring JDBC,还是以MyBatis为代表的ORM框架,Spring都能够使用统一的编程模型对事务进行管理并为事务管理提供通用的支持。
- 基于Spring IOC和Spring AOP,Spring提供了声明式事务管理的方式,它允许开发人员直接在Spring容器中定义事务的边界和属性,除此之外,Spring还实现了事务管理和数据访问的分离,在这种条件下,开发人员只需关注对当前事务的界定,其余工作将由Spring框架自动完成。
一句话:事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。
一句话:事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
事务四个特性(ACID)
- 原子性(atomicity)
事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用 - 一致性(consistency)
一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中 - 隔离性(isolation)
可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏 - 持久性(durability)
事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中
(搭建事务操作环境)
1、创建数据库表,添加记录
2、创建service,搭建dao,完成对象创建和注入关系
(1)service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource
public interface UserDao {
//多钱
public void addMoney();
//少钱
public void reduceMoney();
}
@Service
public class UserService {
//注入dao
@Autowired
private UserDao userDao;
}
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
}
3、在dao创建两个方法:多钱和少钱的方法,在service创建方法(转账的方法)
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
//lucy转账100给mary
//少钱
@Override
public void reduceMoney() {
String sql = "update t_account set money=money-? where username=?";
jdbcTemplate.update(sql, 100, "lucy");
}
//多钱
@Override
public void addMoney() {
String sql = "update t_account set money=money+? where username=?";
jdbcTemplate.update(sql, 100, "mary");
}
}
@Service
public class UserService { //注入dao
@Autowired
private UserDao userDao;
// 转账的方法
public void accountMoney() {
//lucy少100
/userDao.reduceMoney(); //mary多100
userDao.addMoney();
}
}
4、上面代码,如果正常执行没有问题的,但是如果代码执行过程中出现异常,有问题
(1)上面问题如何解决呢?
- 使用事务进行解决
(2)事务操作过程
事务操作(Spring 事务管理介绍)
1、事务添加到JavaEE三层结构里面Service层(业务逻辑层)
2、在Spring进行事务管理操作
(1)有两种方式:编程式事务管理和声明式事务管理(使用)
3、声明式事务管理
(1)基于注解方式(使用)
(2)基于xml配置文件方式
4、在Spring进行声明式事务管理,底层使用AOP原理
5、Spring事务管理API
(1)提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
注解声明式事务管理
1、在spring配置文件配置事务管理器
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
2、在spring配置文件,开启事务注解
(1)在spring配置文件引入名称空间 tx
<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: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/context http://www.springframework.org/schema/context/spring-context.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">
(2)开启事务注解
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3、在service类上面(或者service类里面方法上面)添加事务注解
(1)@Transactional,这个注解添加到类上面,也可以添加方法上面
(2)如果把这个注解添加类上面,这个类里面所有的方法都添加事务
(3)如果把这个注解添加方法上面,为这个方法添加事务
@Service
@Transactional
public class UserService {
事务操作(声明式管理参数配置)
1、在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数
2、propagation:事务传播行为
(1)多事务方法直接进行调用,这个过程中事务 是如何进行管理的
多事务方法:一个有事务调一个无事务,一个无事务调一个有事务,
事务方法:对数据库表数据进行变化的操作
3、ioslation:事务隔离级别
(1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题
(2)有三个读问题:脏读、不可重复读、虚(幻)读
(3)脏读:一个未提交事务读取到另一个未提交事务的数据
(4)不可重复读:一个未提交事务读取到另一提交事务修改数据
(5)虚读:一个未提交事务读取到另一提交事务添加数据
(6)解决:通过设置事务隔离级别,解决读问题
4、timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是 -1 ,设置时间以秒单位进行计算
5、readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2)readOnly默认值false,表示可以查询,可以添加修改删除操作
(3)设置readOnly值是true,设置成true之后,只能查询
6、rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
7、noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚
事务操作( XML声明式事务管理)
- 在使用XML文件完成声明式事务管理时,首先要引入tx命名空间。在引入tx命名空间之后,可以使用
<tx:advice>
元素来配置事务管理的通知,进而通过Spring AOP实现事务管理。 <tx:advice>
元素包含两个属性,它们分别是id属性和transaction-manager属性,其中id属性用于配置<tx:advice>
元素的id值,transaction-manager属性用于配置TransactionManager。- 除此之外,tx:advice元素还包含有子元素tx:attributes,tx:attributes元素中可以配置多个tx:method子元素,这些tx:method子元素主要用于配置事务的属性。
- tx:method元素提供了一系列属性用于事务的定义,具体如表所示
- 表中列举了tx:advice元素的属性,其中name、propagation和isolation这三个属性的应用范围较广,开发人员可根据实际需要选择使用。
1、在spring配置文件中进行配置
第一步 配置事务管理器
第二步 配置通知
第三步 配置切入点和切面
<!--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="accountMoney" propagation="REQUIRED"/>
<!--<tx:method name="account*"/>-->
</tx:attributes>
</tx:advice>
<!--3 配置切入点和切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
<!--配置切面 -->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
原理就是要进行事务管理的方法上com.atguigu.spring5.service.UserService.*(..)
添加事务
<aop:aspect>
与<aop:advisor>
的区别
-
< aop:aspect>:定义切面(切面包括通知和切点)
-
< aop:advisor>:定义通知器(通知器跟切面一样,也包括通知和切点
-
advisor只持有一个Pointcut和一个advice,而aspect可以多个pointcut和多个advice
<aop:advisor>
:
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
<aop:advisor advice-ref="adviceHandler" pointcut-ref="pointCut"/>
</aop:config>
<aop:aspect>
:
<aop:config>
<aop:aspect id="aspect" ref="adviceHandler">
<aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
<aop:around method="doAround" pointcut-ref="pointCut"/>
</aop:aspect>
</aop:config>
<aop:advisor>
直接通过advice-ref和pointcut-ref指向advice和point。
<aop:aspect>
需要在内部定义不同的advice类型,比如<aop:around>
(注意<aop:pointcut>
也可写到<aop:aspect>
外部)
事务操作(完全注解声明式管理)
@Configuration //配置类
@ComponentScan(basePackages = "com.atguigu") //组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///user_db");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
//创建JdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
//到ioc容器中根据类型找到dataSource
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//注入dataSource
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void insertUser(){
userDao.insert();
//otherDao.other();xxx
System.out.println("插入完成...");
int i = 10/0;
}
}
环境搭建:
1、导入相关依赖
数据源、数据库驱动、Spring-jdbc模块
2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
3、给方法上标注 @Transactional 表示当前方法是一个事务方法;
4、 @EnableTransactionManagement 开启基于注解的事务管理功能;
@EnableXXX
5、配置事务管理器来控制事务;
@Bean
public PlatformTransactionManager transactionManager()