Spring5-事务学习

Spring5_事务学习

1.事务概念

1.1什么是事务

事务是数据库操作的基本单元,逻辑上一组操作,一组操作为一个整体,要么都成功,如果有其中一个操作失败,则所有操作都失败

2.2事务的四个特征 (ACID)

  1. 原子性:事务要么都成功,要么都失败。
  2. 一致性:保证事务只能把数据库从一个有效(正确)的状态“转移”到另一个有效(正确)的状态。
  3. 隔离性:多事务操作时,不会相互影响
  4. 持久性:在事务提交之后,表中数据真正发生变化

2.事务操作(搭建事务操作环境-idea)

以银行转账为例
张三转账100元给李四
张三少100元,李四多100元
、银行转账

2.1 创建数据库,添加记录

-- 创建一个表t_account
CREATE TABLE t_account(
id INT PRIMARY KEY,
username VARCHAR(20),
money INT
);

-- 向表中添加数据
INSERT INTO t_account VALUES 
(1,'张三',1000),
(2,'李四',1000);

数据库

2.2配置bean.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: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.ccby.spring5"></context:component-scan>

    <!--数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456abcd"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>

    <!--JdbcTemplate 对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入DataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>

2.3创建service ,搭建dao,完成对象创建和注入

目录结构

@Service
public class UserService {

    //注入dao
    @Autowired
    private UserDao userDao;
}
@Repository
public class UserDaoImpl implements UserDao {

    //注入JdbcTemplate
    private JdbcTemplate jdbcTemplate;
}

2.4在dao创建:转入和转出的方法;在service创建转账的方法

@Repository
public class UserDaoImpl implements UserDao {

    //注入JdbcTemplate
    private JdbcTemplate jdbcTemplate;


    //张三转账100给李四
    /**
     * 转入
     */
    @Override
    public void addMoney() {
        String sql = "update t_account set money = money-? where username = ?";
        jdbcTemplate.update(sql, 100, "张三");
    }

    /**
     * 转出
     */
    @Override
    public void reduceMoney() {
        String sql = "update t_account set money = money+? where username = ?";
        jdbcTemplate.update(sql, 100, "李四");
    }
}
//转账
    public void accountMoney() {
        userDao.reduceMoney();
        userDao.addMoney();
    }

3.Spring 事务管理介绍

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

  2. 在Spring进行事务管理操作(两种方式)

    (1) 编程式业务管理
    (2) 声明式业务管理 (使用)

  3. 声明式业务管理
    (1)基于注解方式 (使用)
    (2)基于xml配置文件方式

  4. 在Spring进行声明式业务管理,底层使用Aop原理

  5. Spring事务管理API
    提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类 (PlatformTransactionManager)

4.注解声明式事务管理

4.1 在spring配置文件中配置事务管理器

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

4.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: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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
  2. 开启事务注解

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

    1. @Transactional,这个注解添加到类上面,也可以添加到方法上面
    2. 如果把这个注解添加到类上面,这个类里面所有的方法都添加事务
    3. 如果把这个注解添加到方法上面,为这个方法添加事务
@Service
@Transactional
public class UserService {

    //注入dao
    @Autowired
    private UserDao userDao;

    //转账
    public void accountMoney() {
        userDao.reduceMoney();

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

        userDao.addMoney();
    }
}
@Test
    public void test1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();

    }

事务成功回滚

5. 声明式事务管理参数配置

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

在这里插入图片描述

  • propagation:事务传播行为

    • 多事务方法直接调用。(事务方法:对数据库表数据进行变化操作)

    • Spring定义了7种类传播行为

    • 传播属性描述举例
      REQUUIRED如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新事务,并在自己的事务内运行如果说,当前方法(方法1)本身有事务,调用一个没有事务的方法(方法2),则方法2使用方法1中的事务;如果方法1本身没有事务,调用方法2之后,创建新事务
      REQUIRED_NEW当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起使用方法1调用方法2,无论方法1是否有事务,都创建新的事务
      SUPPORTS如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务内
      NOT_SUPPORTS当前的方法不应该运行在事务中,如果有事务,将它挂起
      MANDATORY当前的方法必须运行在事务内,如果没有正在运行的的事务,就抛出异常
      NEVER当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
      NESTED如果有事务在运行,当前的方法就应该在这个事物的嵌套事务内运行,否则就启动一个新事务,并在它自己的事务内运行
  • isolation:事务隔离级别

    • 事务有特性称为隔离性,多事务操作之间不会产生运行,不考虑隔离性会产生:脏读、不可重复读、幻读

      • 脏读:一个未提交事务读取到了另外一个未提交事务的值 (事务1读取到事务2改变的数据,此时事务2回滚,但是事务1中的数据还为事务2改变的数据)
      • 不可重复读:同一次事务前后查询到的数据不一致
      • 幻读:一个未提交事务读取到另一提交事务添加(删除)数据(一次事务中前后数据量发生变化,用户产生不可预料的问题)
    • 提供设置事务隔离级别,解决读问题

      脏读不可重复读幻读
      READ UNCOMMITTED (只读未提交)
      READ COMMITTED (读以提交)
      REPEATABLE READ (可重复读)
      SERIALIZABLE (串行化)
  • timeout:超时时间

    • 事务需要在一定时间内进行提交,如果不提交进行回滚,设置时间以秒为单位
  • readOnly:是否只读

    • 默认值为false,若设置成true后,只可以查询
  • rollbackFor:回滚

    • 可设置出现哪些异常进行回滚
  • noRollbackFor:不回滚

    • 可设置出现哪些异常不进行回滚

6.XML声明式事务管理

6.1在spring配置文件中进行配置

  1. 配置事务管理器
  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: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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--组件扫描-->
    <context:component-scan base-package="com.ccby.spring5"></context:component-scan>

    <!--数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql:///user_db"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456abcd"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </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">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--2.配置通知-->
    <tx:advice id="tx_advice">
        <!--配置事务参数-->
        <tx:attributes>
            <!--指定哪种规则的方法上面添加事务-->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
            <!--以account开头的方法 <tx:method name="account*" />-->
        </tx:attributes>
    </tx:advice>
    
    <!--配置切入点和切面-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="tx_advice" pointcut-ref="pt"></aop:advisor>
    </aop:config>
</beans>

7. 完全注解声明式管理事务

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

package com.ccby.spring5.config;

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 = "com.ccby.spring5") //组件扫描
@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("123456abcd");
        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;
    }
}

//测试
@Test
    public void test2() {
        ApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值