当前位置: 首页 > article >正文

Spring 中的事务

🧾 一、什么是事务?

🧠 通俗理解:

事务 = 一组操作,要么全部成功,要么全部失败,不能只做一半。

比如你转账:

  • A 账户扣钱
  • B 账户加钱

如果 A 扣了钱但 B 没收到,那就出问题了!这就是 数据不一致,事务就是为了解决这类问题。

✅ 二、事务的四大特性(ACID)

特性解释
原子性(Atomicity)要么全部成功,要么全部失败
一致性(Consistency)操作前后数据处于一致状态
隔离性(Isolation)多个事务互不干扰
持久性(Durability)提交后的数据是永久保存的

💡 三、Spring 中的事务管理方式

Spring 支持两种事务管理方式:

1. 编程式事务管理(不常用)

手动写事务边界,代码控制事务提交/回滚。

TransactionStatus status = txManager.getTransaction(...);
try {// 业务代码txManager.commit(status);
} catch (Exception e) {txManager.rollback(status);
}

🚫 缺点:代码侵入性强、重复、易出错。实际开发中不推荐。

2. 声明式事务管理 ✅(主流)

通过注解或配置来管理事务,干净、简洁、优雅!

@Service
public class AccountService {@Transactionalpublic void transfer() {// 扣钱// 加钱// 如果中间出异常,自动回滚}
}

📌 四、@Transactional 注解详解

@Transactional 是 Spring 中声明事务的注解,作用范围可以是类或方法。

常用属性:

属性含义
propagation事务传播行为(默认 REQUIRED
isolation事务隔离级别
rollbackFor指定哪些异常触发回滚(默认是运行时异常)
readOnly是否只读事务
timeout设置事务超时时间

🔄 五、事务的传播行为(重点)

行为含义
REQUIRED(默认)有事务就加入,没有就新建
REQUIRES_NEW每次都新建一个事务,原事务挂起
NESTED嵌套事务,有独立的回滚点
SUPPORTS有事务就用,没有就不用
NOT_SUPPORTED不支持事务,挂起当前事务
NEVER当前不能存在事务,否则抛异常
MANDATORY必须存在事务,否则抛异常

🔒 六、事务隔离级别(对应数据库的)

隔离级别解决的问题说明
DEFAULT使用数据库默认
READ_UNCOMMITTED脏读最低,性能高但不安全
READ_COMMITTED不可重复读常用,如 Oracle 默认
REPEATABLE_READ幻读MySQL 默认
SERIALIZABLE最强隔离安全但性能差

💣 七、事务生效的注意事项(易踩坑)

🚨 1. 事务方法必须是 public

@Transactional // 正确
public void doSomething() {}

🚨 2. 方法 不能是同一个类中内部调用

// 错误示例:事务不起作用
public void outer() {this.inner(); // 没经过代理
}

✅ 正确做法:通过代理调用

  • 注入自身(@Lazy 方式)
  • 拆到 Service 层让 Spring 来代理调用

🚨 3. 默认只对 运行时异常 回滚

@Transactional(rollbackFor = Exception.class)

🧪 八、事务管理器(Spring 内部机制)

Spring 通过 PlatformTransactionManager 接口进行统一管理。

常用实现类:

实现类场景
DataSourceTransactionManager使用 JDBC、MyBatis
JpaTransactionManager使用 JPA/Hibernate
ChainedTransactionManager多数据源事务

✅ 九、一句话总结

Spring 的事务机制让你只关心业务逻辑,不用手动管理事务,声明式的方式简洁高效,是真正的企业级利器。

@Transactional 实现原理

它的实现原理非常巧妙,实际上是通过 AOP(面向切面编程)代理机制 实现的。这一机制让你无需写一行事务管理的代码,Spring 会自动为你处理。

我们一起来详细剖析一下底层原理!🧠

💡 一、核心原理概览

1. AOP + 代理

@Transactional 注解是基于 AOP(面向切面编程)实现的,具体来说,Spring 会为标记了 @Transactional 注解的方法创建一个代理对象,这个代理对象会在方法执行前后进行事务的开启、提交和回滚等处理。

2. 动态代理

Spring 通过动态代理技术(JDK 代理或 CGLIB 代理)生成一个代理对象,这个对象会拦截你的方法调用,在方法调用前后进行事务管理的相关操作。

3. 事务管理器

Spring 会利用配置的 事务管理器(PlatformTransactionManager 来处理事务的开启、提交、回滚等操作。

🛠️ 二、@Transactional 的工作流程

步骤 1:创建代理对象

  • 代理方式:Spring 使用 JDK 动态代理CGLIB 代理 来生成代理对象。默认情况下,如果目标类实现了接口,Spring 会使用 JDK 动态代理;如果没有实现接口,则使用 CGLIB 创建子类代理。

步骤 2:事务管理器的配置

  • @Transactional 依赖于 事务管理器 来执行事务操作,Spring 根据你配置的 PlatformTransactionManager 来管理事务。常见的事务管理器有:
    • DataSourceTransactionManager:用于 JDBC。
    • JpaTransactionManager:用于 JPA(如 Hibernate)。
    • HibernateTransactionManager:用于 Hibernate。

步骤 3:方法执行前,开启事务

当你调用被 @Transactional 注解标记的方法时,Spring 代理会拦截这个方法的调用,首先会判断当前方法是否需要开启新事务(即,方法的传播行为是 REQUIRED)。如果需要开启新事务,则会通过 事务管理器 启动一个新的事务。

  • 事务的传播行为(propagation:比如,REQUIRED 表示如果当前没有事务,就新建一个事务,如果已有事务,就加入到当前事务中。

步骤 4:方法执行中,进行事务操作

方法执行过程中,Spring 会维持该事务的状态,直到方法执行完毕。

  • 事务隔离级别(isolation:隔离级别决定了事务之间如何互相影响(比如,是否允许脏读、不可重复读等)。

步骤 5:方法执行后,提交或回滚事务

  • 方法正常完成:如果方法执行没有异常,Spring 会在方法结束后提交事务。
  • 方法出现异常:如果方法抛出异常,Spring 会根据 @Transactional 配置的异常回滚规则,判断是否回滚该事务。

⚙️ 三、事务管理的关键组件

1. TransactionInterceptor:核心事务拦截器

  • Spring 使用 TransactionInterceptor 来处理所有带有 @Transactional 注解的方法,它是事务管理的关键拦截器。
  • 该拦截器负责从容器中获取事务管理器、根据事务配置设置事务属性(如隔离级别、传播行为等),并且控制事务的开启、提交和回滚。

2. TransactionProxyFactoryBean:生成代理对象

  • TransactionProxyFactoryBean 是 Spring 用来创建事务代理的工厂,实际上它会根据注解或配置生成一个代理对象。
  • 这个代理对象会拦截对事务方法的调用,并在调用方法前后进行事务的处理。

3. PlatformTransactionManager:事务管理器

  • 事务管理器(如 DataSourceTransactionManager)负责实际的事务操作,包括开启事务、提交事务、回滚事务等。

🔍 四、事务处理的实际步骤

  1. 方法调用被代理对象拦截
    • @Transactional 标记的方法会被 AOP 代理拦截,调用 TransactionInterceptor
  2. 事务拦截器执行逻辑
    • TransactionInterceptor 会根据 @Transactional 配置,从容器中获取 事务管理器PlatformTransactionManager)。
  3. 判断事务传播行为
    • 如果当前没有事务(例如没有正在进行的事务),根据传播行为决定是否新建事务。默认是 REQUIRED,即如果没有事务,创建一个新的事务。
  4. 开启事务
    • 通过 PlatformTransactionManager 开启一个事务(实际是对底层数据库操作的封装)。
  5. 执行目标方法
    • 目标方法执行,在方法内的操作都在同一个事务中进行。
  6. 提交或回滚事务
    • 如果方法执行没有抛出异常,Spring 提交事务;如果抛出指定异常(如运行时异常),Spring 会回滚事务。

💡 五、示例:@Transactional 事务的底层工作

假设你有一个服务类 AccountService,方法 transfer()@Transactional 注解标记:

@Service
public class AccountService {@Transactionalpublic void transfer() {// 扣款操作// 加款操作// 如果中间出错,Spring 会自动回滚}
}
  • Spring 会生成一个代理对象 AccountService,拦截 transfer() 方法调用。
  • 代理对象通过 TransactionInterceptor 来控制事务的开启、提交或回滚。
  • 在调用 transfer() 方法之前,Spring 会检查是否需要开启事务,创建事务并将其绑定到当前线程(一般是通过 ThreadLocal 来绑定)。
  • transfer() 执行完后,如果没有异常,Spring 会提交事务;如果出现异常,Spring 会根据配置回滚事务。

🧠 六、总结

@Transactional 的底层原理依赖于 AOP + 动态代理,通过 事务拦截器TransactionInterceptor)和 事务管理器PlatformTransactionManager)来实现事务的控制。Spring 提供了灵活的事务传播行为和隔离级别,让事务控制变得更加简单和清晰。

Spring 事务在什么情况下会失效?

1. 方法是 privateprotected

Spring 的事务管理是基于 AOP(面向切面编程) 实现的,而 AOP 需要代理对象来执行方法。如果方法是 privateprotected,Spring 的 AOP 代理是无法拦截到该方法的,因此事务无法生效。

解决方法:

  • 将事务方法设置为 public,这样 Spring 的代理对象才能正确地拦截并应用事务。
@Transactional
public void transfer() { // 必须是 public// 业务逻辑
}

2. 在同一类内调用事务方法

当一个类内部的事务方法相互调用时,事务是不会生效的。这是因为 事务代理 是基于代理对象的,而类内部方法调用是直接调用对象的方法,不会经过代理。

例子:

@Service
public class AccountService {@Transactionalpublic void transfer() {// 扣款操作this.otherMethod(); // 调用同一个类中的方法}@Transactionalpublic void otherMethod() {// 加款操作}
}

在这个例子中,transfer() 调用了 otherMethod(),但 @Transactional 注解没有生效,因为调用 this.otherMethod() 是直接调用类内部的方法,不会经过代理。

解决方法:

  • 拆分方法,将事务性方法提取到另一个服务类中,确保 Spring 代理对象能够接管方法调用。

3. 没有配置事务管理器

Spring 中的事务是依赖于 PlatformTransactionManager 来进行管理的。如果没有配置或注入正确的事务管理器,事务就无法生效。

解决方法:

  • 确保在 applicationContext.xmlSpring Boot 配置类中配置了正确的事务管理器。

Spring Boot 示例:

@Configuration
@EnableTransactionManagement
public class TransactionConfig {@Beanpublic PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {return new JpaTransactionManager(entityManagerFactory);}
}

4. 事务方法抛出了非 RuntimeException 异常

Spring 默认只对 运行时异常 (RuntimeException 和其子类) 回滚事务。如果你在方法中抛出了一个 检查型异常(checked exception(如 IOExceptionSQLException 等),默认情况下,Spring 不会回滚事务。

解决方法:

  • 使用 @TransactionalrollbackFor 属性来指定哪些异常需要回滚事务。
@Transactional(rollbackFor = Exception.class)  // 指定回滚异常
public void transfer() throws IOException {// 业务逻辑
}

5. 事务被 @Transactional 注解的代理方法外部调用

Spring 的事务管理依赖于 代理对象,如果事务方法被其他 非 Spring 管理的对象调用,Spring 的事务也不会生效。

解决方法:

  • 确保事务方法仅通过 Spring 管理的代理对象来调用。避免手动调用 new 创建的对象或外部非 Spring 管理的对象。

6. 事务的传播行为不正确

事务的传播行为(propagation)控制了事务的嵌套和传播方式。如果设置不当,事务可能不会按预期工作。

例如,如果你使用了 REQUIRES_NEW 传播行为,每次方法都会启动一个新的事务,原事务会被挂起。如果这时原事务出现问题,它就无法回滚。

解决方法:

  • 确保事务的传播行为与业务场景相匹配。常见的设置是 REQUIRED(默认),它会加入当前事务,如果没有事务,则创建一个新的事务。
@Transactional(propagation = Propagation.REQUIRED)
public void transfer() {// 事务逻辑
}

7. 非事务方法调用事务方法时,事务失效

如果一个非事务方法调用了带有 @Transactional 的方法,在一些情况下事务不会生效。特别是在 非 Spring 管理的对象 上,事务不会生效。

解决方法:

  • 确保事务方法是由 Spring 管理的代理对象来调用,避免在非 Spring 管理的对象中调用事务方法。

8. 只读事务修改数据

@Transactional 中的 readOnly 属性告诉 Spring 该事务是只读的。如果在只读事务中执行了写操作(比如更新数据库),在某些数据库系统中事务可能不会按预期提交,甚至会抛出异常。

解决方法:

  • 确保只读事务只用于查询操作,避免在只读事务中执行写操作。
@Transactional(readOnly = true)
public List<User> getAllUsers() {return userRepository.findAll();
}

🚦 九、总结

Spring 事务失效的常见原因:

  1. 事务方法是 privateprotected
  2. 方法在同一类中被调用(直接调用,未通过代理)。
  3. 没有配置事务管理器
  4. 抛出了非 RuntimeException 异常
  5. 事务方法被非 Spring 管理的对象外部调用
  6. 事务的传播行为设置不当
  7. 非事务方法调用事务方法时,事务失效
  8. 只读事务进行数据修改

避免失效的建议:

  • 确保事务方法是 public
  • 使用 Spring 管理的代理对象来调用事务方法。
  • 正确配置事务管理器。
  • 根据需求调整 rollbackForpropagation 配置。
  • 使用 readOnly 标记仅进行查询的事务。

相关文章:

Spring 中的事务

&#x1f9fe; 一、什么是事务&#xff1f; &#x1f9e0; 通俗理解&#xff1a; 事务 一组操作&#xff0c;要么全部成功&#xff0c;要么全部失败&#xff0c;不能只做一半。 比如你转账&#xff1a; A 账户扣钱B 账户加钱 如果 A 扣了钱但 B 没收到&#xff0c;那就出问…...

Java中的同步和异步

一、前言 在Java中&#xff0c;同步&#xff08;Synchronous&#xff09;和异步&#xff08;Asynchronous&#xff09;是两种不同的任务处理模式。核心区别在任务执行的顺序控制和线程阻塞行为。 二、同步&#xff08;Synchronous&#xff09; 定义&#xff1a;任务按顺序执行…...

vue2 vue3 响应式差异

vue2 响应式原理看这 链接: link 总结&#xff1a; object.defineproperty()是对属性的劫持&#xff0c;对属性劫持有两大缺陷 1. 需要遍历对象的所有属性&#xff0c;深层属性需递归&#xff0c;存在效率问题 2. 后添加的属性&#xff0c;无法获得响应式&#xff0c;因为劫持…...

唯一ID生成器设计方案

《亿级流量系统架构设计与实战》总结 1. 唯一ID的核心需求 • 全局唯一性&#xff1a;分布式系统中所有节点生成的ID不可重复。 • 趋势递增性&#xff08;可选&#xff09;&#xff1a;ID按时间或序列递增&#xff0c;优化数据库写入性能。 • 高可用性&#xff1a;服务需72…...

OpenCV 图形API(16)将极坐标(magnitude 和 angle)转换为笛卡尔坐标(x 和 y)函数polarToCart()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 描述 计算二维向量的 x 和 y 坐标。 polarToCart 函数根据 magnitude 和 angle 的对应元素表示的每个二维向量&#xff0c;计算其笛卡尔坐标&#xff1a;…...

在 Ubuntu24.04 LTS 上 Docker Compose 部署基于 Dify 重构二开的开源项目 Dify-Plus

一、安装环境信息说明 硬件资源&#xff08;GB 和 GiB 的主要区别在于它们的换算基数不同&#xff0c;GB 使用十进制&#xff0c;GiB 使用二进制&#xff0c;导致相同数值下 GiB 表示的容量略大于 GB&#xff1b;换算关系&#xff1a;1 GiB ≈ 1.07374 GB &#xff1b;1 GB ≈ …...

安装和配置Docker

其他版本的安装方式可直接参考官方网站&#xff0c;推荐通过官方网站提供的方式安装Dockers&#xff0c;下面只是个演示的示例&#xff0c;仅供参考 Install | Docker Docs 安装 Docker 的前置准备 1.虚拟机配置&#xff1a; 推荐配置 内存&#xff1a;4GB&#xff08;最低…...

Ansible YAML 基础语法与关键词 的详细指南

以下是 Ansible YAML 基础语法与关键词 的详细指南&#xff0c;帮助你快速掌握 Playbook 编写规范和核心概念&#xff1a; 目录 一、Ansible Playbook 基础结构1. YAML 文件基础 二、核心关键词1. Play 定义2. Task 定义3. Handler 定义4. 变量&#xff08;Variables&#xff0…...

NO.64十六届蓝桥杯备战|基础算法-简单贪心|货仓选址|最大子段和|纪念品分组|排座椅|矩阵消除(C++)

贪⼼算法是两极分化很严重的算法。简单的问题会让你觉得理所应当&#xff0c;难⼀点的问题会让你怀疑⼈⽣ 什么是贪⼼算法&#xff1f; 贪⼼算法&#xff0c;或者说是贪⼼策略&#xff1a;企图⽤局部最优找出全局最优。 把解决问题的过程分成若⼲步&#xff1b;解决每⼀步时…...

瑞萨RA4M2使用心得-KEIL5的第一次编译

目录 前言 环境&#xff1a; 开发板&#xff1a;RA-Eco-RA4M2-100PIN-V1.0 IDE&#xff1a;keil5.35 一、软件的下载 编辑瑞萨的芯片&#xff0c;除了keil5 外还需要一个软件&#xff1a;RASC 路径&#xff1a;Releases renesas/fsp (github.com) 向下找到&#xff1a; …...

java根据集合中对象的属性值大小生成排名

1&#xff1a;根据对象属性降序排列 public static <T extends Comparable<? super T>> LinkedHashMap<T, Integer> calculateRanking(List<ProductPerformanceInfoVO> dataList, Function<ProductPerformanceInfoVO, T> keyExtractor) {Linked…...

数据分析-Excel-学习笔记

Day1 复现报表聚合函数&#xff1a;日期联动快速定位区域SUMIF函数SUMIFS函数环比、同比计算IFERROR函数混合引用单元格格式总结汇报 拿到一个Excel表格&#xff0c;首先要看这个表格个构成&#xff08;包含了哪些数据&#xff09;&#xff0c;几行几列&#xff0c;每一列的名称…...

整车CAN网络和CANoe

车载网络中主要包含有Can网络,Lin网络,FlexRay,Most,以太网。 500kbps:500波特率,表示的数据传输的速度。表示的是最大的网速传输速度。也就是每秒 500kb BodyCan车身Can InfoCan娱乐信息Can 车身CAN主要连接的是ESB电动安全带 ADB自适应远光灯等 PTCan动力Can 底盘Can...

ChatGPT 的新图像生成器非常擅长伪造收据

本月&#xff0c;ChatGPT 推出了一种新的图像生成器&#xff0c;作为其 4o 模型的一部分&#xff0c;该模型在生成图像内的文本方面做得更好。 人们已经在利用它来生成假的餐厅收据&#xff0c;这可能会为欺诈者使用的已经很广泛的 AI 深度伪造工具包添加另一种工具。 多产的…...

JS页面尺寸事件

元素位置 在这里插入图片描述 父元素带有定位时输出相对于父亲元素的距离值...

SpringBoot的日志框架

目录 默认日志框架 日志配置 更换日志框架 排除默认Logback 引入目标日志框架 添加配置文件 logback.xml SpringBoot的核心设计宗旨是约定大于配置,很多框架功能都给你默认加载和配置完成供你使用,但这就要求使用者对框架有一定的理解和改造能力,比如这个日志框架,是其…...

网络协议之基础介绍

写在前面 本文看下网络协议相关基础内容。 1&#xff1a;为什么要有网络协议 为了实现世界各地的不同主机的互联互通。 2&#xff1a;协议的三要素 协议存在的目的就是立规矩&#xff0c;无规矩不成方圆嘛&#xff01;但是这个规矩也不是想怎么立就怎么立的&#xff0c;也…...

【学Rust写CAD】34 精确 Alpha 混合函数(argb.rs补充方法)

源码 #[inline]pub fn over_exact(self, dst: Argb) -> Argb {let a 255 - self.alpha32();let t dst.rb() * a 0x80_00_80;let mut rb (t ((t >> 8) & Argb::MASK)) >> 8;rb & Argb::MASK;rb self.rb();// saturaterb | 0x1000100 - ((rb >&…...

利用NumPy核心知识点优化TensorFlow模型训练过程

利用NumPy核心知识点优化TensorFlow模型训练过程 NumPy是Python科学计算的基础库&#xff0c;掌握它的高效操作可以显著提升TensorFlow模型的训练效率。本文详细探讨如何将NumPy的核心优势应用于TensorFlow模型训练的各个环节。 1. 数据预处理优化 高效向量化操作 NumPy的向…...

初识数据结构——Java集合框架解析:List与ArrayList的完美结合

&#x1f4da; Java集合框架解析&#xff1a;List与ArrayList的完美结合 &#x1f31f; 前言&#xff1a;为什么我们需要List和ArrayList&#xff1f; 在日常开发中&#xff0c;我们经常需要处理一组数据。想象一下&#xff0c;如果你要管理一个班级的学生名单&#xff0c;或…...

TDengine 从入门到精通(2万字长文)

目录 第一章:走进 TDengine 的世界 TDengine 是个啥? TDengine 的硬核特性 性能炸裂 分布式架构,天生可扩展 SQL 用起来贼顺手 写入方式花样多 内置缓存,省心又省力 TDengine 能干啥? 智能制造 能源管理 物联网平台 工业大数据 第二章:上手 TDengine:安装与…...

DevOps 与持续集成(CI/CD)

1. DevOps 概述 DevOps(Development + Operations)是一种软件开发方法,强调开发(Dev)与运维(Ops)协作,通过自动化工具提高软件交付效率。其目标是: ✅ 提高部署速度 —— 频繁发布新版本 ✅ 减少人为错误 —— 通过自动化降低运维风险 ✅ 增强可观测性 —— 监控和日…...

[特殊字符] 使用 Handsontable 构建一个支持 Excel 公式计算的动态表格

在 Web 应用中&#xff0c;处理表格数据并提供 Excel 级的功能&#xff08;如公式计算、数据导入导出&#xff09;一直是个挑战。今天&#xff0c;我将带你使用 React Handsontable 搭建一个强大的 Excel 风格表格&#xff0c;支持 公式计算、Excel 文件导入导出&#xff0c;并…...

uniapp微信小程序引入vant组件库

1、首先要有uniapp项目&#xff0c;根据vant官方文档使用yarn或npm安装依赖&#xff1a; 1、 yarn init 或 npm init2、 # 通过 npm 安装npm i vant/weapp -S --production# 通过 yarn 安装yarn add vant/weapp --production# 安装 0.x 版本npm i vant-weapp -S --production …...

贪心进阶学习笔记

反悔贪心 贪心是指直接选择局部最优解&#xff0c;不需要考虑之后的影响。 而反悔贪心是在贪心上面加了一个“反悔”的操作&#xff0c;于是又可以撤销之前的“鲁莽行动”&#xff0c;让整个的选择稍微变得“理智一些”。 于是&#xff0c;我个人理解&#xff0c;反悔贪心是…...

Java 大视界 -- Java 大数据在航天遥测数据分析中的技术突破与应用(177)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

架构师面试(二十七):单链表

问题 今天的问题对于架构师来说会相对容易许多。今天出一个【数据结构与算法】相关的题目&#xff0c;醒醒脑。 给一张【单链表】&#xff0c;该单链表有100个节点元素&#xff08;当然&#xff0c;事先我们是不知道100这个数目的&#xff09;&#xff0c;要获取倒数第8个元素…...

从扩展黎曼泽塔函数构造物质和时空的结构-15

回来考虑泽塔函数&#xff0c; 我们知道&#xff0c; 也就是在平面直角坐标系上反正切函数在x上的变化率&#xff0c;那么不难看出&#xff0c; 就是在s维空间上的“广义”反正切函数在单位p上的变化率&#xff0c;而泽塔函数&#xff0c;就是这些变化率的全乘积&#xff0c; 因…...

数据库访问工具 dbVisitor v6.0.0 发布

dbVisitor 是一款轻量小巧、功能完备的 Java 数据库 ORM 工具&#xff0c;它的前身是 HasorDB&#xff0c;历经 8 年迭代后正式更名为 dbVisitor 并开始独立发展4。以下是关于 dbVisitor v6.0.0 发布的相关信息&#xff1a; 发布说明 在 Maven Central 上可查询到 dbVisitor …...

01背包问题详解 具体样例模拟版

01背包 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 v i v_i vi​&#xff0c;价值是 w i w_i wi​。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入格式 …...