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

异步持久化策略对比

1.背景

游戏服务器其中一项重点工作,就是对游戏玩家的数据进行持久化,保证下次登录可以再续前缘。如果游戏服务器架构里没有缓存,每次操作都需要读写数据库,无疑对数据库带来非常大的压力。一旦使用缓存,就伴随异常持久化的需求。也就是说,玩家数据先写入缓存,然后服务器在稍后的某个时候,再把数据回写到数据库。

这里的“某个时候”,就有几种策略。

排队策略:采用“先进先出”的策略,排在前面的数据先入库,多次操作去重。

延迟策略:先拿个号,XX时间后,再入库,期间的多次操作直接进行数据合并。

定时策略:基于cron表达,例如每隔五分钟,将排队的所有数据批量更新。

2.代码实现

2.1.实体接口

说实在,加这个接口多少带点无奈,因为加了就强迫用户的领域类实现该接口,对用户的现有代码造成了入侵。但是不加这个,又无法解决一个难题。当用户引入了Redis等进程外缓,每次从Redis读取的数据都是重新序列化的。持久化容器没办法判断前后两个对象是不是同一个对象。

所以这个接口的唯一目的,就是提供一个getId()接口,以便容器能够去重。

import java.io.Serializable;public interface Entity<ID extends Serializable & Comparable<ID>> {ID getId();default String getKey() {return getClass().getSimpleName() + "@" + getId().toString();}}

2.2.持久化容器接口

容器接收每一个需要持久化的对象,然后按自己的策略进行入库,需要一个接收的接口。每个项目使用不同的orm工具库,不同的数据库,如何保存对象这个功能也要作为接口定义。最后,为了支持完美停机,保证服务关闭之前,将所有等待数据进行批量操作,需要另外一个接口。总体,设计如下:

public interface PersistContainer {/*** 接收实体* @param entity*/void receive(Entity<?> entity);/*** 优雅退出,会保证所有等待队列的数据都会跑完*/void shutdownGraceful();SavingStrategy getSavingStrategy();
}
/*** 持久化策略*/
public interface SavingStrategy {/*** 真正执行入库工作,* @param entity*/void doSave(Entity<?> entity);
}

2.3.排队容器

该策略是一种典型的生产者消费者模型,所有的持久化元素会不断的排队,同时持久化线程会不断的消费。如果数据更新非常频繁,那么线程会一直工作,直到消费队伍为空。先来看一段有问题的代码

