16. Spring 事务和事务传播机制

news2024/12/24 20:40:10

源码位置:transaction

1. 事务回顾

在数据库阶段,想必大家都已经学习过事务了。当多个操作要么一起成功,要么一起失败的时候就需要将多个操作放在同一个事务中。

举个例子:比如用户A给用户B转账100元的业务,需要把用户A的余额-100,并且用户B的余额+100,这两个操作对应着数据库的两条SQL语句,两条SQL语句可以放入事务中,要么一起成功(提交)一起失败(回滚)。

MySQL中的事务无非围绕着这三个SQL语句:

-- 开启事务
start transaction;
-- 提交事务
commit;
-- 回滚事务
rollback;

在数据库阶段主要以理解事务的概念为主,然而在实际的开发中,并不是简单的通过事务来处理,因此我们要学习Spring中的事务操作。

2. Spring中事务的实现

Spring中的事务操作分为两类:

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

2.1 前置操作

在学习事务之前,先准备需要使用的库和表,SQL脚本如下:

drop database if exists trans;
create database trans default character set utf8mb4;
use trans;

drop table if exists userinfo;
create table userinfo (
    `id` int not null auto_increment,
    `username` varchar(20) not null,
    `password` varchar(30) 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 = '用户表';

通过普通的MyBatis插入几条数据:

实体类 UserInfo:

@Data
public class UserInfo {

    private Integer id;
    private String username;
    private String password;
    private Timestamp createTime;
    private Timestamp updateTime;
}

控制层 UserController:

@RequestMapping("/user")
@RestController
@Slf4j
public class UserController {
    @Autowired
    UserService userService;

    @RequestMapping("/registry")
    public String registry(UserInfo userInfo) {
        Integer result = userService.insertUser(userInfo);
        log.info("插入了" + result + "条数据~");
        return "注册成功";
    }
}

服务层 UserService:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public Integer insertUser(UserInfo userInfo) {
        return userMapper.insertUser(userInfo);
    }
}

mapper层 UserMapper:

@Mapper
public interface UserMapper {
    Integer insertUser(UserInfo userInfo);
}

UserMapper.xml实现接口

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chenshu.transaction.mapper.UserMapper">

    <insert id="insertUser">
        insert into userinfo
                        <trim prefix="(" suffix=")" suffixOverrides=",">
                            <if test="username != null">
                                username,
                            </if>
                            <if test="password != null">
                                password,
                            </if>
                            <if test="createTime != null">
                                creat_time,
                            </if>
                            <if test="updateTime != null">
                                update_time,
                            </if>
                        </trim>
        values
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="username != null">
                    #{username},
                </if>
                <if test="password != null">
                    #{password},
                </if>
                <if test="createTime != null">
                    #{createTime},
                </if>
                <if test="updateTime != null">
                    #{updateTime},
                </if>
            </trim>
    </insert>
</mapper>

通过url插入几条数据:

image.png

通过几次url访问,成功插入以下数据:

image.png

2.1 编程式事务(了解)

Spring手动操作事务和上面MySQL操作事务类似,有3个重要操作步骤:

  • 获取事务状态
  • 回滚事务
  • 提交事务

2.1.1 获取事务状态

编程式事务有两个重要的类:

  • 事务管理器:org.springframework.jdbc.datasource.DataSourceTransactionManager
  • 事务属性的接口:org.springframework.transaction.TransactionDefinition

在Controller层依赖注入这两个类:

public class UserController {
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    @Autowired
    private TransactionDefinition transactionDefinition;

通过事务管理器DataSourceTransactionManagergetTransaction()方法,在方法里传入TransactionDefinition可以拿到一个TransactionStatus代表当前事务状态的类。

TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);

通过TransactionStatus可以对事务进行回滚 or 提交

2.1.2 事务回滚

@RequestMapping("/registry")
public String registry(UserInfo userInfo) {
    //获取事务状态
    TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);

    Integer result = userService.insertUser(userInfo);
    log.info("插入了" + result + "条数据~");
    //回滚事务
    dataSourceTransactionManager.rollback(transaction);

    return "注册成功";
}

再次通过url调用该方法:

image.png

由于事务回滚,表里没有插入数据:

image.png

2.1.3 事务提交

