首页 > 编程语言 >Java-SpringAop 编程式事物实现

Java-SpringAop 编程式事物实现

时间:2024-03-19 23:34:57浏览次数:23  
标签:Java int 事物 编程 PROPAGATION SpringAop 允许 数据库 READ

SpringAop 编程式事物实现

1. 数据库事物特性
  • 原子性

多个数据库操作是不可分割的,只有所有的操作都执行成功,事物才能被提交;只要有一个操作执行失败,那么所有的操作都要回滚,数据库状态必须回复到操作之前的状态

  • 一致性

事物操作成功后,数据库的状态和业务规则必须一致。例如:从A账户转账100元到B账户,无论数据库操作成功失败,A和B两个账户的存款总额是不变的。

  • 隔离性

当并发操作时,不同的数据库事物之间不会相互干扰(当然这个事物隔离级别也是有关系的)

  • 持久性

事物提交成功之后,事物中的所有数据都必须持久化到数据库中。即使事物提交之后数据库立刻崩溃,也需要保证数据能能够被恢复。

2.事物隔离级别

当数据库并发操作时,可能会引起脏读、不可重复读、幻读、第一类丢失更新、第二类更新丢失等现象。

  • 脏读

事物A读取事物B尚未提交的更改数据,并做了修改;此时如果事物B回滚,那么事物A读取到的数据是无效的,此时就发生了脏读。

  • 不可重复读

一个事务执行相同的查询两次或两次以上,每次都得到不同的数据。如:A事物下查询账户余额,此时恰巧B事物给账户里转账100元,A事物再次查询账户余额,那么A事物的两次查询结果是不一致的。

  • 幻读

A事物读取B事物提交的新增数据,此时A事物将出现幻读现象。幻读与不可重复读容易混淆,如何区分呢?幻读是读取到了其他事物提交的新数据,不可重复读是读取到了已经提交事物的更改数据(修改或删除)

  • 第一类丢失更新

A事物的回滚覆盖了B事物已经提交的数据。如:账户有1000元,A事物执行取款100元操作,但未提交事物;此时B事物向账户存入100元并提交事物,账户余额改为1100元。此时A事物回滚了取款操作,账户余额被恢复成了1000元。

  • 第二类更新丢失

A事物的提交覆盖了B事物已经提交的数据。如:账户有1000元,A事物操作向账户存入100元,但未提交事物;此时B事物从账户取出100元并提交事物,账户余额改为900元;此时A事物提交事物,账户余额变为1100元。

对于以上问题,可以有多个解决方案,设置数据库事物隔离级别就是其中的一种,数据库事物隔离级别分为四个等级,通过一个表格描述其作用。

隔离级别脏读不可重复读幻象读第一类丢失更新第二类丢失更新
READ UNCOMMITTED允许允许允许允许允许
READ COMMITTED脏读允许允许允许允许
REPEATABLE READ不允许不允许允许不允许不允许
SERIALIZABLE不允许不允许不允许不允许不允许
3.Spring事物支持核心接口

在这里插入图片描述

TransactionDefinition–>定义与spring兼容的事务属性的接口

public interface TransactionDefinition {
    // 如果当前没有事物,则新建一个事物;如果已经存在一个事物,则加入到这个事物中。
    int PROPAGATION_REQUIRED = 0;
    // 支持当前事物,如果当前没有事物,则以非事物方式执行。
    int PROPAGATION_SUPPORTS = 1;
    // 使用当前事物,如果当前没有事物,则抛出异常。
    int PROPAGATION_MANDATORY = 2;
    // 新建事物,如果当前已经存在事物,则挂起当前事物。
    int PROPAGATION_REQUIRES_NEW = 3;
    // 以非事物方式执行,如果当前存在事物,则挂起当前事物。
    int PROPAGATION_NOT_SUPPORTED = 4;
    // 以非事物方式执行,如果当前存在事物,则抛出异常。
    int PROPAGATION_NEVER = 5;
    // 如果当前存在事物,则在嵌套事物内执行;如果当前没有事物,则与PROPAGATION_REQUIRED传播特性相同
    int PROPAGATION_NESTED = 6;
    // 使用后端数据库默认的隔离级别。
    int ISOLATION_DEFAULT = -1;
    // READ_UNCOMMITTED 隔离级别
    int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
    // READ_COMMITTED 隔离级别
    int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
    // REPEATABLE_READ 隔离级别
    int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
    // SERIALIZABLE 隔离级别
    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
    // 默认超时时间
    int TIMEOUT_DEFAULT = -1;
    // 获取事物传播特性
    int getPropagationBehavior();
    // 获取事物隔离级别
    int getIsolationLevel();
    // 获取事物超时时间
    int getTimeout();
    // 判断事物是否可读
    boolean isReadOnly();
    // 获取事物名称
    @Nullable
    String getName();
}

  1. Spring事物传播特性表:
传播特性名称说明
PROPAGATION_REQUIRED如果当前没有事物,则新建一个事物;如果已经存在一个事物,则加入到这个事物中
PROPAGATION_SUPPORTS支持当前事物,如果当前没有事物,则以非事物方式执行
PROPAGATION_MANDATORY使用当前事物,如果当前没有事物,则抛出异常
PROPAGATION_REQUIRES_NEW新建事物,如果当前已经存在事物,则挂起当前事物
PROPAGATION_NOT_SUPPORTED以非事物方式执行,如果当前存在事物,则挂起当前事物
PROPAGATION_NEVER以非事物方式执行,如果当前存在事物,则抛出异常
PROPAGATION_NESTED如果当前存在事物,则在嵌套事物内执行;如果当前没有事物,则与PROPAGATION_REQUIRED传播特性相同
  1. Spring事物隔离级别表:
隔离级别脏读不可重复读幻象读第一类丢失更新第二类丢失更新
ISOLATION_DEFAULT同后端数据库同后端数据库同后端数据库同后端数据库同后端数据库
ISOLATION_READ_UNCOMMITTED允许允许允许允许允许
ISOLATION_READ_COMMITTED脏读允许允许允许允许
ISOLATION_REPEATABLE_READ不允许不允许允许不允许不允许
ISOLATION_SERIALIZABLE不允许不允许不允许不允许不允许
  • PlatformTransactionManager–>Spring事务基础结构中的中心接口
public interface PlatformTransactionManager {
    // 根据指定的传播行为,返回当前活动的事务或创建新事务。
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
    // 就给定事务的状态提交给定事务。
    void commit(TransactionStatus status) throws TransactionException;
    // 执行给定事务的回滚。
    void rollback(TransactionStatus status) throws TransactionException;
}

Spring将事物管理委托给底层的持久化框架来完成,因此,Spring为不同的持久化框架提供了不同的PlatformTransactionManager接口实现。列举几个Spring自带的事物管理器:

事物管理器说明
org.springframework.jdbc.datasource.DataSourceTransactionManager提供对单个javax.sql.DataSource事务管理,用于Spring JDBC抽象框架、iBATIS或MyBatis框架的事务管理
org.springframework.orm.jpa.JpaTransactionManager提供对单个javax.persistence.EntityManagerFactory事务支持,用于集成JPA实现框架时的事务管理
org.springframework.transaction.jta.JtaTransactionManager提供对分布式事务管理的支持,并将事务管理委托给Java EE应用服务器事务管理器
  • TransactionStatus–>事物状态描述
  1. TransactionStatus接口
public interface TransactionStatus extends SavepointManager, Flushable {
    // 返回当前事务是否为新事务(否则将参与到现有事务中,或者可能一开始就不在实际事务中运行)
    boolean isNewTransaction();
    // 返回该事务是否在内部携带保存点,也就是说,已经创建为基于保存点的嵌套事务。
    boolean hasSavepoint();
    // 设置事务仅回滚。
    void setRollbackOnly();
    // 返回事务是否已标记为仅回滚
    boolean isRollbackOnly();
    // 将会话刷新到数据存储区
    @Override
    void flush();
    // 返回事物是否已经完成,无论提交或者回滚。
    boolean isCompleted();
}

  1. SavepointManager接口
public interface SavepointManager {
    // 创建一个新的保存点。
    Object createSavepoint() throws TransactionException;
    // 回滚到给定的保存点。
    // 注意:调用此方法回滚到给定的保存点之后,不会自动释放保存点,
    // 可以通过调用releaseSavepoint方法释放保存点。
    void rollbackToSavepoint(Object savepoint) throws TransactionException;
    // 显式释放给定的保存点。(大多数事务管理器将在事务完成时自动释放保存点)
    void releaseSavepoint(Object savepoint) throws TransactionException;
}
  1. Flushable接口
public interface Flushable {
    // 将会话刷新到数据存储区
    void flush() throws IOException;
}

4.Spring编程式事物

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `balance` int(11) DEFAULT NULL COMMENT '账户余额',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='--账户表'

实现

package com.lyc.cn.v2.day08;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.sql.DataSource;

/**
 * Spring编程式事物
 * @author: LiYanChao
 * @create: 2018-11-09 11:41
 */
public class MyTransaction {

    private JdbcTemplate jdbcTemplate;
    private DataSourceTransactionManager txManager;
    private DefaultTransactionDefinition txDefinition;
    private String insert_sql = "insert into account (balance) values ('100')";

    public void save() {

        // 1、初始化jdbcTemplate
        DataSource dataSource = getDataSource();
        jdbcTemplate = new JdbcTemplate(dataSource);

        // 2、创建物管理器
        txManager = new DataSourceTransactionManager();
        txManager.setDataSource(dataSource);

        // 3、定义事物属性
        txDefinition = new DefaultTransactionDefinition();
        txDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        // 3、开启事物
        TransactionStatus txStatus = txManager.getTransaction(txDefinition);

        // 4、执行业务逻辑
        try {
            jdbcTemplate.execute(insert_sql);
            //int i = 1/0;
            jdbcTemplate.execute(insert_sql);
            txManager.commit(txStatus);
        } catch (DataAccessException e) {
            txManager.rollback(txStatus);
            e.printStackTrace();
        }

    }

