事务概念

1.什么是事务
1.事务是数据库操作的单元,指在逻辑上的一组操作,要么都成功要么都失败
2.典型场景:银行转账
2.事务的特性(ACID特性)
1.原子性:一个过程不可分割,要么都成功要么都失败
2.一致性:一个数据操作之前与操作之后的总量是不变的
3.持久性:在多事务操作的时候它们之间不会产生影响
4.隔离性:事务提交之后表中的数据也相应的发生了变化

事务操作

搭建事务操作环境

1.创建数据库的表,添加记录
2.创建service,搭建dao,完成对象创建和注入关系
1.在service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource
3.在dao创建两个方法:多钱和少钱的方法,在service创建方法(转账的方法)

  1. @Repository
  2. public class UserDaoImpl implements UserDao {
  3. @Resource
  4. private JdbcTemplate jdbcTemplate;
  5. //多钱
  6. public void addMoney() {
  7. String sql = "update t_account set money=money+? where id=?";
  8. jdbcTemplate.update(sql,100,"2");
  9. }
  10. //少钱 lucy转账100给mary
  11. public void reduceMoney() {
  12. String sql = "update t_account set money=money-? where id=?";
  13. jdbcTemplate.update(sql,100,"1");
  14. }
  15. }

service中一个方法

  1. @Service
  2. public class UserServiceImpl implements UserService {
  3. @Resource
  4. private UserDao userDao;
  5. //转账
  6. public void accountMoney() {
  7. //lucy少100
  8. userDao.reduceMoney();
  9. //mary加100
  10. userDao.addMoney();
  11. }
  12. }

4.上面代码,如果正常执行没有问题的,但是如果代码执行过程中出现了异常,就会有问题

  1. @Service
  2. public class UserServiceImpl implements UserService {
  3. @Resource
  4. private UserDao userDao;
  5. //转账
  6. public void accountMoney() {
  7. //lucy少100
  8. userDao.reduceMoney();
  9. //模拟异常
  10. int i = 1 / 0;
  11. //mary加100
  12. userDao.addMoney();
  13. }
  14. }

1.上面的问题该如何解决呢?
使用事务进行解决

  1. @Service
  2. public class UserServiceImpl implements UserService {
  3. @Resource
  4. private UserDao userDao;
  5. //转账
  6. public void accountMoney() {
  7. try{
  8. //第一步 开启事务
  9. //第二步 进行业务操作
  10. //lucy少100
  11. userDao.reduceMoney();
  12. //模拟异常
  13. int i = 1 / 0;
  14. //mary加100
  15. userDao.addMoney();
  16. //第三步 没有发生异常 提交事务
  17. }catch (Exception e){
  18. //第四步 如果出现异常 事务回滚
  19. e.printStackTrace();
  20. }
  21. }
  22. }

Spring事务管理介绍

1.事务添加到javaEE三层结构里面的service层(业务逻辑层)
2.在Spring进行事务管理操作
1.有两种方式
(1)编程式事务管理
(2)声明式事务管理(常用)
3.声明式事务管理
1.基于注解方式
2.基于xml配置文件方式
4.在spring进行声明式事务管理,底层使用AOP原理
5.Spring事务管理API
1.提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
捕获.PNG

注解声明式事务管理

1.在spring的配置文件中配置事务管理器

  1. <!--创建事务管理器-->
  2. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  3. <!--注入数据源-->
  4. <property name="dataSource" ref="dataSource"/>
  5. </bean>

2.在spring配置文件中,开启事务注解
1.在spring配置文件

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. 事务:xmlns:tx="http://www.springframework.org/schema/tx"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context
  9. http://www.springframework.org/schema/context/spring-context.xsd
  10. http://www.springframework.org/schema/aop
  11. http://www.springframework.org/schema/aop/spring-aop.xsd
  12. 事务: http://www.springframework.org/schema/tx
  13. 事务:http://www.springframework.org/schema/tx/spring-tx.xsd">

2.开启事务的注解

  1. <!--开启事务注解-->
  2. <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

因为spring的事务注解底层是aop实现的所以要把aop配置打开

  1. <!--配置aop-->
  2. <aop:config proxy-target-class="true"></aop:config>