/*** 以队列的形式持久化*/
public class QueueContainer implements PersistContainer {private final Logger logger = LoggerFactory.getLogger("DbContainer");private final AtomicBoolean run = new AtomicBoolean(true);private final String name;private final BlockingQueue<Entity<?>> queue = new LinkedBlockingDeque<>();private final Set<String> savingQueue = new ConcurrentHashSet<>();private static final NamedThreadFactory namedThreadFactory = new NamedThreadFactory("jforgame-persist-queue-thread");private SavingStrategy savingStrategy;public QueueContainer(String name, SavingStrategy savingStrategy) {// 启动线程跑namedThreadFactory.newThread(this::run).start();this.name = name;this.savingStrategy = savingStrategy;this.run();}@Overridepublic void receive(Entity<?> entity) {String key = entity.getKey();// t2时刻线程a执行if (savingQueue.contains(key)) {return;}this.queue.add(entity);}private void run() {while (run.get()) {Entity<?> entity = null;try {entity = queue.take();savingStrategy.doSave(entity);  // t1时刻线程b执行savingQueue.remove(entity.getKey()); // t3时刻线程b执行} catch (ConcurrentModificationException e1) {// 有可能是并发抛错,重新放入队列receive(entity);} catch (Exception e) {// 其他异常,重复放入队列,还是无法解决问题,有问题的终究有问题// 这里需要一个强通知操作,例如通知开发人员,起来修bug了logger.error("", e);}}}@Overridepublic void shutdownGraceful() {run.compareAndSet(true, false);for (; ; ) {if (!queue.isEmpty()) {saveAllBeforeShutDown();} else {break;}}logger.info("db container [{}] close ok", name);}@Overridepublic SavingStrategy getSavingStrategy() {return savingStrategy;}private void saveAllBeforeShutDown() {while (!queue.isEmpty()) {Iterator<Entity<?>> it = queue.iterator();while (it.hasNext()) {Entity<?> ent = it.next();it.remove();savingStrategy.doSave(ent);}}}
}

这里有个线程并发问题,当持久化线程执行完  savingStrategy.doSave(entity); 这句代码的时候,还没来得及执行savingQueue.remove(entity.getKey())的时候,业务执行执行了receive()方法,就会导致此次保存的动作消失了。

解决的方法也有点意思,只需要消费的时候,代码的顺序调整下即可

savingQueue.remove(entity.getKey()); 
savingStrategy.doSave(entity);  

入库的时候,只要获取到对象,立马释放savingQueue,保证业务线程可以重新加入队列。

2.4.延迟容器 

该策略当一个记录想要入库的时候,先让它等一等,想一想,还有没有其他数据需要合并,不管有没有,隔XX时间一定执行保存动作。

/*** 以延迟执行的形式持久化*/
public class DelayContainer implements PersistContainer {private static final Logger logger = LoggerFactory.getLogger(DelayContainer.class);private static final ScheduledExecutorService service = Executors.newScheduledThreadPool(1, new NamedThreadFactory("common-scheduler"));private final Set<String> savingQueue = new ConcurrentHashSet<>();private ConcurrentMap<String, Node> queue = new ConcurrentHashMap<>();private final AtomicBoolean run = new AtomicBoolean(true);private final String name;/*** 延迟秒数*/private final int delaySeconds;private SavingStrategy savingStrategy;public DelayContainer(String name, int delaySeconds, SavingStrategy savingStrategy) {this.name = name;this.delaySeconds = delaySeconds;this.savingStrategy = savingStrategy;}public void receive(Entity<?> entity) {if (!run.get()) {// 小店已经打烊了,恕不招待return;}String key = entity.getKey();if (savingQueue.contains(key)) {return;}Runnable task = () -> {savingStrategy.doSave(entity);queue.remove(key);};Node node = new Node();node.key = key;node.task = task;queue.put(key, node);service.schedule(node, delaySeconds, TimeUnit.SECONDS);}@Overridepublic void shutdownGraceful() {run.compareAndSet(true, false);Iterator<Map.Entry<String, Node>> iterator = queue.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, Node> next = iterator.next();// 直接执行next.getValue().task.run();iterator.remove();}logger.info("db container [{}] close ok", name);}@Overridepublic SavingStrategy getSavingStrategy() {return savingStrategy;}private static class Node implements Runnable {String key;Runnable task;@Overridepublic void run() {task.run();}}}

2.5.周期策略

该策略不针对一个一个对象,而是周期性的批量处理所有对象,例如每隔一分钟。可以借助Quartz这个第三方库,或者spring的cron表达式,执行复杂的周期性任务。

import org.quartz.CronScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;public class CronContainer implements PersistContainer {private static final Logger logger = LoggerFactory.getLogger(CronContainer.class);private final AtomicBoolean run = new AtomicBoolean(true);private final String name;// 存储待持久化的实体,以实体的唯一标识作为键private  ConcurrentHashMap<String, Entity<?>> entityQueue = new ConcurrentHashMap<>();// Quartz调度器private final Scheduler scheduler;private SavingStrategy savingStrategy;public CronContainer(String name, String cronExpression, SavingStrategy savingStrategy) {this.name = name;this.savingStrategy = savingStrategy;try {// 创建Quartz调度器实例并启动scheduler = StdSchedulerFactory.getDefaultScheduler();scheduler.start();// 创建定时任务并注册到调度器中,使用传入的cronExpression配置触发规则JobDetail jobDetail = JobBuilder.newJob(CronPersistJob.class).withIdentity("cronPersistJob", name).build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity("cronTrigger", name).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build();scheduler.scheduleJob(jobDetail, trigger);// 将当前CronContainer实例存入调度器上下文,方便在任务执行时获取scheduler.getContext().put("cronContainer", this);} catch (SchedulerException e) {logger.error("Failed to initialize scheduler for CronContainer [{}]", name, e);throw new RuntimeException("Failed to initialize scheduler", e);}}@Overridepublic void receive(Entity<?> entity) {if (!run.get()) {return;}String key = entity.getKey();entityQueue.put(key, entity);}@Overridepublic void shutdownGraceful() {run.compareAndSet(true, false);try {// 关闭调度器,停止定时任务scheduler.shutdown(true);logger.info("Cron container [{}] close ok", name);} catch (SchedulerException e) {logger.error("Failed to shutdown scheduler for CronContainer [{}]", name, e);}}@Overridepublic SavingStrategy getSavingStrategy() {return savingStrategy;}// 内部类实现Job接口,定义定时任务执行时的逻辑,会按照cronExpression配置的规则触发public static class CronPersistJob implements Job {@Overridepublic void execute(JobExecutionContext context) {try {CronContainer container = (CronContainer) context.getScheduler().getContext().get("cronContainer");if (container != null && container.run.get()) {// 获取当前队列中所有待持久化的实体Map<String, Entity<?>> entities = container.entityQueue;// 重置引用,数据隔离container.entityQueue = new ConcurrentHashMap<>();Set<String> keys = entities.keySet();for (String key : keys) {Entity<?> entity = entities.get(key);if (entity != null) {// 对每个实体执行持久化操作container.savingStrategy.doSave(entity);}}}} catch (SchedulerException e) {logger.error("Error occurred during executing cron job for CronContainer", e);}}}
}

2.6.组合策略

当一种策略不满足需求的时候,我们可以考虑以组合的形式。例如,如果觉得玩家表一个线程跑不过来,我们也可以加多几个,形成一个容器组,类似下面的代码。

public class QueueContainerGroup extends QueueContainer {private QueueContainer[] group;public QueueContainerGroup(String name, SavingStrategy savingStrategy, int workers) {super(name, savingStrategy);group = new QueueContainer[workers];for (int i = 0; i < workers; i++) {QueueContainer work = new QueueContainer(name, savingStrategy);group[i] = work;}}@Overridepublic void receive(Entity<?> entity) {int index = entity.getId().hashCode() % group.length;group[index].receive(entity);}}

2.7.示例代码

/*** 异步持久化服务*/
@Service
public class AsyncDbService {private SavingStrategy savingStrategy = new MySavingStrategy();private PersistContainer playerWorker = new CronContainer("player", "0 0/1 * * * ?", savingStrategy);private PersistContainer commonWorker = new DelayContainer("common", 60, savingStrategy);/*** 调用此方法,将需要持久化的对象放入队列** @param entity*/public void saveToDb(BaseEntity<?> entity) {if (entity instanceof PlayerEnt) {playerWorker.receive(entity);} else {commonWorker.receive(entity);}}public void deleteFromDb(BaseEntity<?> entity) {entity.setDelete(true);saveToDb(entity);}public void shutDown() {playerWorker.shutdownGraceful();commonWorker.shutdownGraceful();}}
public class MySavingStrategy implements SavingStrategy {@SuppressWarnings("all")@Overridepublic void doSave(Entity<?> entity) {BaseEntity baseEntity = (BaseEntity) entity;// 优先处理删除操作if (baseEntity.isDelete()) {baseEntity.getCrudRepository().delete(entity);} else {baseEntity.getCrudRepository().save(entity);}}
}

相关文章:

异步持久化策略对比

1.背景 游戏服务器其中一项重点工作&#xff0c;就是对游戏玩家的数据进行持久化&#xff0c;保证下次登录可以再续前缘。如果游戏服务器架构里没有缓存&#xff0c;每次操作都需要读写数据库&#xff0c;无疑对数据库带来非常大的压力。一旦使用缓存&#xff0c;就伴随异常持…...

手机租赁系统开发全流程解析与实用指南

内容概要 在如今快速发展的科技时代&#xff0c;手机租赁系统已经成为一种新兴的商业模式&#xff0c;非常符合当下市场需求。那么&#xff0c;在开发这样一个系统的时候&#xff0c;首先要从需求分析和市场调研开始。在这一阶段&#xff0c;你需要了解用户需要什么&#xff0…...

apache-dubbo

dubbo 文档地址 dubbo 官方文档地址 https://dubbo.apache.org/zh-cn/docs/user/references/api.html nacos 官方文档地址 https://nacos.io/zh-cn/docs/quick-start.html nacos下载地址 https://github.com/alibaba/nacos/releases/download/2.3.0/nacos-server-2.3.0.…...

【JavaEE】网络(1)

&#x1f435;本篇文章开始讲解计算机网络相关的知识 一、基础概念 1.1 局域网和广域网 局域网→Local Area Network→简称LAN&#xff0c;局域网是局部组建的一种私有网络&#xff0c;局域网内的主机之间可以进行网络通信&#xff0c;局域网和局域网之间在没有连接的情况不能…...

系统思考—决策

今年在为不同公司交付培训与项目时&#xff0c;常常听到“降本增效”的提法&#xff0c;但关键是&#xff1a;“降”的到底是什么成本&#xff1f;裁员无疑是最快的成本削减方式&#xff0c;但也可能带来人心惶惶。人力是资本&#xff0c;不是成本。除非企业到了生死存亡的关头…...

nVisual 前端集成SDK使用说明

目前客户需要搭建自己的可视化产品,但需要使用nVisual的可视化视图功能,根据目前项目实施需求,决定做了一款简单版的SDK视图插件,这个小插件的主要功能是嵌入到客户项目里给客户提供 ‘详细视图’‘拓扑视图’或者是‘主视图’的展示功能.目前已经开发完毕,这里做一下简单介绍.…...

上传文件时获取音视频文件时长和文本文件字数

获取音视频文件时长和文本文件字数 一、获取音视频文件时长二、计算文本文件字数 最近有个需求&#xff0c;要求上传文件时获取音视频文件时长和文本文件字数&#x1f436;。 发现这样的冷门资料不多&#xff0c;特做个记录。本文忽略文件上传功能&#xff0c;只封装核心的工具…...

[COLM 2024] V-STaR: Training Verifiers for Self-Taught Reasoners

本文是对 STaR 的改进方法&#xff0c;COLM 是 Conference On Language Models&#xff0c;大模型领域新出的会议&#xff0c;在国际上很知名&#xff0c;不过目前还没有被列入 ccf list&#xff08;新会议一般不会列入&#xff09;&#xff1b;作者来自高校、微软研究院和 Goo…...

【C++】string的主要功能模拟复现

经常调用的短小函数直接定义在头文件中&#xff0c;可以节省时间开销 #include<iostream> #include<assert.h> using namespace std; namespace mumu {class string{friend ostream& operator<<(ostream& _cout, const mumu::string& s);friend…...

Linux环境安装Jenkins

Linux环境安装Jenkins Jenkins和JDK的版本 Jenkins和JDK的版本需要对应&#xff0c;不然无法正常启动。 Jenkins稳定版下载地址 Jenkins服务 手动使用命令启动和关闭Jenkins比较麻烦&#xff0c;所以可以把Jenkins设置成开机启动。 创建Jenkins.sh文件 JAVA_HOME和jenk…...

Elasticsearch:ES|QL 中的全文搜索 - 8.17

细心的开发者如果已经阅读我前两天发布的文章 “Elastic 8.17&#xff1a;Elasticsearch logsdb 索引模式、Elastic Rerank 等”&#xff0c;你就会发现在 8.17 的发布版中&#xff0c;有一个重要的功能发布。那就是 ES|QL 开始支持全文搜索了。在今天的文章中我们来尝试一下。…...

Leetcode 3387. Maximize Amount After Two Days of Conversions

Leetcode 3387. Maximize Amount After Two Days of Conversions 1. 解题思路2. 代码实现 题目链接&#xff1a;3387. Maximize Amount After Two Days of Conversions 1. 解题思路 这一题思路上其实就是要分别求出day 1以及day 2中原始货币与其他各个货币之间的成交价&…...

Lumos学习王佩丰Excel第二十一讲:经典Excel动态图表实现原理

一、动态图表实现原理 1、理解图表中的数据系列 在Excel图表中&#xff0c;系列指的是图表中的数据集合&#xff0c;它通常代表着一个数据源。每个系列都可以包含多个数据点&#xff0c;这些数据点在图表中以特定的形式展现&#xff0c;如柱状图中的柱子&#xff0c;折线图中…...

静态路由、RIP、OSPF、BGP的区别

静态路由&#xff1a;是管理员手动将路由写入到路由器中&#xff0c;配置简单开销小&#xff0c;但不能适应网络变化&#xff0c;只用于小型的网络 RIP&#xff0c;路由信息协议&#xff0c;属于距离矢量路由协议的一种&#xff0c;根据跳数来判断最优路由&#xff0c;如果跳数…...

解决 Flutter 在 Mac 上的编译错误

解决 Flutter 在 Mac 上的编译错误 在使用 Flutter 进行项目开发并尝试在 Mac 设备上进行编译时&#xff0c;遇到了一系列的错误信息&#xff0c;这些错误信息给项目的构建与部署带来了阻碍。 一、错误详情 在编译过程中&#xff0c;Xcode 输出了大量的信息&#xff0c;其中…...

ECharts实现数据可视化入门详解

文章目录 ECharts实现数据可视化入门详解一、引言二、基础配置1.1、代码示例 三、动态数据与交互2.1、代码示例 四、高级用法1、多图表组合1.1、在同一容器中绘制多个图表1.2、创建多个容器并分别初始化 ECharts 实例1.3、实现多图联动 五、总结 ECharts实现数据可视化入门详解…...

LRM-典型 Transformer 在视觉领域的应用,单个图像生成3D图像

https://yiconghong.me/LRM. 一、Abstract 第一个大型重建模型&#xff08;LRM&#xff09;&#xff0c;它可以在5秒内从单个输入图像预测物体的3D模型。LRM采用了高度可扩展的基于transformer的架构&#xff0c;具有5亿个可学习参数&#xff0c;可以直接从输入图像中预测神经…...

Stream– ESP8266物联网应用,(客户端向服务器发送数据信息 客户端向服务器请求数据信息)

Stream– ESP8266物联网应用 Stream对于ESP8266-Arduino语言来说指的是数据序列。请留意&#xff1a;在C编程中Stream常被翻译作“流”。我们认为将Stream称为数据序列更加直观。因为数据序列这一概念有两个很关键特点。 第一个特点是“序”&#xff0c;即数据序列不能是杂乱…...

win10系统右下角没有显示网络图标 , 打开或关闭系统图标网络灰色

win10系统右下角没有显示网络图标 / 打开或关闭系统图标网络灰色 win10系统右下角没有显示网络图标, 并且打开或关闭系统图标网络灰色 解决方案: 首先&#xff0c;按【Ctrl Alt Del】组合键&#xff0c;然后点击【任务管理器】。任务管理器窗口&#xff0c;找到并选择【Wind…...

Python使用Selenium库获取 网页节点元素、名称、内容的方法

我们要用到一些网页源码信息&#xff0c;例如获取一些节点的class内容&#xff0c; 除了使用Beautifulsoup来解析&#xff0c;还可以直接用Selenium库打印节点&#xff08;元素&#xff09;名称&#xff0c;用来获取元素的文本内容或者标签名。 例如获取下面的class的内容&am…...

onnx文件转pytorch pt模型文件

onnx文件转pytorch pt模型文件 1.onnx2torch转换及测试2.存在问题参考文献 从pytorch格式转onnx格式&#xff0c;官方有成熟的API&#xff1b;那么假如只有onnx格式的模型文件&#xff0c;该怎样转回pytorch格式&#xff1f; https://github.com/ENOT-AutoDL/onnx2torch提供了…...

计算机网络中的SIP协议是什么?

SIP&#xff08;Session Initiation Protocol&#xff0c;会话初始化协议&#xff09;是由IETF&#xff08;Internet Engineering Task Force&#xff0c;因特网工程任务组&#xff09;制定的多媒体通信协议。以下是对SIP的详细简述&#xff1a; 一、SIP的基本概念 SIP是一个…...

Apache Kylin最简单的解析、了解

官网&#xff1a;Overview | Apache Kylin 一、Apache Kylin是什么&#xff1f; 由中国团队研发具有浓厚的中国韵味&#xff0c;使用神兽麒麟&#xff08;kylin&#xff09;为名 的一个OLAP多维数据分析引擎:&#xff08;据官方给出的数据&#xff09; 亚秒级响应&#xff…...

axfbinhexelf文件区别

0 Preface/Foreword axf,bin,hex,elf四个都能存在于嵌入式软件领域。 1 文件介绍 嵌入式软件中常见的文件包含&#xff1a; axf&#xff0c;包含调试信息&#xff0c;文件最大。调试信息放在机器码前面。elfhex&#xff0c;包含地址信息&#xff0c;文件内容较大。bin&#x…...

MySQL表自增id溢出的故障复盘,你是如何解决与监控的

文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons&#xff1a;JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram&#xff0c;自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 &#xff1f; 5 IDEA必装的插件&…...

03、SpirngMVC核心(下)

一、关于RESTful编程风格 什么是RESTful RESTful的英文全称是:Representational State Transfer(表述性状态转移) RESTful是Web服务接口的一种设计风格。它定了一组约束和规范,可以让Web服务接口更加简洁、易于理解、易于扩展、安全可靠。 RESTful对于请求的约束如下:…...

【游戏设计原理】10 - 科斯特的游戏理论

科斯特的游戏理论强调了游戏与学习之间的关系&#xff0c;认为“玩得开心”与“学习”是紧密相连的。换句话说&#xff0c;游戏的核心魅力在于通过适当的挑战和不断的学习进程激发玩家的内啡肽循环&#xff0c;这让玩家在不断的探索和进步中找到乐趣。 科斯特的理论通过游戏是…...

【JAVA】Java项目实战—Java EE项目:客户关系管理(CRM)系统

Java EE项目&#xff1a;客户关系管理&#xff08;CRM&#xff09;系统 一、背景介绍 1.1 Java语言的重要性 Java是一种广泛使用的编程语言&#xff0c;因其跨平台性、面向对象特性以及丰富的生态系统而受到开发者的青睐。Java EE&#xff08;Enterprise Edition&#xff09…...

JAVA 零拷贝技术和主流中间件零拷贝技术应用

目录 介绍Java代码里面有哪些零拷贝技术java 中文件读写方式主要分为什么是FileChannelmmap实现sendfile实现 文件IO实战需求代码编写实战IOTest.java 文件上传阿里云&#xff0c;测试运行代码看耗时为啥带buffer的IO比普通IO性能高&#xff1f;BufferedInputStream为啥性能高点…...

STM32软件IIC驱动TCA9548A多路测量AHT10

STM32软件IIC驱动TCA9548多路测量AHT10 TCA9548AAHT10代码逻辑代码展示现象总结 TCA9548A TCA9548A 有八个可通过 I2C 总线控制的双向转换开关&#xff0c;SCL/SDA 上行对扩展到八个下行对&#xff0c;或者通道&#xff0c;适用于系统中存在I2C目标地址冲突的情况。8路双向转换…...

博弈论3:图游戏SG函数(Graph Games)

目录 一、图游戏是什么 1.游戏特征 2.游戏实例 二、图游戏的必胜策略 1.SG 函数&#xff08;Sprague-Grundy Function&#xff09; 2.必胜策略&#xff08;利用SG函数&#xff09; 3.拿走游戏转化成图游戏&#xff08;Take-away Game -> Graph Game&#xff09; 一、图…...

音视频入门基础:MPEG2-TS专题(17)——FFmpeg源码中,解析TS program map section的实现

一、引言 由《音视频入门基础&#xff1a;MPEG2-TS专题&#xff08;16&#xff09;——PMT简介》可以知道&#xff0c;PMT表&#xff08;Program map table&#xff09;由一个或多个段&#xff08;Transport stream program map section&#xff0c;简称TS program map sectio…...

SQL server学习05-查询数据表中的数据(上)

目录 一&#xff0c;基本格式 1&#xff0c;简单的SQL查询语句 2&#xff0c;关键字TOP 3&#xff0c;关键字DISTINCT 二&#xff0c;模糊查询 1&#xff0c;通配符 三&#xff0c;对结果集排序 1&#xff0c;不含关键字DISTINCT 2&#xff0c;含关键字DISTINCT 3&…...

Transformer记录Attention is all you need

视频&#xff1a; Transformer 原理详解_哔哩哔哩_bilibili 代码&#xff1a; harvardnlp/annotated-transformer: An annotated implementation of the Transformer paper....

JAVA入门:使用IDE开发

JAVA入门&#xff1a;使用IDE开发 什么是IDE IDE&#xff08;Integrated Development Environment&#xff0c;集成开发环境&#xff09;是一种软件应用程序&#xff0c;它为程序开发、软件设计、项目管理等提供全面的设施。 简单来说就是简化开发过程&#xff0c;让编程更加…...

汽车嵌入式软件构建高效技术团队的全面思考

在汽车嵌入式软件开发领域&#xff0c;构建一支高效的通用技术团队至关重要。这类团队负责为各种项目提供可复用、标准化的技术基石&#xff0c;从而提高开发效率、降低成本并确保产品质量。构建这样的团队需要从技术能力、角色分工、标准化与复用、流程管理与质量保证、工具和…...

Debezium源码分析: TopicSelector实现原理与应用

Debezium源码分析: TopicSelector实现原理与应用 Debezium源码分析: TopicSelector实现原理与应用文章目录背景介绍主要功能应用场景实现原理DataCollectionId 接口核心设计工作流程源码分析基础实现默认选择器创建应用示例1. 分库分表场景2. 多租户场景3. 业务领域分组总结设计…...

SpringCloud微服务实战系列:03spring-cloud-gateway业务网关灰度发布

目录 spring-cloud-gateway 和zuul spring webflux 和 spring mvc spring-cloud-gateway 的两种模式 spring-cloud-gateway server 模式下配置说明 grayLb://system-server 灰度发布代码实现 spring-cloud-gateway 和zuul zuul 是spring全家桶的第一代网关组件&#x…...

【恶意软件检测论文】通过提取 API 语义来实现的一个新颖的安卓恶意软件检测方法

目录 摘要1. 引言2. 相关工作2.1. 基于重新训练的恶意软件检测2.2. 基于应用关系图的恶意软件检测2.3. 基于异常样本识别的恶意软件检测2.4. 基于API聚类的恶意软件检测 3. AMDASE概述4. 基于语义距离的API聚类4.1. API特征提取4.2. API句子生成4.3. API句子编码4.4.聚类中心生…...

大模型系列4--开源大模型本地部署到微调(WIP)

背景 一直想真正了解大模型对硬件资源的需求&#xff0c;于是准备详细看一篇视频&#xff0c;将核心要点总结记录下。本文内容参考视频&#xff1a;保姆级教程&#xff1a;6小时掌握开源大模型本地部署到微调&#xff0c;感谢up主 训练成本 训练 > 微调 > 推理训练GPT…...

Linux 磁盘满了怎么办?快速排查和清理方法

当 Linux 磁盘满了&#xff0c;会导致系统无法正常运行&#xff0c;比如无法写入文件、服务停止、甚至系统崩溃。因此&#xff0c;快速排查并清理磁盘空间是非常重要的。以下是详细的排查和解决步骤&#xff1a; 一、快速定位磁盘占用原因 1. 检查磁盘使用情况 使用 df 命令查…...

go 协程练习例题

go 协程练习例题 例1&#xff1a;统计 1-200000 的数字中&#xff0c;哪些是素数例2&#xff1a;使用单通道、2个协程交替读取字符串例3&#xff1a;使用1个管道&#xff0c;2个协程写数据、1个协程读例4&#xff1a;完成一个并发任务调度器&#xff0c;按照指定顺序执行一系列…...

JAVA:访问者模式(Visitor Pattern)的技术指南

1、简述 访问者模式(Visitor Pattern)是一种行为型设计模式,允许你将操作分离到不同的对象中,而无需修改对象本身的结构。这种模式特别适合复杂对象结构中对其元素进行操作的场景。 本文将介绍访问者模式的核心概念、优缺点,并通过详细代码示例展示如何在实际应用中实现…...

如何实现邮箱+验证码登录功能(express+vue+MySQL版)

目录 1. 初始化项目2. 配置环境变量3. 更新数据库4. 编写路由函数5. 前端调用接口 1. 初始化项目 前端根目录&#xff1a;/web 后端根目录&#xff1a;/api_server 安装依赖&#xff1a; npm install express mysql nodemailer randomstring dotenv其中&#xff0c;nodemaile…...

Pycharm访问MySQL数据库·上

1.MySQL驱动模块Connector #导入数据库的驱动工具 import mysql.connector #连接数据库必备的条件 config {"host": "localhost","port": 3306,"user": "root","password": "888888","database&…...

vscode+msys2+clang+xmake c++开发环境搭建

转载请标明出处&#xff1a;小帆的帆的专栏 安装msys2 下载msys2安装包&#xff1a;清华源下载地址安装msys2&#xff1a;安装目录&#xff0c;C:\Softwares\msys64 安装cling工具链&#xff0c;xmake &#xff01;&#xff01;&#xff01;在开始菜单中启动MSYS2 CLANG64,…...

Python面试常见问题及答案5

一、基础语法相关 问题1&#xff1a; Python的可变数据类型和不可变数据类型有哪些&#xff1f; 答案&#xff1a; 在Python中&#xff0c;可变数据类型有列表&#xff08;list&#xff09;、字典&#xff08;dict&#xff09;、集合&#xff08;set&#xff09;。这些数据类型…...

威联通docker无法拉取镜像

链接:威联通TS-464C 折腾--Container Station国内无法拉取镜像_docker_wangguanghe-开放原子开发者工作坊我这里用的是IPV6 ,没有公网资源啊。 wangguanghe...

3D 生成重建034-NerfDiff借助扩散模型直接生成nerf

3D 生成重建034-NerfDiff借助扩散模型直接生成nerf 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 感觉这个论文可能能shapE差不多同时期工作&#xff0c;但是shapE是生成任意种类。 本文提出了一种新颖的单图像视图合成方法NerfDiff&#xff0c;该方法利用神经辐射场 …...

ASP.net Core EntityFramework Code EF code 汇总

Entity FrameWork EF 总结 EF Core EF Core 如果实体模型很多&#xff0c;全部放在 上下文中的 OnModelCreating(ModelBuilder modelBuilder) 不太好维护 可以把实体模型 分离出去&#xff0c;每个类创建一个实体模型 public class BookConfiguration &#xff1a;IEntityT…...