@RequestMapping("/registry")
public String registry(UserInfo userInfo) {
    //获取事务状态
    TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);

    Integer result = userService.insertUser(userInfo);
    log.info("插入了" + result + "条数据~");
    //提交事务
    dataSourceTransactionManager.commit(transaction);

    return "注册成功";
}

再次输入url来调用注册方法:

image.png

由于事务提交,表中成功插入了数据:

image.png

我们发现用户wangwu此时的自增 id 为5,证明上次的SQL语句即使回滚了,还是留下了执行SQL的痕迹。

既然执行过SQL又是如何进行回滚的呢?接下来我们就来讲讲事务状态TransactionStatus这个对象做了什么。

2.1.4 事务状态的解释

观察事务的回滚和提交的日志信息,并对比差别:

回滚事务的日志:

//创建事务会话
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2014a533]
//从连接池获取连接
JDBC Connection [HikariProxyConnection@207488314 wrapping
//执行SQL语句
com.mysql.cj.jdbc.ConnectionImpl@135f132a] will be managed by Spring
==>  Preparing: insert into userinfo ( username, password ) values ( ?, ? )
==> Parameters: wangwu(String), 123(String)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2014a533]
2024-04-26 22:10:19.758  INFO 10561 --- [nio-8080-exec-1] c.c.t.controller.UserController          : 插入了1条数据~
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2014a533]
//关闭事务会话
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2014a533]

提交事务的日志:

//创建事务会话
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@599475b7]
//从连接池获取连接
JDBC Connection [HikariProxyConnection@1632144075 wrapping 
//执行SQL语句
com.mysql.cj.jdbc.ConnectionImpl@37fb4a40] will be managed by Spring
==>  Preparing: insert into userinfo ( username, password ) values ( ?, ? )
==> Parameters: wangwu(String), 123(String)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@599475b7]
2024-04-26 22:02:44.931  INFO 10517 --- [nio-8080-exec-1] c.c.t.controller.UserController          : 插入了1条数据~
//提交事务
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@599475b7]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@599475b7]
//关闭事务会话
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@599475b7]

对比二者发现提交事务的连接多了一个提交事务的操作。

数据库中是类似这样处理的:

  1. 当获取事务状态时,相当于开启了事务,数据库此时会记录一个时间点
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);
  1. 执行SQL语句
  2. 通过dataSourceTransactionManager事务管理器进行rollback() or commit()
  3. rollback(): 不提交事务,将事务标记为已回滚状态后关闭事务会话,并回滚到开启事务的时间点;commit(): 提交事务,并将事务标记为已提交状态后关闭事务会话

2.2 声明式事务(推荐)

为了简化编程式事务,Spring新增了声明式事务的方式。

使用一个@Transactional注解声明方法:

@RequestMapping("/registry")
@Transactional
public String registry(UserInfo userInfo) {
    Integer result = userService.insertUser(userInfo);
    log.info("插入了" + result + "条数据~");
    return "注册成功";
}

2.2.1 @Transactional 作用

@Transactional可以用来修饰方法或类:

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

当方法/类被该注解修饰后,它会做下面三件事:

  1. 在方法执行前开启事务
  2. 执行目标方法
  3. 如果未出现异常或异常被程序捕获就提交事务,如果出现异常并没被捕获就回滚事务(不完全对,马上就讲)

2.2.2 @Transactional的常用属性

valuetransactionManager:这两个属性的作用相同,对应事务管理器的名称,分库分表时会用到

@AliasFor("transactionManager")
String value() default "";

@AliasFor("value")
String transactionManager() default "";

propagationisolation:代表传播机制隔离级别,后面详细介绍

Propagation propagation() default Propagation.REQUIRED;

Isolation isolation() default Isolation.DEFAULT;
【引入】回滚相关属性

与回滚相关的属性有下面四个:

Class<? extends Throwable>[] rollbackFor() default {};

String[] rollbackForClassName() default {};

Class<? extends Throwable>[] noRollbackFor() default {};

String[] noRollbackForClassName() default {};

分别解释四个参数:

  • rollbackFor:里面传的是异常的.class对象,抛出符合条件异常就回滚
  • rollbackForClassName:里面传异常的类名,抛出符合条件异常就回滚
  • noRollbackfor:里面传的是异常的.class对象,抛出符合条件异常不回滚
  • noRollbackForClassName:里面传异常的类名,抛出符合条件异常不回滚