3.在service类上面(或者service类里面的方法上面)添加一个事务的注解
1.@Transactional,这个注解添加到类上面,也可以添加到方法上面
2.如果把这个注解添加到类上面,这个类里面所有的方法都添加事务
3.如果把这个注解添加到方法上面,为这个方法添加了事务

  1. @Service
  2. @Transactional
  3. public class UserServiceImpl implements UserService {

声明式事务管理参数配置

1.在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数
捕获1.PNG

1.propagation:事务传播行为

1.多事务方法直接进行调用,这个过程中事务是如何进行管理的
Spring框架事务传播行为有7种
捕获2.PNG
前两个必须知道

REQUIRED 如果add方法本身就有事务,调用update之后,update使用当前add方法里面的事务.
如果add方法本身没有事务,调用update方法之后,创建一个新的事务
REQUIRES_NEW 使用add方法去调用update方法,如果add无论是否有事务,都会创建一个新的事务
  1. @Service
  2. @Transactional(propagation = Propagation.REQUIRED)
  3. public class UserServiceImpl implements UserService {

2.isolation:事务的隔离级别

1.事务有特性成为隔离性,多事务操作之间不会产生影响.不考虑隔离性会产生很多问题
2.有三个读问题:脏读,不可重复读,幻读
脏读:一个未提交事务读取到另一个未提交事务的数据
不可重复读:一个未提交事务读取到另一个已经提交事务的修改数据
幻读:一个未提交的事务读取到另一个已提交事务添加的数据
通过设置事务隔离级别可以解决问题
捕获3.PNG

  1. @Service
  2. @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.SERIALIZABLE)
  3. public class UserServiceImpl implements UserService {

3.timeout:超时时间

1.事务需要在一定的时间内进行提交,如果不提交就会进行回滚
2.默认值为-1,设置时间是以秒为单位进行计算的

  1. @Service
  2. @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.SERIALIZABLE,timeout = 5)
  3. public class UserServiceImpl implements UserService {

4.readOnly:是否只读

1.读:查询操作,写:添加修改删除操作
2.readOnly默认值为false,表示可以查询,可以添加修改删除操作
3.可以设置readOnly值为true,设置成true之后,只能查询

  1. @Service
  2. @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.SERIALIZABLE,timeout = 5,readOnly = false)
  3. public class UserServiceImpl implements UserService {

5.rollbackFor:回滚

1.设置出现哪些异常进行事务的回滚

6.noRollbackFor:不回滚

1.设置出现哪些异常不进行事务回滚

XML声明式事务管理

1.在spring配置文件中进行配置
1.配置事务管理器
2.配置通知
3.配置切入点和切面

  1. <!--创建事务管理器-->
  2. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  3. <!--注入数据源-->
  4. <property name="dataSource" ref="dataSource"/>
  5. </bean>
  6. <!--配置通知-->
  7. <tx:advice id="txadvice">
  8. <!--配置事务参数-->
  9. <tx:attributes>
  10. <!--指定哪种规则的方法上面添加事务-->
  11. <!--<tx:method name="accountMoney"/>-->
  12. <tx:method name="account*" propagation="REQUIRED"/>
  13. </tx:attributes>
  14. </tx:advice>
  15. <!--配置切入点和切面-->
  16. <aop:config proxy-target-class="true">
  17. <!--配置切入点-->
  18. <aop:pointcut id="pt" expression="execution(* com.ranin.service.impl.UserServiceImpl.*(..))"/>
  19. <!--配置切面-->
  20. <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
  21. </aop:config>

完全注解声明式事务管理

1.创建配置类,使用配置类替代xml配置文件

  1. @Configuration//配置类
  2. @ComponentScan(basePackages = "com.ranin")//组件扫描
  3. @EnableTransactionManagement//开启事务
  4. public class TxConfig {
  5. //配置数据库连接池
  6. @Bean
  7. public DruidDataSource getDruidDataSource(){
  8. DruidDataSource dataSource = new DruidDataSource();
  9. dataSource.setDriverClassName("com.mysql.cj.jadb.Driver");
  10. dataSource.setUrl("jdbc:mysql://47.93.182.140:3306/test?serverTimezone=GMT%2B8&useSSL=false");
  11. dataSource.setUsername("root");
  12. dataSource.setPassword("123456");
  13. return dataSource;
  14. }
  15. //创建JdbcTemplate对象
  16. @Bean
  17. public JdbcTemplate getJdbcTemplate(DataSource dataSource){
  18. JdbcTemplate jdbcTemplate = new JdbcTemplate();
  19. //注入datasource
  20. jdbcTemplate.setDataSource(dataSource);
  21. return jdbcTemplate;
  22. }
  23. //创建事务管理器
  24. @Bean
  25. public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
  26. DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
  27. dataSourceTransactionManager.setDataSource(dataSource);
  28. return dataSourceTransactionManager;
  29. }
  30. }