【Spring】Spring事务和事务传播机制

在这里插入图片描述

文章目录

  • 什么是事务
  • 事务的操作
  • Spring 中事务的实现
    • Spring编程式事务
    • Spring 声明式事务 @Transactional
      • @Transactional作用
      • @Transactional 详解
        • rollbackFor
        • 事务隔离级别
        • Spring 事务隔离级别
        • Spring 事务传播机制

什么是事务

事务(Transaction)是一个程序中一系列严密的操作,所有操作执行必须成功完成,否则在每个操作所做的更改将会被撤销,这也是事务的原子性(要么成功,要么失败)。在计算机术语中,事务通常是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL、C++、Java)书写的用户程序的执行所引起,并用形如BeginTransaction和EndTransaction语句(或函数调用)来界定。

前面我们学习 MySQL 的时候,也为大家介绍了关于事务方面的知识,事务具有以下特性:

  1. 原子性(Atomicity):事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。原子性可以消除系统处理操作子集的可能性。
  2. 一致性(Consistency):事务在完成时,必须使所有的数据都保持一致状态。事务可以保证数据库的完整性,避免因各种原因而导致数据库的内容不一致,产生错误的数据。
  3. 隔离性(Isolation):事务处理过程中的中间状态对其他事务是透明的。事务隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
  4. 持续性(Durability):持续性是指事务一旦提交,它对数据库中数据的改变是永久性的。接下来的操作或故障不应对其有任何影响。

当我们在进行转账或者购物的时候,往往需要用到事务操作,为什么呢?假设我向别人转账 100 元,我钱已经转过去了,但是在对方接收的时候出现了问题,那么我自己账户上的余额少了 100,但是对方的账户上却没有收到我的 100,这种现象是绝对不可以出现的。有了事务的插足,如果在我们钱已经转出去了情况,但是在对方收的过程中发生问题的话,事务就会进行回滚,发出方的 100 元就不会扣掉。

事务的操作

事务的操作主要为下面三个部分:

  1. 开启事务:start transaction/begin(一组操作前开启事务)
  2. 提交事务:commit(这组操作全部成功,提交事务)
  3. 回滚事务:rollback(这组操作中间任何一个操作出现异常,并且这个异常没有被处理,就是回滚事务)

Spring 中事务的实现

在 Spring 中实现事务的方式有两种:

  1. 编程式事务(手动写代码操作事务)
  2. 声明式事务(利用注解自动开启事务和提交事务)

这篇文章为大家介绍事务,主要通过操作数据库的操作来体现,所以我们先准备两个表:

-- 创建数据库
DROP DATABASE IF EXISTS trans_test;
CREATE DATABASE trans_test DEFAULT CHARACTER SET utf8mb4;
-- 用户表
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (`id` INT NOT NULL AUTO_INCREMENT,`user_name` VARCHAR (128) NOT NULL,`password` VARCHAR (128) NOT NULL,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARACTER
SET = utf8mb4 COMMENT = '用户';-- 操作日志表
DROP TABLE IF EXISTS log_info;
CREATE TABLE log_info (`id` INT PRIMARY KEY auto_increment,`user_name` VARCHAR ( 128 ) NOT NULL,`op` VARCHAR ( 256 ) NOT NULL,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now()
) DEFAULT charset 'utf8mb4';

配置 MyBatis:

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/trans_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivermybatis:configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations: classpath:mapper/**Mapper.xml

为对应的表创建 model:

import lombok.Data;import java.util.Date;@Data
public class UserInfo {private int id;private String userName;private String password;private Date createTime;private Date updateTime;
}
import lombok.Data;import java.util.Date;@Data
public class LogInfo {private int id;private String userName;private String op;private Date createTime;private Date updateTime;
}

MyBatis 操作数据库:

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserInfoMapper {@Insert("insert into user_info (·user_name·,`password`) values (#{userName},#{password})")Integer insert(String userName, String password);
}
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface LogInfoMapper {@Insert("insert into log_info (`name`, `op`) values (#{name},#{op})")Integer insertLog(String name,String op);
}

Service 层:

import com.example.springtransaction.mapper.UserInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserInfoService {@Autowiredprivate UserInfoMapper userInfoMapper;public void registryUser(String name, String password) {userInfoMapper.insert(name, password);}
}
import com.example.springtransaction.mapper.LogInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class LogInfoService {@Autowiredprivate LogInfoMapper logInfoMapper;public void insertLog(String name, String op) {logInfoMapper.insertLog(name,op);}
}

Contoller 层:

import com.example.springtransaction.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/user")
@RestController
public class UserInfoController {@Autowiredprivate UserInfoService userInfoService;@RequestMapping("/registry")public String  registry(String name, String password) {userInfoService.registryUser(name, password);return "注册成功";}
}
import com.example.springtransaction.service.LogInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/log")
@RestController
public class LogInfoController {@Autowiredprivate LogInfoService logInfoService;@RequestMapping("/insert")public String insertLog(String name, String op) {logInfoService.insertLog(name, op);return "日志插入成功";}
}

Spring编程式事务

Spring 手动操作事务,有三个重要步骤:

  1. 开启事务(获取事务)
  2. 提交事务
  3. 回滚事务

在 Spring 中如何获取到事务呢?

要想获取到事务,我们需要借助 Spring 内置的两个对象:

  • DataSourceTransactionManager:事务管理器,用来获取事务(开启事务),提交或回滚事务
  • TransactionDefinition:事务的属性,在获取事务的时候需要将 TransactionDefinition 传递进去从而获得一个事务 TransactionStatus
import com.example.springtransaction.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/user")
@RestController
public class UserInfoController {@Autowiredprivate UserInfoService userInfoService;@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;@Autowiredprivate TransactionDefinition transactionDefinition;@RequestMapping("/registry")public String  registry(String name, String password) {//开启事务TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);userInfoService.registryUser(name, password);//提交事务dataSourceTransactionManager.commit(transactionStatus);return "注册成功";}
}

访问 127.0.0.1:8080/user/registry 之后,我们查看日志:

在这里插入图片描述

观察表可以发现数据插入成功:

在这里插入图片描述

这个是事务提交成功的日志,然后我们再来看看当事务回滚之后会出现什么日志:

//回滚事务
dataSourceTransactionManager.rollback(transactionStatus);

在这里插入图片描述
可以看到,当发生事务回滚的时候,就只有打开 sqlSession 和关闭 sqlSession 的操作,没有 commit 提交的操作,并且观察数据库可以发现,并没有插入数据:

在这里插入图片描述
通过编程式实现事务操作比较复杂,而使用声明式事务就简单很多。

Spring 声明式事务 @Transactional

Spring 声明式实现事务很简单,只需要加上 @Transactional 注解就可以实现了,无需手动开启和提交事务,进入方法的时候会自动开始事务,中途发生了未处理的异常就会自动回滚事务。跟前面的 AOP 统一功能处理是一样的,方法开始前干什么,结束后干什么,抛出异常后干什么。

import com.example.springtransaction.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/trans")
@RestController
public class TransactionalController {@Autowiredprivate UserInfoService userInfoService;@Transactional@RequestMapping("/registry")public String registry(String name, String password) {userInfoService.registryUser(name,password);return "注册成功";}
}

在这里插入图片描述
在这里插入图片描述
我们在这个方法中制造出异常,看是否会发生事务的回滚:

System.out.println(10/0);

在这里插入图片描述

没有提交事务就说明发生了事务的回滚。

在这里插入图片描述

@Transactional作用

@Transactional 可以修饰方法,也可以修饰类:

  • 修饰方法时:只有修饰 public 方法的时候才会生效(修饰其他权限的方法的时候不会报错,但是也不会生效)【推荐】
  • 修饰类时:对 @Transactional 修饰的类中所有的 public 方法都生效

当类/方法被 @Transactional 修饰的时候,在目标方法执行之前,就会自动开启事务,方法执行结束之后,会自动结束事务。但是如果在方法执行的过程中出现了异常,并且异常没有被正确捕获的话,就会进行事务的回滚操作;如果这个异常被成功捕获,那么方法就会被认为是正常执行,事务就会被正常提交。

我们对上面制造的异常进行捕获:

try {System.out.println(10/0);
} catch (Exception e) {e.printStackTrace();
}

在这里插入图片描述

事务被提交,并且数据库的插入操作成功:

在这里插入图片描述

如果我们想要自己控制事务的回滚,有两种方式可以达到:

(1)重新抛出异常:

try {System.out.println(10/0);
} catch (Exception e) {throw e;
}

在这里插入图片描述
在这里插入图片描述
(2)手动回滚事务:

首先我们需要通过 TransactionAspectSupport.currentTransactionStatus()方法来获取到当前事务,然后再调用 setRollbackOnly 进行事务的回滚操作:

try {System.out.println(10/0);
} catch (Exception e) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}

@Transactional 详解

上面我们了解了 @Transactional 的基本使用,那么接下来我们将详细学习一下 @Transactional 注解。

在这里插入图片描述
@Transactional 注解中的属性有很多,但是我们主要学习这三个属性:

  1. rollbackFor:异常回滚属性。指定能够触发事务回滚的异常类型,默认可以发生事务回滚的异常类型是 RuntimeException 及其子类以及 Error ,可以指定多个异常类型
  2. Isolation:事务的隔离级别。默认值为 Isolation.DEFAULT
  3. propagation:事务的传播机制。默认值为 Propagation.REQUIRED
rollbackFor

@Transactional 默认只会在发生运行时异常和 Error 的时候才会发生事务的回滚操作:

在这里插入图片描述
假设我们抛出的异常是非运行时异常:

try {System.out.println(10/0);
} catch (Exception e) {throw new IOException();
}

在这里插入图片描述
在这里插入图片描述

可以看到,当抛出的异常类型是非运行异常的时候,不会发生事务的回滚。

如果我们想指定,发生非运行异常的时候也能进行事务回滚的操作的话,我们就需要配置 @Transactional 注解中的 rollbackFor 属性:

@Transactional(rollbackFor = Exception.class)

在这里插入图片描述
抛出非运行时异常的时候,也进行了事务的回滚操作。

结论:

  • 在 Spring 的事务管理中,默认只在遇到运行时异常 RuntimeException 和 Error 的时候才会回滚
  • 如果需要回滚指定类型的异常,可以通过 rollbackFor 属性来指定
事务隔离级别

事务的隔离级别有下面几种:

  1. 未提交读(Read Uncommitted):最低的事务隔离级别,允许读取尚未提交的事务数据。这意味着可能会出现脏读、不可重复读和幻读的情况。
  • 该隔离级别可以读到其他事务未提交的数据,但是如果其他事务发生了事务回滚的话,那么我们读到的数据就是“脏数据”,这个问题被称为脏读
  1. 提交读(Read Committed):在事务执行过程中,只允许读取已经提交的数据。这样可以避免脏读问题,但仍然可能出现不可重复读和幻读。
  • 该隔离级别可以避免出现脏读的情况,但是由于该隔离级别可以读取到其他事务已提交的数据,所以在不同时间段读取到的数据可能是不同的,这种现象叫做不可重复读
  1. 可重复读(Repeatable Read):在这个级别中,事务在其生命周期内可以多次读取同一个数据,而不会看到其他事务对该数据的修改。这可以避免脏读和不可重复读问题,但仍然可能出现幻读。
  • 假设该事务级别的事务正在读取数据,并且在此期间,其他事务又插入了新的数据,因为该隔离级别下读取到的数据都是一样的,所以就无法读取到新插入的这条数据,当前事务再插入这条数据的时候,因为唯一主键的约束,就无法成功插入,,但是在当前事务中又查询不到这条数据,又插入不成功,所以就出现了幻读的情况
  1. 可串行化(Serializable):最高的事务隔离级别,通过强制事务串行执行,避免了脏读、不可重复读和幻读问题。但这种级别的性能开销较大,因为事务必须串行执行。

给大家举个例子:假设我要考试了,但是考试前两天我去老师办公室叫作业,我看见老师电脑上显示的是 2024年高数期末考试试卷草稿,所以我就将试卷给拍了下来,然后回到了寝室就只琢磨复习试卷上出现的题目就,等到考试那天我信心满满的走进考场,但是当我看到试卷的那一刻,我懵了,很多题目都不一样。这是因为我那天看到的只是草稿,在我走后老师又对其进行了修改,这就是脏读的问题。

假设我工厂生产机器,要生产两批不同的机器,A机器生产100台,B机器生产50台,先生产的是 A 机器,我按照给定的图纸来制造,当制造了 95 台 A 机器的时候,上面就将 B 机器的图纸传过来了,但是我不知道,我知道的就是按照图纸来造,这样就导致了 A 机器制造的数量不够,这就是不可重复读的问题。

假设公司让我们一个团队的人进行数据库的增加操作,我的操作就是先查询一遍数据库,看看还有那些数据需要插入,然后我后面插入的时候也是看第一遍查询的结果吗,这样我一个人做的话,是不会出现什么问题的,但是如果跟我同一个团队的人也在执行同样的操作的话,他插入了我将要插入的数据,但是我还是按照第一编查询的结果来,那么这个数据就不能成功插入,我再查询,还是第一遍的结果,我说这条数据我没插入啊,为什么插入不进去呢?这就是幻读的问题。

事务隔离级别脏读不可重复读幻读
读未提交
读已提交×
可重复读××
串行化×××

随着隔离级别的提高,效率也会降低。

Spring 事务隔离级别

Spring 中事务隔离级别有五种:

  1. Isolation.DEFAULT:以连接的数据库事务隔离级别为主
  2. Isolation.READ_UNCOMMITTED:读未提交,对应SQL标准的 READ UNCOMMIT
  3. Isolation.READ_COMMITTED:读已提交,对应SQL标准的 READ COMMIT
  4. Isolation.REPEATABLE_READ:可重复读,对应SQL标准的REPEATABLE READ
  5. Isolation.SERIALIZABLE:串行化,对应SQL标准的SERIALIZABLE

在这里插入图片描述

Spring 中隔离级别的配置需要配置 @Transactional 注解的 isolation 属性:

@Transactional(rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ)
Spring 事务传播机制

什么是事务传播机制?

事务传播机制是指当一个事务(父事务)调用另一个事务(子事务)的方法时,子事务如何传播的事务处理机制。它主要解决的是在多个事务方法相互调用时,如何决定使用哪个事务上下文以及如何管理这些事务的执行顺序和隔离级别。

事务隔离级别解决的是多个事务同时调用一个数据库的问题

在这里插入图片描述
而事务传播机制解决的是一个事务在多个节点(方法)中传递的问题

在这里插入图片描述
Spring 中的事务传播机制有7种:

  1. Propagation.REQUIRED:默认的事务传播机制。如果当前存在事务,则加入该事务;如果没有事务,则创建一个新事务
  2. Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果不存在事务,则以非事务的方式继续运行
  3. Propagation.MANDATORY:强制性。如果当前存在事务,则加入该事务,如果不存在,则抛出异常
  4. Propagation.REQUIRES_NEW:创建一个新的事务。如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法都是新开始自己的事务,且开启的事务相互独立,互不干扰
  5. Propagation.NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起(不用)
  6. Propagation.NEVER:以非事务方式运行,如果当前存在事务,则抛出异常
  7. Propagation.NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 Propagation.REQUIRED

在这里插入图片描述

对于上面的事务传播机制,我这里主要为大家说明两种:

  1. REQUIRED(默认值)
  2. REQUIRES_NEW

这里我们在 controller 层和 service 层都加上这个注解 @Transactional(propagation = Propagation.REQUIRED)

@RequestMapping("/trans")
@RestController
public class TransactionalController {@Autowiredprivate UserInfoService userInfoService;@Autowiredprivate LogInfoService logInfoService;@Transactional(rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)@RequestMapping("/registry")public String registry(String name, String password) throws IOException {userInfoService.registryUser(name,password);logInfoService.insertLog(name,"注册");return "注册成功";}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在其中一个事务中制造异常:

@Transactional(propagation = Propagation.REQUIRED)
public void registryUser(String name, String password) {userInfoMapper.insert(name, password);System.out.println(10/0);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,当事务传播机制为 Propagation.REQUIRED 的时候,当其中任何一个事务出现异常的时候,整个事务都会执行事务回滚的操作。

再来看看 Propagation.REQUIRED_NEW 隔离级别:

@Transactional(propagation = Propagation.REQUIRES_NEW)

还是 userInfoService 中抛出异常:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到 Propagation.REQUIRED_NEW 隔离级别中的事务都是相互独立的,互不影响。

将隔离级别改为 NEVER

在这里插入图片描述
当隔离级别为 NEVER 的时候,如果当前存在事务,就会直接报错。

NESTES 隔离级别

在这里插入图片描述
使用嵌套 NESTED 隔离级别,当其中一个事务抛出异常之后,所有事务都会回滚。

但是这样不就和 REQUIRED 隔离级别是一样的吗?这样看确实一样,但是还是有区别的:

我们将出现错误的事务单独进行回滚:

@Transactional(propagation = Propagation.NESTED)
public void registryUser(String name, String password)throws RuntimeException {userInfoMapper.insert(name, password);try {System.out.println(10/0);}catch (Exception e) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后将隔离级别改为 REQUIRED:

在这里插入图片描述
整个事务都回滚了。

所以 REQUIRED 和 NESTED 隔离界别的区别:

  • 整个事务如果都执行成功,二者的结果是一样的
  • 如果事务一部分执行成功,REQUIRED 加入事务会导致整个事务回滚,NESTED 嵌套事务可以实现局部回滚,不会影响上一个方法的执行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/670455.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【vue-baidu-map】百度地图组件,实现精准搜索,当前定位功能

实现效果&#xff1a; 代码如下&#xff1a; //引入地图组件 <bmap ref"bmap" map-confirm"confirmPosition" />confirmPosition() {const _this this.$refs.bmapconst center _this.centervar point center.lng , center.latconsole.log(阀控…

JavaEE作业-实验一

目录 1 实验内容 2 思路 3 核心代码 &#xff08;1&#xff09;前端核心代码&#xff1a; &#xff08;2&#xff09;后端核心代码&#xff1a; 4 实验结果 1 实验内容 用Servlet JSP JavaBean实现登录功能 2 思路 ①建好web项目,创建数据库 ②建立两个简单的前端页…

HarmonyOS Next开发----k线图滑动问题

前言 最近做股票软件鸿蒙版本的适配&#xff0c;K线趋势图的手势交互上遇到了问题&#xff0c;这里记录下~ 功能需求&#xff1a; 实现k线趋势图滑动及fling的效果 思路&#xff1a; 1. 借鉴Flutter版本的思路&#xff0c;在K线趋势图上面叠加一个Scroll布局&#xff0c;使…

parted命令进行磁盘分区

1.使用lsblk 查看可用的磁盘 可以看到有sdb sdc两个物理盘还未挂载 2.使用parted命令分区(以sdb为例) 按需要把sdb分成4个逻辑分区 新建磁盘标签类型为gpt 出现提示,输入yes 开始分区: (1)输入mkpart回车,提示输入分区名称,按习惯可命名为sdb1(后面依次sdb2、sdb3)…

部署篇 | MatrixOne与MySQL全面对比

MatrixOne是一款高度兼容MySQL语法的HTAP数据库&#xff0c;在大部分场景下可以直接实现对MySQL的替换。 作为一款开源数据库&#xff0c;MatrixOne 选用对开发者友好的 Apache-2.0 License&#xff0c;支持在主流的 Linux 和 MacOS 系统中直接进行物理部署。在部署方式上&…

JVM 性能调优 - 参数基础(2)

查看 JDK 版本 $ java -version java version "1.8.0_151" Java(TM) SE Runtime Environment (build 1.8.0_151-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode) 查看 Java 帮助文档 $ java -help 用法: java [-options] class [args...] …

Python中的for循环用法详解,一文搞定它

文章目录 for循环1.for循环的基本语法&#xff08;1&#xff09;遍历不等长多级容器&#xff08;2&#xff09;遍历不等长多级容器&#xff08;3&#xff09;遍历等长的容器 2.变量的解包3.for...else【详细讲解】4.range对象5.总结6.打印 1 ~ 10 跳过57.打印菱形小星星 for循环…

Flink 动态表 (Dynamic Table) 解读

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

docer compose部署simple-docker

简介 一个看似简陋但是功能足够用的docker管理工具 安装 创建目录 mkdir -p /opt/simple-docker cd /opt/simple-docker 创建并启动容器 编写docker-compose.yml文件,内容如下 version: 3 services: redis: image: redis:latest restart: always web: image: registry.cn-…

HR看了都想点开的简历:吸睛模板+撰写技巧

工作致富的第一步&#xff1a;写一份好的简历。一个独特、简单、清晰的个人简历模板可以更好地吸引雇主的注意和兴趣&#xff0c;并帮助你在许多求职者中脱颖而出。如何制作一份令人印象深刻的简历&#xff1f;巧妙地使用个人简历模板是一个不错的选择。在本文中&#xff0c;我…

线性代数:矩阵的初等变换

目录 一、初等行变换 行阶梯 / 行最简 性质 二、矩阵的标准型 三、矩阵的等价 四、初等矩阵 五、重要性质与定理 一、初等行变换 行阶梯 / 行最简 性质 二、矩阵的标准型 三、矩阵的等价 四、初等矩阵 五、重要性质与定理

租游戏服务器多少钱1个月?一年价格多少?

游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;游戏服务器配置从4核16G、4核32G、8核32G、16核64G等配置可选&#xff0c;可以选择轻量应用服务器和云服务器&#xff0c;阿腾云atengyu…

SpringBoot注解--04--01--注解@Mapper在IDEA中自动注入警告的解决方案

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 问题原因 解决方案方法1&#xff1a;为 Autowired 注解设置required false方法2&#xff1a;用 Resource 替换 Autowired方法3&#xff1a;在Mapper接口上加上Repo…

跟着pink老师前端入门教程-day19

一、移动WEB开发之流式布局 1、 移动端基础 1.1 浏览器现状 PC端常见浏览器&#xff1a;360浏览器、谷歌浏览器、火狐浏览器、QQ浏览器、百度浏览器、搜狗浏览器、IE浏览器。 移动端常见浏览器&#xff1a;UC浏览器&#xff0c;QQ浏览器&#xff0c;欧朋浏览器&#xff0…

论文阅读-Transformer-based language models for software vulnerability detection

「分享了一批文献给你&#xff0c;请您通过浏览器打开 https://www.ivysci.com/web/share/biblios/D2xqz52xQJ4RKceFXAFaDU/ 您还可以一键导入到 ivySCI 文献管理软件阅读&#xff0c;并在论文中引用 」 本文主旨&#xff1a;本文提出了一个系统的框架来利用基于Transformer的语…

宠物空气净化器适合养猫家庭吗?除猫毛好的猫用空气净化器推荐

宠物掉毛是一个普遍存在的问题&#xff0c;尤其在脱毛季节&#xff0c;毛发似乎无处不在。这给家中的小孩和老人带来了很多麻烦&#xff0c;他们容易流鼻涕、过敏等不适。此外&#xff0c;宠物有时还会不规矩地拉扯和撒尿&#xff0c;这股气味实在是难以忍受。家人们对宠物的存…

算法学习——LeetCode力扣哈希表篇2

算法学习——LeetCode力扣哈希表篇2 454. 四数相加 II 454. 四数相加 II - 力扣&#xff08;LeetCode&#xff09; 描述 给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 …

Springboot启动出现Waiting for changelog lock...问题

今天在开发的时候&#xff0c;Springboot启动的时候出现Waiting for changelog lock…问题. 问题原因&#xff1a;该问题就是发生了数据库的死锁问题&#xff0c;可能是由于一个杀死的liquibase进程没有释放它对DATABASECHANGELOGLOCK表的锁定&#xff0c;导致服务启动失败&…

我的世界Java版服务器如何搭建并实现与好友远程联机Minecarft教程

文章目录 1. 安装JAVA2. MCSManager安装3.局域网访问MCSM4.创建我的世界服务器5.局域网联机测试6.安装cpolar内网穿透7. 配置公网访问地址8.远程联机测试9. 配置固定远程联机端口地址9.1 保留一个固定tcp地址9.2 配置固定公网TCP地址9.3 使用固定公网地址远程联机 本教程主要介…

「深度学习」循环神经网络RNN

一、序列模型的例子 二、数学符号定义 X^{(i)<t>}&#xff1a;训练样本 i 的输入序列的第 t 个元素。 T_{X}^{i}&#xff1a;训练样本 i 的输入序列的长度。 Y^{(i)<t>}&#xff1a;训练样本 i 的输出序列的第 t 个元素。 T_{Y}^{i}&#xff1a;训练样本 i 的输…