注:符合条件指的是抛出该异常或该异常的子类

image.png

如果@Transactional注解没有添加上面任何属性值,那么只有在运行时异常和Error才会进行回滚

举个例子,如果想抛出所有异常都回滚,可以这样写:

@RequestMapping("/registry")
@Transactional(rollbackFor = {Exception.class})
public String registry(UserInfo userInfo) {
    Integer result = userService.insertUser(userInfo);
    log.info("插入了" + result + "条数据~");
    return "注册成功";
}

前面提到如果异常被捕获,就会提交事务,那如果发生异常后被捕获,也希望事务回滚,可以通过下面这两种方式回滚事务:

  1. 继续把异常抛出去
@RequestMapping("/registry")
@Transactional(rollbackFor = {Exception.class})
public String registry(UserInfo userInfo) {
    Integer result = userService.insertUser(userInfo);
    log.info("插入了" + result + "条数据~");
    try {
        int a = 10/0;
    } catch (Exception e) {
        log.warn("发生了异常..");
        throw e;
    }
    return "注册成功";
}
  1. 手动设置回滚
@RequestMapping("/registry")
@Transactional(rollbackFor = {Exception.class})
public String registry(UserInfo userInfo) {
    Integer result = userService.insertUser(userInfo);
    log.info("插入了" + result + "条数据~");
    try {
        int a = 10/0;
    } catch (Exception e) {
        log.warn("发生了异常..");
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
    return "注册成功";
}

2.2.3 Spring 事务隔离级别

理解Spring的隔离级别是以了解SQL标准中的事务隔离级别为基础的,如果对此部分内容有所遗忘可以点击这里:数据库的事务的并发问题和四种隔离级别

MySQL默认的隔离级别是可重复读

通过下面的SQL可以查看MySQL设置的隔离级别

select @@global.tx_isolation,@@tx_isolation;

image.png


Spring中事务隔离级别有5种:对比SQL标准中的隔离级别多了一个DEFAULT

  1. Isolation.DEFAULT:以连接的数据库的事务隔离级别为主
  2. Isolation.READ_UNCOMMITTED:读未提交
  3. Isolation.READ_COMMITTED:读已提交
  4. Isolation.REPEATABLE_READ:可重复读
  5. Isolation.SERIALIZABLE:串行化

Spring的事务隔离级别是通过@Transational注解的isolation属性来设置的:

image.png

2.2.4 Spring 事务传播机制

事务传播机制是Spring新增加的概念,在数据库中是不存在的。

它描述的内容是:多个事务方法存在调用关系时,事务是如何在这些方法之间进行传播的。

假设方法A调用方法B,在方法B上设置不同的事务传播级别程序会 进行不同的处理。事务传播机制的设置是通过@Transational注解的propagation属性来设置的,属性值如下:

  1. Propagation.REQUIRED : 需要事务 (默认的事务传播级别),如果方法A存在事务,则方法B加⼊该事务;如果方法A没有事务,则方法B创建⼀个新的事务。

2. Propagation.SUPPORTS : 支持事务 如果方法A存在事务,则方法B加⼊该事务;如果方法A没有事务,则方法B以⾮事务的⽅式运⾏。

  1. Propagation.MANDATORY :强制性事务 如果方法A存在事务,则方法B加⼊该事务;如果方法A没有事务,则抛出异常。

  2. Propagation.REQUIRES_NEW : 需要新事务 如果方法A存在事务,则把当前事务挂起;如果方法A不存在事务,方法B就创建新事务。也就是说不管外部⽅法是否开启事务, 方法B都会新开启⾃⼰的事务,且开启的事务相互独立,互不干扰。

  3. Propagation.NOT_SUPPORTED : 不支持事务 如果方法A存在事务,则把当前事务挂起(不⽤),方法B以非事务的方式运行;如果方法A不存在事务,方法B以非事务的方式运行。也就是说不管外部⽅法是否开启事务,方法B都会以事务的方式运行。

6.Propagation.NEVER : 非事务 以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常。

7.Propagation.NESTED : 嵌套事务 如果方法A存在事务,则方法B创建⼀个事务作为当前事务的嵌套事务来运⾏;如果方法A没有事务,则该取值等价于 PROPAGATION_REQUIRED


接下来我将通过代码演示加入事务、挂起事务、嵌套事务的区别,前置工作如下:

SQL脚本:

drop table if exists log_info;
create table log_info (
    `id` int primary key auto_increment,
    `username` varchar(20) not null,
    `op` varchar(256) not null,
    `create_time` datetime default now(),
    `update_time` datetime default now() ON UPDATE now()
) default charset 'utf8mb4'

LogMapper:映射日志表的新增SQL

@Mapper
public interface LogMapper {
    @Insert("insert into log_info(username, op) values (#{username},#{op})")
    Integer insertLog(LogInfo logInfo);
}

LogService:新增日志表记录的业务

@Service
public class LogService {
    @Autowired
    private LogMapper logMapper;
    @Transactional
    public Integer insertLog(LogInfo logInfo) {
        Integer ret = logMapper.insertLog(logInfo);
        return  ret;
    }
}

PropaController:分别调用 userServicelogService的方法

@RequestMapping("/propa")
@RestController
public class PropaController {
    @Autowired
    private LogService logService;

    @Autowired
    private UserService userService;

    @Transactional
    @RequestMapping("/p1")
    public String p1(UserInfo userInfo) {
        userService.insertUser(userInfo);
        LogInfo logInfo = new LogInfo();
        logInfo.setUsername(userInfo.getUsername());
        logInfo.setOp("用户主动注册");
        logService.insertLog(logInfo);
        return "注册成功";
    }
}
【解释】加入事务和挂起事务的区别

这里我将通过Propagation.REQUIREDPropagation.REQUIRES_NEW两种隔离级别来演示。

1. 两个被调用的方法都使用Propagation.REQUIRED隔离级别,并且有一个方法出现异常的情况

我将UserServiceLogService的事务隔离级别设置为Propagation.REQUIRED,并在LogService中构造算术异常:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional(propagation = Propagation.REQUIRED)
    public Integer insertUser(UserInfo userInfo) {
        return userMapper.insertUser(userInfo);
    }
}
@Service
public class LogService {
    @Autowired
    private LogMapper logMapper;
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer insertLog(LogInfo logInfo) {
        Integer ret = logMapper.insertLog(logInfo);
        //构造算术异常
        ing a = 10/0;
        return  ret;
    }
}