    public DataSource getDataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/my_test?useSSL=false&useUnicode=true&characterEncoding=UTF-8");
        dataSource.setUsername("root");
        dataSource.setPassword("liyanchao1989@");
        return dataSource;
    }

}

  • 增加Gradle模块和包
// 引入spring-jdbc模块
optional(project(":spring-jdbc"))// https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp
compile group: 'commons-dbcp', name: 'commons-dbcp', version: '1.4'// https://mvnrepository.com/artifact/mysql/mysql-connector-java
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.38'
  • 测试类及结果
package com.lyc.cn.v2.day08;

import org.junit.Test;

/**
 * @author: LiYanChao
 * @create: 2018-11-07 18:45
 */
public class MyTest {
    @Test
    public void test1() {
        MyTransaction myTransaction = new MyTransaction();
        myTransaction.save();
    }
}

运行测试类,在抛出异常之后手动回滚事物,所以数据库表中不会增加记录。

标签:Java,int,事物,编程,PROPAGATION,SpringAop,允许,数据库,READ
From: https://blog.csdn.net/lvyuanj/article/details/136820250

相关文章

  • Java
    该程序完整展示了一个类的基本构成类的名称:类的名称用于标识这个类,通常采用大驼峰命名法(首字母大写,单词间无空格)。成员变量(属性):成员变量是描述类的特征或属性的变量,用来表示类的状态。每个对象都有自己的一组属性值。成员方法(函数):成员方法定义了类的行为或功能,通过调......
  • java初体验———数组篇
        在编程的世界里,数组无疑是最基础且重要的一种数据结构。经过这段时间对数组的学习,我对其有了更深刻的理解和认识,也从中体会到了编程的魅力和乐趣。    数组的学习让我感受到了数据结构的魅力。数组作为一种线性数据结构,它的有序性和可索引性使得数据存储和......
  • JavaSE(上)-Day6
    JavaSE(上)-Day6数组数组的定义数组的初始化打印数组分析数组索引数组内存图方法方法的定义和调用方法的重载方法的内存图二维数组二位数组的创建和初始化二维数组的内存图数组1.数组是一种容器,可以一次存储多个相同类型的数据数组的定义 int[]array1;......
  • 组合设计模式Java代码快速开始
    组合模式介绍使用组合模式可以让用户可以使用统一的方式处理整个树形结构的个别对象和组合对象,从而简化客户端的操作。并且扩展性好当需要处理的对象是树形结构时可以考虑使用组合模式。节点和叶子节点存在很大差异的情况下不建议使用组合模式。代码举例不使用组合模式举例......
  • 史上最全Java核心面试题(带全部答案)2024年最新版
    今天要谈的主题是关于求职,求职是在每个技术人员的生涯中都要经历多次。对于我们大部分人而言,在进入自己心仪的公司之前少不了准备工作,有一份全面细致面试题将帮助我们减少许多麻烦。在跳槽季来临之前,特地做这个系列的文章,一方面帮助自己巩固下基础,另一方面也希望帮助想要换工......
  • 【Java】使用递归完成水仙花数
    总所周知,水仙花数没什么高速的数学解法,尤其是在不确定位数时。但暴力解法实在直接粗暴,为了更唬人代码美学(真的有那样的东西吗),我用递归写了个水仙花数。importjava.util.Scanner;publicclassMain{ staticintn; //算次幂 staticintpower(intNUM){ intn......
  • 简历管理系统java+springboot+vue
    简历管理系统1、功能介绍1.1、演示视频2、系统部分功能展示管理员功能模块用户管理功能模块模板类型管理报名招聘管理3、系统分析技术可行性操作可行性1、功能介绍本文以Java为开发技术,实现了一个简历管理系统。主要功能:管理员登录,通过填写用户名、密码、角色......
  • 前端基础之JavaScript的数据类型
    一、常用的调试语句方法说明示例归属alert(msg);警告,在浏览器中弹出一个警告框,内容为alert里面的内容alert("Surprise");浏览器closole.log(msg);控制台,在控制台内输出一些内容console.log("Surprise");浏览器prompt(问题,值);对话框,第一个参数是询问内......
  • 前端基础之JavaScript引入
    一、什么是JavaScriptJavaScript是一门跨平台、面向对象的脚本语言(不需要编译,直接解释运行即可),来控制网页的行为,它能使网页可交互。脚本语言:不需要编译,运行过程中由js解释器(js引擎)逐行来进行解释并执行。现在也可以基于Node.js技术进行服务器端编程W3C标准:网页主要由......
  • Java 编程实例:相加数字、计算单词数、字符串反转、元素求和、矩形面积及奇偶判断
    Java如何相加两个数字相加两个数字示例intx=5;inty=6;intsum=x+y;System.out.println(sum);//打印x+y的和输出11解释首先,声明两个int类型的变量x和y,并分别赋值为5和6。然后,使用+运算符将x和y相加,并将结果赋给变量sum。最后,使用Sy......