当前位置:   article > 正文

【Spring】spring事务配置_spring 事务配置

spring 事务配置

【Spring系列】IOC控制反转

【Spring系列】IOC操作bean管理(一)——bean管理实例详解

【Spring系列】IOC操作bean管理(二)——bean的生命周期、作用域

【Spring系列】IOC操作bean管理(三)——xml自动装配

【Spring系列】IOC操作bean管理(四)——引入外部属性文件

【Spring系列】IOC操作bean管理(五)——bean管理注解

【Spring系列】AOP详解

【Spring系列】JdbcTemplate操作数据库详解

【Spring系列】spring事务配置详解

【Spring系列】spring5框架新特性



一、事务基础

(一)概念

(1)事务是数据库操作最基本单元;
(2)事务指的是逻辑上一组操作,要么都成功,如果有任何一个失败,所有都失败;
(3)事务典型场景:银行转账;

(二)特性(ACID)

(1)原子性: 不可分割,只有操作都成功
(2)一致性: 操作前后总量不变
(3)隔离性: 并发操作,多个事务之间不会产生影响
(4)持久性: 当事务结束之后,数据库真正发生变化

(三)问题

  • 如果不考虑隔离性,将产生的读问题

(1)脏读: 两个事务都没有提交,但是都能看到对方事务的操作(致命问题);
(2)不可重复读: 一个事物提交了,另一个事务没有提交,但没有提交的这个事务能看到这个已经提交事务的操作(现象);
(3)幻(虚)读: 一个事务提交了,另一个事务没有提交,但没有提交的这个事务能看到这个已经提交事务的 添加 操作(现象);

(四)解决

(1)设置事务隔离级别

隔离级别脏读不可重复读幻读
Read Uncommitted(读未提交)
ReadCommitted(读已提交)
Repeatable Read(可重复读)
Serializable(串行化/不可并发)
  • Serializable 效率较低

(2)mysql默认隔离级别:repeatable read

二、spring事务配置

下面讲解一个转账的实例,来演示事务的配置过程

(一)搭建转账环境

(1)创建表

  • 转账表

表结构:
在这里插入图片描述

表数据:

在这里插入图片描述

在这里插入图片描述

(2)创建项目

  • 先创建service和dao,完成注入关系

dao类:

package com.springlearn.dao;

public interface UserDao {

    //转账——少钱的方法
    public void decrMoney();