此时我将userinfo以及log_info表中的所有数据清空,并在浏览器的url中输入http://localhost:8080/propa/p1?username=admin&password=123 ,看看会是什么结果:

image.png

结论: 由于此时UserServiceLogService中的两个方法设置的传播机制都是Propagation.REQUIRED,因此直接加入PropaControllerp1事务,而由于LogService的方法出现算术异常,因此整个事务一起回滚,所有两个表中什么数据都没有。


2. 两个被调用的方法都使用Propagation.NESTED隔离级别,并且有一个方法出现异常的情况

我将UserServiceLogService的事务隔离级别设置为Propagation.REQUIRES_NEW,并在浏览器的url中输入http://localhost:8080/propa/p1?username=admin&password=123 ,再次进行测试:

image.png

结论: 由于此时UserServiceLogService中的两个方法设置的传播机制都是Propagation.REQUIRED_NEW,因此将PropaControllerp1事务挂起,并开启两个新的事务,所有事务之间相互独立,互不干扰,因此插入userinfo的事务成功提交,插入log_info的事务独自回滚。

【解释】加入事务和嵌套事务的区别

这里我将通过Propagation.NESTED隔离级别来演示。

其实加入事务和嵌套事务差不多,只不过在手动回滚的处理下嵌套事务可以进行单独回滚。

1. 不手动设置回滚的情况
UserServiceLogService的事务隔离级别设置为propagation = Propagation.NESTED,并在LogService中构造算术异常并且不捕获异常

@Transactional(propagation = Propagation.REQUIRED)
public Integer insertLog(LogInfo logInfo) {
    Integer ret = logMapper.insertLog(logInfo);
    int a = 10/0;
    return  ret;
}

此时我将userinfo以及log_info表中的所有数据清空并在浏览器的url中输入http://localhost:8080/propa/p1?username=admin&password=123 进行测试:

image.png

