IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 请你谈谈spring事务的理解-1? -> 正文阅读

[Java知识库]请你谈谈spring事务的理解-1?

1 事务的概念

事务:是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元) ;通俗点说就是为了达到某个目的而做的一系列的操作要么一起成功 (事务提交),要么一起失败(事务回滚)。

2 事务的四大特性

1(Atomicity)原子性 :事务是最小的执行单位,不允许分割。原子性确保动作要么全部完成,要么完全不起作用;
2(Consistency)一致性:一致性代表了底层数据存储的完整性, 事务系统通过保证事务的原子性,隔离性和持久性来满足这一要求执行事务前后,数据保持一致;
3(Isolation)隔离性: 并发访问数据库时,一个事务不被其他事务所干扰。
4(Durability)持久性: 一个事务被提交之后,对数据库中数据的改变是持久的,即使数据库发生故障。

3 事务的隔离级别

在这里插入图片描述
脏读:事务A读取了事务B中尚未提交的数据。如果事务B回滚,则A读取使用了错误的数据。
不可重复读:对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值。这是由于在查询期间,这个数据被另一个事务修改并提交了。【更新操作】
幻读: 在事务A多次读取构成中,事务B对数据进行了新增操作,导致事务A多次读取的数据不一致。【增删】

第一类事物丢失: (称为回滚丢失):A和B同时在执行一个数据, 然后B事物已经提交了,然后A事物回滚了,这样B事物的操作就因A事物回滚而丢失了。
第二类事物丢失: (提交覆盖丢失):也称为覆盖丢失,就是A和B一起执行一个数据,两个同时取到一个数据,然后B事物首先提交,但是A事物又提交,这样就覆盖了B事物。

Read uncommitted
读未提交,顾名思义,就是一个事务可以读取另-个未提交事务的数据,会产生脏读。
Read committed
读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据,会产生不可重复读。
Repeatable read
重复读,就是在开始读取数据(事务开启)时,不再允许修改操作,可能会产生幻读。
Serializable
Serializable是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

4 spring怎么配置事务

在这里插入图片描述

package com.zs.pojo;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
    private Integer id;
    private String name;
    private String money;
}
package com.zs.mapper;
@Repository
public class UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void out(String fromName, Integer money) {
        String sql = "update user set money = money - ? where name = ? ";
        jdbcTemplate.update(sql, money, fromName);
    }
    public void in(String toName, Integer money) {
        String sq1 ="update user set money = money + ? where name = ?";
        jdbcTemplate.update(sq1, money, toName) ;
    }
}
package com.zs.service;
@Service
public class UserService {
    @Autowired
    private UserDao userDA0;

    public void transfer(String fromName, String toName, Integer money) {
        userDA0.out(fromName, money);
        int x = 10;
        if (x == 10)
            throw new RuntimeException("出错啦! ");
        userDA0.in(toName, money);
    }
}

spring-dao.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:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       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/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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

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

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mp?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <bean class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>
package com.zs.test;
public class TestBean {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserService userService = (UserService) context.getBean(UserService.class);
        userService.transfer("Tom", "Jerry", 100);
    }
}

测试中,出现的问题:

int x = 10;
if (x == 10)
	throw new RuntimeException("出错啦! ");

在这里插入图片描述

int x = 1;
if (x == 10)
	throw new RuntimeException("出错啦! ");

在这里插入图片描述

5 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:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       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/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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

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

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mp?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

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

    <!-- 配置事务模板对象 -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

package com.zs.config;
@ComponentScan("com.zs")
@Configuration
public class AppConfig {
    @Bean
    public TransactionTemplate transactionTemplate(DataSourceTransactionManager transactionManager) {
        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(transactionManager);
        return transactionTemplate;
    }
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/mp?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
}
package com.zs.service;
@Service
public class UserService {
    @Autowired
    private UserDao userDAO;
    @Autowired
    private TransactionTemplate transactionTemplate;
    public void transfer(String fromName, String toName, Integer money) {
        transactionTemplate.execute(status -> {
            userDAO.out(fromName, money);
            int a = 1 / 0;
            userDA0.in(toName, money);
            return null;
        });
    }
}

6 AspectJ申明式事务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:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       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/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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

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

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mp?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

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

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--基于AspectJ申明式事务XML配置方式-->
    <!-- 定义一个增强-->
    <tx:advice id="txAdvice"
               transaction-manager="transactionManager">
        <!--增强(事务)的属性的配置-->
        <tx:attributes>
            <tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--aop配置定义切面和切点的信息-->
    <aop:config>
        <!--定义切点:哪些类的哪些方法应用增强-->
        <aop:pointcut
              expression="execution(* com.zs.service..*.*(..))"
              id="mypointcut"/>
        <!--定义切面: -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="mypointcut" />
    </aop:config>
</beans>

