Spring——事务

事务

1、事务操作(事务概念)

1.1、什么事务?

事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操 作都失败。

典型场景:银行转账。

1.2、事务四个特性(ACID)

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

2、事务操作(搭建事务操作环境)

在这里插入图片描述

2.1、创建数据库表,添加记录

CREATE TABLE t_account(
	id int PRIMARY KEY NOT NULL,
	username VARCHAR(50),
	money int
);

INSERT INTO t_account VALUES
(1, "lucy", 1000),
(2, "mary", 1000);

mysql> select * from t_account;
+----+----------+-------+
| id | username | money |
+----+----------+-------+
|  1 | lucy     |  1000 |
|  2 | mary     |  1000 |
+----+----------+-------+
2 rows in set (0.00 sec)

2.2、创建 service,搭建 dao,完成对象创建和注入关系

(1)service 注入 dao,在 dao 注入 JdbcTemplate,在 JdbcTemplate 注入 DataSource

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import spring5.dao.UserDao;

@Service
public class UserService {
    //注入dao
    @Autowired
    private UserDao userDao;
    
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao{
    //注入 JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;
}

2.3、在 dao 创建两个方法:多钱和少钱的方法,在 service 创建方法(转账的方法)

@Repository
public class UserDaoImpl implements UserDao{
    //注入 JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;

    //lucy转账100给mary
    @Override
    public void addMoney() {
        String sql = "update t_account set money = money + ? where username = ?";
        jdbcTemplate.update(sql, 100, "mary");
    }

    //lucy转账100给mary
    @Override
    public void reduceMoncy() {
        String sql = "update t_account set money = money - ? where username = ?";
        jdbcTemplate.update(sql, 100, "lucy");
    }
}
@Service
public class UserService {
    //注入dao
    @Autowired
    private UserDao userDao;

    //转账的方法
    public void accountMoney() {
        //lucy少100
        userDao.reduceMoncy();
        //mary多100
        userDao.addMoney();
    }
}

测试代码:

@Test
public void test() {
    ApplicationContext context =
            new ClassPathXmlApplicationContext("bean1.xml");
    UserService userService = context.getBean("userService", UserService.class);

    userService.accountMoney();
}
mysql> select * from t_account;
+----+----------+-------+
| id | username | money |
+----+----------+-------+
|  1 | lucy     |   900 |
|  2 | mary     |  1100 |
+----+----------+-------+
2 rows in set (0.00 sec)

2.4、上面代码,如果正常执行没有问题的,但是如果代码执行过程中出现异常,有问题(事务引入)

//转账的方法
public void accountMoney() {
    //lucy少100
    userDao.reduceMoncy();
    
    //模拟异常
    int i = 3/0;
    
    //mary多100
    userDao.addMoney();
}

还原一下场景:

mysql> select * from t_account;
+----+----------+-------+
| id | username | money |
+----+----------+-------+
|  1 | lucy     |  1000 |
|  2 | mary     |  1000 |
+----+----------+-------+
2 rows in set (0.00 sec)

执行测试代码(肯定会报错),查看最后的数据库结果:

mysql> select * from t_account;
+----+----------+-------+
| id | username | money |
+----+----------+-------+
|  1 | lucy     |   900 |
|  2 | mary     |  1000 |
+----+----------+-------+
2 rows in set (0.00 sec)

上面问题如何解决呢?

  • 使用事务进行解决

事务操作的基本过程:

//转账的方法
public void accountMoney() {
    try {
        //1 开启事务
        
        //2 进行业务操作
        //lucy少100
        userDao.reduceMoncy();

        //模拟异常
        int i = 3/0;


        //mary多100
        userDao.addMoney();

        //3 没有异常,提交事务
    }catch (Exception e){
        //4 如果出现异常,事务回滚
    }
}

3、事务操作(Spring 事务管理介绍)

(1)事务添加到 JavaEE 三层结构里面 Service 层(业务逻辑层)

(2)在 Spring 进行事务管理操作