结论: 在没有自行进行回滚事务的时候,整个事务一起回滚,与Propagation.REQUIRED是一样的。

2. 手动设置回滚的情况

UserServiceLogService的事务隔离级别设置为propagation = Propagation.NESTED,并在LogService中构造算术异常并在捕获后手动设置回滚

@Transactional(propagation = Propagation.REQUIRED)
public Integer insertLog(LogInfo logInfo) {
    Integer ret = logMapper.insertLog(logInfo);
    try {
        int a = 10/0;
    } catch (Exception e) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
    return  ret;
}

此时我将userinfo以及log_info表中的所有数据清空并在浏览器的url中输入http://localhost:8080/propa/p1?username=admin&password=123 进行测试:

image.png

结论: 在自行回滚事务的时候,嵌套事务的传播机制使插入log_info的事务单独回滚,而不影响其他事务。

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

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

相关文章

英文文档阅读学习atoi

文档链接&#xff1a;atoi - C Reference (cplusplus.com) 如果可以看的懂英文的可以直接看这个图&#xff0c;看不明白也没关系&#xff0c;可以看一下下面的翻译&#xff1a; 这是一些c语言的相关单词意思&#xff1a; C-string——使用空字符 0 结尾的一维字符数组 as in i…

(学习日记)2024.04.28:UCOSIII第五十二节:User文件夹函数概览(uC-LIB文件夹)第二部分

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

重学java 24.面向对象 多态

下雨了&#xff0c;跑不跑衣服都会被淋湿&#xff0c;还不如慢慢地走&#xff0c;结局已定 —— 24.4.25 多态 1.面向对象三大特性&#xff1a;封装 继承 多态 2.怎么学&#xff1a; a、不要从字面意思上理解多态这两个字&#xff0c;要从使用形式上掌握 b、要知…

【Redis 开发】Redis哨兵

哨兵 作用和原理服务状态监控选举新的master 搭建哨兵集群RedisTemplate的哨兵模式 作用和原理 Redis提供了哨兵机制来实现主从集群中的自动故障恢复&#xff1a; 哨兵也是一个集群 监控&#xff1a;会不断检查master和slave是否按预期工作自动故障恢复&#xff1a;如果mast…

开发工具-pycharm的代码自动部署服务器以及服务端python配置、项目开发环境一键启动服务

文章目录 一、pycharm的ssh配置1.本地生成ssh密钥2.密钥配置到远端服务器(1-1) 有权限ssh访问到服务器(1-2) 无权限ssh访问到服务器(1-3) 没有办法通过以上形式上传到服务器(2) 配置到authorized_keys自动访问 3.pycharm中配置ssh(1) 选择File中的settings(1) 选择Tools中的SSH…

Github创建远程仓库(项目)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

StarBright染料--星光高亮抗体 助力多色方案

星光染料是一种独特的荧光纳米粒子&#xff0c;将它与 Bio-Rad 高度验证的抗体结合&#xff0c;专为流式细胞术开发&#xff0c;为您提供卓越染色效果。星光染料使稀有群体和低密度抗原易于分辨&#xff0c;同时保持适用于任何多色实验的灵活性。 本篇将帮助你了解高亮星光染料…

springboot权限验证学习-下

上篇讲了rbac对于菜单的权限&#xff0c;下面准备完成按钮权限以及行数据和列数据权限 权限控制(按钮权限) 权限控制 操作权限就是将操作视为资源&#xff0c;比如删除操作&#xff0c;有些人可以有些人不行。于后端来说&#xff0c;操作就是一个接口。于前端来说&#xff0…

vue2使用change事件监听不了回车事件的问题

在 vue2 项目中使用 el-input 的 change 监听&#xff0c;数据不发生变化时&#xff0c;回车事件和失去焦点不生效 输入框会一直显示 只有数据发生变化时才生效 <el-input v-model"editedText" change"endEditing" ref"input"></el-inp…

校园广播系统:智能化管理提升校园安全与效率

在现代教育环境中&#xff0c;校园广播系统不再仅仅是一个播放音乐和通知的工具&#xff0c;它已经成为学校基础设施中不可或缺的一部分。根据《义务教育阶段学校信息化设备配备标准》的第8条&#xff0c;校园广播系统在学校范围内的日常运用极为广泛&#xff0c;涵盖了升旗仪式…