package com.zs.service;
@Service
public class UserService {
    @Autowired
    private UserDao userDA0;
    public void transfer(String fromName, String toName, Integer money) {
        userDA0.out(fromName, money);
        int a = 1 / 0;
        userDA0.in(toName, money);
    }
}

7 申明式事务注解配置方式

package com.zs.config;
@ComponentScan("com.zs")
@EnableTransactionManagement // 开启注解事务
public class AppConfig {
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/mp?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;

    }
}
package com.zs.service;

@Service
public class UserService {
    @Autowired
    private UserDao userDA0;
    @Transactional
    public void transfer(String fromName, String toName, Integer money) {
        userDA0.out(fromName, money);
        int a = 1 / 0;
        userDA0.in(toName, money);
    }
}

package com.zs.test;
public class TestBean {
    @Test
    public void test() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userService = context.getBean(UserService.class);
        userService.transfer("Tom", "Jerry", 100);
    }
}

8 事务的传播特性

所谓事务传播机制,也就是在事务在多个方法的调用中是如何传递的,是重新创建事务还是使用父方法的事务?父方法的回滚对子方法的事务是否有影响?这些都是可以通过事务传播机制来决定的。

事务传播行为常量都是以PROPAGATION_ 开头,形如PROPAGATION_XXX。
在这里插入图片描述

在这里插入图片描述
1)REQUIRED
定义:如果有事务则加入事务,如果没有事务,则创建一个新的(默认值)

  • 操作1:将BlogServiceImpl和BlogServiceImpl2的事务传播机制都修改为
    @Transactional(propagation=Propagation.REQUIRED)

在这里插入图片描述

  • 操作2:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.REQUIRED)

在这里插入图片描述

  • 总结:当BlogServiceImpl提供事务的时候,BlogServiceImpl2的方法执行使用当前已有事务,不再新建事务;当BlogServiceImpl不创建事务的时候,BlogServiceImpl2的方法执行发现没有事务可用,自己新建事务;

2)NOT_SUPPORTED
定义:Spring不为当前方法开启事务,相当于没有事务

  • 操作:将BlogServiceImpl和BlogServiceImpl2的事务传播机制都
    修改为@Transactional(propagation=Propagation.NOT_SUPPORTED)

在这里插入图片描述
总结:NOT_SUPPORTED相当于没有Spring事务,每条执行语句单独执行,单独提交

3)REQUIRES_NEW
定义:不管是否存在事务,都创建一个新的事务,原来的事务挂起,新的方法执行完毕后,继续执行老的事务

  • 操作:将BlogServiceImpl事务传播机制为@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的为@Transactional(propagation=Propagation.REQUIRES_NEW)
    在这里插入图片描述
    总结:REQUIRES_NEW为当前方法创建一个新的事务,并且当前事务先提交,然后再提交老的事务

4)MANDATORY
定义:必须在一个已有的事务中执行,否则报错

  • 操作:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.MANDATORY),查看是否报错
    在这里插入图片描述
    总结:MANDATORY必须在已有事务下被调用,否则报错;NOT_SUPPORTED执行数据库层面的事务操作,故当前测试中,insert方法成功执行,delete方法的抛错并不影响insert方法的执行

5)NEVER
定义:必须在一个没有的事务中执行,否则报错

  • 操作:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.NEVER),查看是否报错
    在这里插入图片描述
    6)SUPPORTS
    定义:如果其他bean调用这个方法时,其他bean声明了事务,则就用这个事务,如果没有声明事务,那就不用事务

  • 操作1:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.SUPPORTS)

在这里插入图片描述

  • 操作1:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.SUPPORTS)
    在这里插入图片描述
    总结: SUPPORTS类型的事务传播机制,是否使用事务取决于调用方法是否有事务,如果有则直接用,如果没有则不使用事务

    7)NESTED
    定义:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作

  • 操作1:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.NESTED)

在这里插入图片描述

  • 操作2:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.NESTED)
    在这里插入图片描述
    总结:save方法创建一个事务,则再调用delete方法时,直接在该事务的基础上创建一个嵌套事务,本质上还是同一个事务,做一次提交;save方法不创建事务,则调用delete方法时,直接创建一个新的事务,单独提交。

  • 1)REQUIRED
    当两个方法的传播机制都是REQUIRED时,如果一旦发生回滚,两个方法都会回滚

  • 2)REQUIRES_NEW
    当delete方法传播机制为REQUIRES_NEW,会开启一个新的事务,并单独提交事务,所以save方法的回滚并不影响delete方法事务提交

  • 3)NESTED
    当save方法为REQUIRED,delete方法为NESTED时,delete方法开启一个嵌套事务;
    当save方法回滚时,delete方法也会回滚;反之,如果delete方法回滚,则并不影响save方法的提交

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-11 21:59:56  更:2022-03-11 22:01:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:52:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码