  • 有两种方式: 编程式事务管理和声明式事务管理(使用)

(3)声明式事务管理

  • 基于注解方式(使用)
  • 基于 xml 配置文件方式

(4)在 Spring 进行声明式事务管理,底层使用 AOP 原理

(5)Spring 事务管理 API

提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类:

在这里插入图片描述


4、事务操作(注解声明式事务管理)

(1)在 spring 配置文件配置事务管理器

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

(2)在 spring 配置文件,开启事务注解

  1. 在 spring 配置文件引入名称空间 tx

    <?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">
    
  2. 开启事务注解

    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    
  3. 在 service 类上面( 或者 service 类里面方法上面)添加事务注解

    • @Transactional,这个注解添加到类上面,也可以添加方法上面
    • 如果把这个注解添加类上面,这个类里面所有的方法都添加事务
    • 如果把这个注解添加方法上面,为这个方法添加事务
    @Service
    @Transactional
    public class UserService {
        //注入dao
        @Autowired
        private UserDao userDao;
    
        //转账的方法
        public void accountMoney() {
    //        try {
                //1 开启事务
    
                //2 进行业务操作
                //lucy少100
                userDao.reduceMoncy();
    
                //模拟异常
                int i = 3/0;
    
    
                //mary多100
                userDao.addMoney();
    
                //3 没有异常,提交事务
    //        }catch (Exception e){
                //4 如果出现异常,事务回滚
    //        }
        }
    }
    

测试代码:

mysql> select * from t_account;
+----+----------+-------+
| id | username | money |
+----+----------+-------+
|  1 | lucy     |  1000 |
|  2 | mary     |  1000 |
+----+----------+-------+
2 rows in set (0.00 sec)

5、事务操作(声明式事务管理参数配置)

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

在这里插入图片描述

  • propagation:事务传播行为

    多事务方法直接进行调用,这个过程中事务是如何进行管理的。

    在这里插入图片描述

在这里插入图片描述

@Service
@Transactional(propagation = Propagation.REQUIRED)
public class UserService {
    ...
}        
  • ioslation:事务隔离级别

    (1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题

    (2)有三个读问题:脏读、不可重复读、虚(幻)读

    (3)脏读:一个未提交事务读取到另一个未提交事务的数据

    (4)不可重复读:一个未提交事务读取到另一提交事务修改数据

    (5)虚读:一个未提交事务读取到另一提交事务添加数据

    (6)解决: 通过设置事务隔离级别,解决读问题

    在这里插入图片描述

    @Service
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
    public class UserService {
        ...
    }        
    
  • timeout:超时时间

    (1)事务需要在一定时间内进行提交,如果不提交进行回滚

    (2)默认值是 -1 ,设置时间以秒单位进行计算

  • readOnly:是否只读

    (1)读:查询操作,写:添加修改删除操作

    (2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作

    (3)设置 readOnly 值是 true,设置成 true 之后,只能查询

  • rollbackFor:回滚

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

  • noRollbackFor:不回滚

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

@Service
@Transactional(readOnly = false, timeout = -1, propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
public class UserService {
    ...
}

6、事务操作(完全注解声明式事务管理)

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

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration  //配置类
@ComponentScan(basePackages = "spring5")
@EnableTransactionManagement //开启事务
public class TxConfig {
    //创建数据库的连接池
    @Bean
    public DruidDataSource getDruidDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://10.150.104.5:3306/user_db");
        dataSource.setUsername("root");
        dataSource.setPassword("Opfordream@0518");
        return dataSource;
    }

    //创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //注入dataSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    //创建事务管理器的对象
    @Bean
    public DataSourceTransactionManager getdataSourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

测试代码:

@Test
public void test2() {
    ApplicationContext context =
            new AnnotationConfigApplicationContext(TxConfig.class);
    UserService userService = context.getBean("userService", UserService.class);

    userService.accountMoney();
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值