基于 SpringCloud 的在线交易平台乐优商城的设计与实现(四)

第 4 章 数据库设计 4.1 数据库设计原则 4.2.数据库概念结构设计 4.3 数据库表设计 4.4.本章小结 前面内容请移步 基于 SpringCloud 的在线交易平台乐优商城的设计与实现&#xff08;三&#xff09; 相关免费源码资源 乐优商城 第 4 章 数据库设计 4.1 数据库设计原…

怎样把音频压缩?3种简单的音频压缩方法分享

怎样把音频压缩&#xff1f;在数字化时代&#xff0c;音频文件占据了大量的存储空间&#xff0c;因此音频压缩成为了许多人的需求。通过音频压缩&#xff0c;我们不仅可以减小文件大小&#xff0c;方便存储和传输&#xff0c;还可以节省设备空间&#xff0c;提升处理效率。因此…

人工智能|推荐系统——推荐大模型最新进展

近年来,大语言模型的兴起为推荐系统的发展带来了新的机遇。这些模型以其强大的自然语言处理能力和丰富的知识表示,为理解和生成复杂的用户-物品交互提供了新的视角。本篇文章介绍了当前利用大型语言模型进行推荐系统研究的几个关键方向,包括嵌入空间的解释性、个性化推荐的知…

电脑黑屏问题的4种解决方法,两分钟轻松掌握

电脑黑屏是一种让人不安的问题&#xff0c;这个问题可能是由多种原因引起的。在这个数字化的时代&#xff0c;电脑已经成为我们工作和娱乐中不可或缺的一部分。当电脑突然陷入黑屏状态&#xff0c;用户通常会感到困扰和焦虑。本文将介绍一些常见的电脑黑屏问题解决方法&#xf…

微服务之并行与分布式计算

一、概述 1.1集中式系统vs分布式系统 集中式系统 集中式系统完全依赖于一台大型的中心计算机的处理能力&#xff0c;这台中心计算机称为主机&#xff08;Host 或 mainframe &#xff09;&#xff0c;与中心计算机相连的终端设备具有各不相同非常低的计算能力。实际上大多数终…

注意力机制、self attention、target attention、双层attention

关于注意力机制要解决2个问题&#xff0c;一是怎么做在哪个层面上做&#xff0c;二是注意力系数如何得到&#xff0c;由谁产出。注意力机制应用广泛的本质原因是求和的普遍存在&#xff0c;只要是有求和的地方加权和就有用武之地。DIN/DIEN把注意力机制用在用户行为序列建模是为…

校园综合服务平台

码功能强大&#xff0c;ui 精美&#xff0c; 功能包含但不限于校园跑腿&#xff0c;外卖&#xff0c;组局&#xff0c;圈子&#xff0c;商城&#xff0c;抽奖&#xff0c;投票&#xff0c;团购&#xff0c;二手市场&#xff0c;签到&#xff0c;积分商城&#xff0c;一元购等&a…

Linux驱动开发:深入理解I2C时序

目录标题 I2C简介I2C时序关键点Linux内核中的I2C时序处理I2C适配器I2C算法I2C核心 代码示例&#xff1a;I2C设备访问调试I2C时序问题 在Linux驱动开发中&#xff0c;理解和正确处理I2C时序对于确保I2C设备正常工作至关重要。本文将详细介绍I2C通信协议的时序特征&#xff0c;并…

企业的核心竞争力,是有效制作电子说明书

在这个信息化的时代&#xff0c;各种产品和服务层出不穷&#xff0c;数不胜数。要想在众多竞争对手中脱颖而出&#xff0c;除了产品质量之外&#xff0c;还有很多因素。比如营销手段、价格优势或者是品牌效应。但今天我要说的&#xff0c;是一个可能容易被人忽视的一个关键点—…

[嵌入式系统-53]:嵌入式系统集成开发环境大全

目录 一、嵌入式系统集成开发环境分类 二、由MCU芯片厂家提供的集成开发工具 三、由嵌入式操作提供的集成开发工具 四、由第三方工具厂家提供的集成开发工具 一、嵌入式系统集成开发环境分类 嵌入式系统集成开发工具和集成开发环境可以按照不同的分类方式进行划分&#xff…