    //转账—多钱的方法
    public void incrMoney();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

service类:

package com.springlearn.service;

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

/**
 * @program: SpringTX
 * @description:
 * @author: txg
 * @create: 2021-08-27 11:04
 **/

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    //转账的方法
    public void accountMoney(){
        //调用少钱的方法
        userDao.decrMoney();
        
        //调用多钱的方法
        userDao.incrMoney();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

dao的实现类:

package com.springlearn.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

/**
 * @program: SpringTX
 * @description:
 * @author: txg
 * @create: 2021-08-27 11:03
 **/

@Repository
public class UserdaoImpl implements UserDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    //转账——少钱的方法 Lucy少100
    @Override
    public void decrMoney() {
        String sql="update account set money=money-? where username=?";
        jdbcTemplate.update(sql,100,"lucy");
    }

    //转账——多钱的方法 mary多100
    @Override
    public void incrMoney() {
        String sql="update account set money=money+? where username=?";
        jdbcTemplate.update(sql,100,"mary");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

(3)测试类

package com.springlearn;

import com.springlearn.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @program: SpringTX
 * @description:
 * @author: txg
 * @create: 2021-08-27 11:04
 **/
public class Main {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

结果:
在这里插入图片描述

(二)事务管理

上面代码如果出现异常,会产生问题,我们可以使用事务解决

1:把事务添加service层
2:spring事务管理方式(2种)
第一种 :编程式事务管理(不使用)
第二种:声明式事务管理(使用这种方式)(2种)
  • ① 基于注解(常用)
  • ②基于xml配置文件
3:在Spring进行声明式事务管理,底层使用AOP原理
4:spring事务管理-事务管理器结构
  • 顶层接口是 PlatformTransactionManager
  • 在这个顶层接口下面有很多实现类,这些实现类针对不同操作数据库技术提供
  • 例如:如果操作数据库使用JdbcTemplate,会使用实现类 DataSourceTransactionManager

(1)声明式事务管理—基于注解

第一步:创建事务管理器对象
    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入DataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
第二步:开启事务注解
  • 让spring认识我们写的注解
	<!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
  • 1
  • 2
第三步:在service类上面添加事务注解
  • 添加注解 @Transactional
  • @Transactional注解可以添加到service类上面,和添加service里的方法上面,注解所添加位置的区别如下表:
位置特点
添加service类上面类里面所有方法都添加了事务
如果只是添加到了方法上面则只是添加注解的方法有事务
@Transactional
public class UserService {
	… …
}
  • 1
  • 2
  • 3
  • 4
重点一:补充 @Transactional注解的属性

(1)timeout:事务提交时间设置

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

(2)readonly:是否只读

  • 是否只能查询,读操作:查询;写操作:添加 修改 删除
  • 默认值为false,表示可以查询,可以添加修改删除操作
  • 设置readOnly值是true之后,只能查询

(3)rollBackFor:回滚

  • 设置出现哪些异常进行事务回滚
  • 默认为空

(4)noRollBackFor:不回滚

  • 设置出现哪些异常不进行事务回滚
  • 默认为空

(5)isolation:设置事务隔离级别 (☆)

  • mysql默认隔离级别 repeatable read

(6)propagation:设置事务传播行为 (☆)

  • 概念:事务方法之间调用过程中,事务是如何使用的

  • 事务方法: 改变数据库表数据的方法,添加修改删除
    例如: 添加方法里面调用修改方法,这个时候的事务如何使用,成为事务的传播行为

  • spring提供多种事务传播行为(七种)

第一种 REQUIRED 如果有事务,使用这个事务,如果没有事务,创建新事务
第二种 REQUIRED_NEW 都是创建新事务,如果之前有事务,不使用
第三种 SUPPORT 如果有事务,使用这个事务,如果没有事务,不使用事务

第四种 NOT_SUPPORT 不用事务
第五种 MANDATORY 如果有事务,使用这个事务,如果没有事务,就抛出异常
第六种 NEVER 如果没有事务,就正常运行,有事务就抛出异常
第七种 NESTED 如果有事务,就再嵌套一个事务在其中使用,如果没有事务,创建新事务
在这里插入图片描述


  • 示例:
@Service
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {
  • 1
  • 2
  • 3

重点二:补充 设计模式—策略模式

(1)个人所得税的例子

(2) spring事务管理配置中使用策略模式

spring事务管理使用顶层接口 PlatformTransactionManager

  • 在这个顶层接口里面有很多实现类
  • 这些实现类是针对不同的操作数据库技术提供的

(2)声明式事务管理—基于xml

配置较为复杂,需要多配置三个内容。具体配置如下:

1)配置事务管理器
2)配置增强通知
3)配置切入点
4)配置切面
<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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">

    <context:component-scan base-package="com.springlearn"></context:component-scan>

    <!--配置德鲁伊连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql:///tbl_test"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入DataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置增强(通知)-->
    <tx:advice id="txadvice">
        <tx:attributes>
            <!--配置对哪种规则的方法添加事务-->
            <tx:method name="account*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--配置切入点和切面-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="p" expression="execution(* com.springlearn.service.UserService.*(..))"/>
        <!--切面:把哪个增强用到哪个切入点-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="p"></aop:advisor>
    </aop:config>

    <!--创建jdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入数据源属性-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

(3)声明式事务管理—完全注解开发

使用配置类来代替xml配置文件:

@Bean注解的作用
1:让方法执行
2:让方法返回在spring进行注册(因为spring是通过bean来创建对象的,new的对象识别不到,所以需要注册spring才能识别到)

package com.springlearn.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;

/**
 * @program: SpringTX
 * @description:
 * @author: txg
 * @create: 2021-08-27 20:57
 **/

@Configuration
@ComponentScan(basePackages = {"com.springlearn"})  //开启组件扫描
@EnableTransactionManagement    //开启事务注解
public class SpringConfig {

    //创建德鲁伊连接池
    //@Bean作用
    //1:让方法执行  2:让方法返回在spring进行注册
    @Bean
    public DruidDataSource getDruidDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///test");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

这篇文章对你有帮助嘛!
欢迎提出宝贵的建议!
感谢阅读~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/995139
推荐阅读
相关标签
  

闽ICP备14008679号