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

uniapp 本地数据库多端适配实例(根据运行环境自动选择适配器)

项目有个需求,需要生成app和小程序,app支持离线数据库,如果当前没有网络提醒用户开启离线模式,所以就随便搞了下,具体的思路就是: 一个接口和多个实现类(类似后端的模板设计模式),例如sqlite实现类,indexedDB实现类等等,根据环境动态选用具体的实现类

indexedDB有些方法没有改,sqlite没有测试,此处就是提供一个思路,只是用来学习和研究着玩了

目录

在这里插入图片描述

class类

BaseApi

import type LocalDB from '@/class/DbClass'
import { tableConfig } from '@/enums/DbEnums'
import { CallBackFunType } from '@/utils/request'
class BaseApi {public localDB: LocalDB;public table: string;public hasTable: boolean;constructor(table: string, localDB: LocalDB){this.table = tablethis.hasTable = falsethis.localDB = localDBif(this.localDB.Db().isOpen()){this.localDB.Db().hasTable(table).then((res:any) => {this.hasTable = res}).catch((res: any) => {console.log("构造初始化失败, table: " + this.table)})}}public getTable(): string{return this.table;}public getHasTable(): boolean{return this.hasTable;}public setHasTable(hasTable:boolean){this.hasTable = hasTable;}/*** 验证是否存在表信息*/public async verifyTable(init: boolean = false): Promise<CallBackFunType<any>>{if(!this.getHasTable() && init){const res = await this.init();if(!res){return new CallBackFunType({}).fail('初始化数据库失败')}else {return new CallBackFunType({}).success('初始化数据库成功');}}return new CallBackFunType({}).success('存在数据库');}/*** 初始化*/public async init(): Promise<boolean>{// 浏览器不能直接新建,需要适配const res = await this.localDB.Db().createTable(this.table, tableConfig[this.table])return res;}
}export default BaseApi;

DbClass

import type SqlAbapter from '@/plugins/db/SqlAbapter'// 根据平台选择适配器
class LocalDB {private db : SqlAbapter;public name : string;public isSupport: boolean;constructor(db:SqlAbapter , name: string, isSupport: boolean){this.db = db;this.name = namethis.isSupport = isSupport}/*** 批量初始化表*/public initDb(tables: Record<string, Record<string, any>>): void{// 验证当前是否开启了离线缓存,验证当前是否支持离线缓存if(!this.isSupport){console.log("当前不支持离线缓存")return;}this.db.open(tables).then((res: boolean) => {if(res){console.log('数据库打开成功')}else {console.log('数据库打开失败')}})}// 验证是否public Db():SqlAbapter{// 验证当前是否开启了离线缓存,验证当前是否支持离线缓存if(!this.isSupport){console.log("当前不支持离线缓存")}return this.db;}
}export default LocalDB;

方法抽象

抽象模版 SqlAbapter.ts


interface SqlAbapter {/*** 数据库是否开启*/isOpen: () => boolean;/*** 开启数据库*/open: (tables: Record<string, Record<string, any>>) => Promise<boolean>;/*** 关闭数据库*/close: () => Promise<boolean>;/*** 是否存在表*/hasTable: (dbTable: string) =>  Promise<boolean>;/*** 创建表*/createTable: (dbTable: string, data: string[]) => Promise<boolean>;/*** 删除表*/dropTable: (dbTable: string) => Promise<boolean>;/*** 新增数据:  indexedDb 重读id会报错*/insertTableData: (dbTable: string, data:Record<string,any>) => Promise<boolean>;/*** 新增或修改*/insertOrReplaceData: (dbTable:string, data:Record<string,any>, condition:Record<string,any>) => Promise<boolean>;/*** 查询数据*/selectTableData: (dbTable:string, condition: Record<string,any>) => Promise<any>;/*** 删除数据*/deleteTableData: (dbTable:string, condition: Record<string,any>) => Promise<boolean>;/*** 更新数据*/updateTableData: (dbTable:string, data: Record<string,any>, condition: Record<string,any>) => Promise<Boolean>;/*** 分页查询*/pullSQL: (dbTable: string, id:string, current: number, size:number) => Promise<any>;}export default SqlAbapter;

sqlite实现

import type SqlAbapter from '@/plugins/db/SqlAbapter'
import { replace, keyValSql, isEmpty, whereSql, updateSetSql } from '@/plugins/utils';
class SqliteAdapter implements SqlAbapter {public dbName: string;public dbPath: string;constructor(dbName: string, dbPath:string){this.dbName = dbName;this.dbPath = dbPath;}// 判断数据库是否打开isOpen() {// 数据库打开了就返回 true,否则返回 falsevar open = plus.sqlite.isOpenDatabase({name: this.dbName,  // 数据库名称path: this.dbPath  // 数据库地址})return open;}// 创建数据库 或 有该数据库就打开open(tables: Record<string, Record<string, any>>):Promise<boolean>  {return new Promise((resolve, reject) => {// 打开数据库plus.sqlite.openDatabase({name: this.dbName,path: this.dbPath,success(e) {resolve(true); // 成功回调// 初始化表 todo: },fail(e) {reject(false);  // 失败回调}})})}hasTable(dbTable: string): Promise<boolean> {let sql = `select * from sqlite_master where type = 'table' and name = '${dbTable}'`return new Promise((resolve, reject) => {// 打开数据库plus.sqlite.executeSql({name: this.dbName,sql: [sql],success(res) {if (res.resultSet.length > 0) {resolve(true); // 成功回调} else {resolve(false);  // 失败回调}},fail(e) {reject(false);  // 失败回调}})})}// 关闭数据库close(): Promise<boolean>  {return new Promise((resolve, reject) => {plus.sqlite.closeDatabase({name: this.dbName,success(e) {resolve(e);},fail(e) {reject(e);}})})}// 数据库建表 sql:'CREATE TABLE IF NOT EXISTS dbTable("id" varchar(50),"name" TEXT) // 创建 CREATE TABLE IF NOT EXISTS 、 dbTable 是表名,不能用数字开头、括号里是表格的表头createTable(dbTable: string, data: string[]): Promise<boolean> {let keys = '';if(!data || data.length <= 0){return new Promise((resolve, reject) => { reject("创建失败,索引不能为空") })}data.forEach((key:string) => {keys = keys + key +",";})keys = replace(keys, ",")// todo: 增加表 属性, varchar等等let sql = `CREATE TABLE IF NOT EXISTS ${dbTable}(${keys})`return new Promise((resolve, reject) => {// executeSql: 执行增删改等操作的SQL语句plus.sqlite.executeSql({name: this.dbName,sql: [sql],success(e) {resolve(true);},fail(e) {reject(false);}})})}// 数据库删表 sql:'DROP TABLE dbTable'dropTable(dbTable: string): Promise<boolean> {return new Promise((resolve, reject) => {plus.sqlite.executeSql({name: this.dbName,sql: [`DROP TABLE ${dbTable}`],success(e) {resolve(true);},fail(e) {reject(false);}})})}// 向表格里添加数据 sql:'INSERT INTO dbTable VALUES('x','x','x')'   对应新增// 或者 sql:'INSERT INTO dbTable ('x','x','x') VALUES('x','x','x')'   具体新增// 插入 INSERT INTO  、 dbTable 是表名、根据表头列名插入列值insertTableData(dbTable: string, data:Record<string,any>): Promise<boolean> {// 判断有没有传参if (dbTable !== undefined && data) {// 判断传的参是否有值if (!isEmpty(data)) {let res = keyValSql(data)// 拼接sql,执行插入var sql = `INSERT INTO ${dbTable} (${res.keySql}) VALUES(${res.valSql})`;// console.log(sql);return new Promise((resolve, reject) => {// 表格添加数据plus.sqlite.executeSql({name: this.dbName,sql: [sql],success(e) {resolve(e);},fail(e) {reject(e);}})})} else {return new Promise((resolve, reject) => { reject("错误添加") })}} else {return new Promise((resolve, reject) => { reject("错误添加") })}}// 根据条件向表格里添加数据  有数据更新、无数据插入// (建表时需要设置主键) 例如 --- "roomid" varchar(50) PRIMARY KEYinsertOrReplaceData(dbTable: string, data: Record<string,any>):Promise<boolean> {// 判断有没有传参if (dbTable !== undefined && data) {if (!isEmpty(data)) {let res = keyValSql(data)let sql = `INSERT OR REPLACE INTO ${dbTable} (${res.keySql}) VALUES(${res.valSql})`;// console.log(sql);return new Promise((resolve, reject) => {// 表格添加数据plus.sqlite.executeSql({name: this.dbName,sql: [sql],success(e) {resolve(e);},fail(e) {reject(e);}})})}else {return new Promise((resolve, reject) => { reject("错误添加") })}} else {return new Promise((resolve, reject) => { reject("错误添加") })}}// 查询获取数据库里的数据 sql:'SELECT * FROM dbTable WHERE lname = 'lvalue''// 查询 SELECT * FROM 、 dbTable 是表名、 WHERE 查找条件 lname,lvalue 是查询条件的列名和列值selectTableData(dbTable:string,  condition: Record<string,any>): Promise<any> {if (dbTable !== undefined) {// 第一个是表单名称,后两个参数是列表名,用来检索let where = ''if(!isEmpty(condition)){where = whereSql(condition)}// if (lname !== undefined && cc !== undefined) {// 	// 两个检索条件// 	var sql = `SELECT * FROM ${dbTable} WHERE ${lname} = '${lvalue}' AND ${cc} = '${dd}'`;// }let sql = `SELECT * FROM ${dbTable}`;if(where){sql = sql + " where " + where;}return new Promise((resolve, reject) => {// 表格查询数据  执行查询的SQL语句plus.sqlite.selectSql({name: this.dbName,sql: sql,success(e) {resolve(e);},fail(e) {reject(e);}})})} else {return new Promise((resolve, reject) => { reject("错误查询") });}}// 删除表里的数据 sql:'DELETE FROM dbTable WHERE lname = 'lvalue''// 删除 DELETE FROM 、 dbTable 是表名、 WHERE 查找条件 lname,lvalue 是查询条件的列名和列值deleteTableData(dbTable:string, condition: Record<string,any>): Promise<boolean> {if (dbTable !== undefined) {let where = ''if(!isEmpty(condition)){where = whereSql(condition)}var sql = `DELETE FROM ${dbTable}`;if(where){sql = sql + " where " + where}return new Promise((resolve, reject) => {// 删除表数据plus.sqlite.executeSql({name: this.dbName,sql: [sql],success(e) {resolve(e);},fail(e) {reject(e);}})})} else {return new Promise((resolve, reject) => { reject("错误删除") });}}// 修改数据表里的数据 sql:"UPDATE dbTable SET 列名 = '列值',列名 = '列值' WHERE lname = 'lvalue'"// 修改 UPDATE 、 dbTable 是表名, data: 要修改的列名=修改后列值, lname,lvalue 是查询条件的列名和列值updateTableData(dbTable:string, data: Record<string,any>, condition: Record<string,any>): Promise<boolean> {if(!dbTable || isEmpty(data)){return new Promise((resolve, reject) => { reject("修改错误") });}let res = updateSetSql(data)var sql = `UPDATE ${dbTable} SET ` + res;if(!isEmpty(condition)){let where = whereSql(condition)if(where){sql = sql + " where " + where}}// WHERE 前面是要修改的列名、列值,后面是条件的列名、列值return new Promise((resolve, reject) => {// 修改表数据plus.sqlite.executeSql({name: this.dbName,sql: [sql],success(e) {resolve(e);},fail(e) {reject(e);}})})}// 获取指定数据条数  sql:"SELECT * FROM dbTable ORDER BY 'id' DESC LIMIT 15 OFFSET 'num'"// dbTable 表名, ORDER BY 代表排序默认正序, id 是排序的条件 DESC 代表倒序,从最后一条数据开始拿// LIMIT 15 OFFSET '${num}',这句的意思是跳过 num 条拿 15 条数据, num 为跳过多少条数据是动态值// 例 初始num设为0,就从最后的数据开始拿15条,下次不拿刚获取的数据,所以可以让num为15,这样就能一步一步的拿完所有的数据pullSQL(dbTable: string, id:string, current: number, size:number): Promise<any> {if(current <= 0){return new Promise((resolve, reject) => { reject("分页查询错误,页码必须从1开始") });}let num = 0;if(current > 0){num = (current - 1) * size}return new Promise((resolve, reject) => {plus.sqlite.selectSql({name: this.dbName,sql: `SELECT * FROM ${dbTable} ORDER BY '${id}' DESC LIMIT ${size} OFFSET '${num}'`,success(e) {resolve(e);},fail(e) {reject(e);}})})}
}export default SqliteAdapter;

indexedDb 实现

import type SqlAbapter from '@/plugins/db/SqlAbapter'
import { keyValSql, isEmpty, whereSql, updateSetSql } from '@/plugins/utils';class IndexDbAdapter implements SqlAbapter {// 这个做法是因为 不同的浏览器获取indexedDB的方式不一样。// mozIndexedDB:火狐浏览器内核;webkitIndexedDB:webkit内核;msIndexedDB:IE内核。public indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;public dbName: string;public dbPath: string;private request: IDBOpenDBRequest | undefined;private db: IDBDatabase | undefined;constructor(dbName: string, dbPath:string){this.dbName = dbName;this.dbPath = dbPath;// this.request = this.indexedDB.open(this.dbName,1)}// 判断数据库是否打开isOpen() {// 数据库打开了就返回 true,否则返回 falseif(this.request == null){return false;}else {return true;}}// 创建数据库 或 有该数据库就打开open(tables: Record<string, Record<string, any>>):Promise<boolean>  {return new Promise((resolve, reject) => {this.request = this.indexedDB.open(this.dbName,1)let _this = this;this.request.onerror = function(event) {console.error('Database error:', event.target?.errorCode);reject("数据库打开失败");};this.request.onupgradeneeded = function(event) {console.log('onupgradeneeded ====>', event)resolve(true);_this.db =  (event.target as IDBOpenDBRequest).result;// _this.createTable('ttt', ['name', 'val'])if(!isEmpty(tables)){let tabs = Object.keys(tables)tabs.forEach((tab:string) => {_this.hasTable(tab).then((res: boolean) => {if(res){// 当前console.log(`当前数据库: ${tab} 已存在,不进行初始化`)}else {// 初始化表_this.createTable(tab, Object.keys(tables[tab])).then((creRes:any) => {if(creRes){console.log(`当前数据库: ${tab} 初始化完成`)}else {console.log(`当前数据库: ${tab} 初始化失败`)}})}})})}};this.request.onsuccess = function(event) {_this.db = (event.target as IDBOpenDBRequest).result;resolve(true);console.log('Database opened successfully');};})}hasTable(dbTable: string): Promise<boolean> {let _this = this;return new Promise((resolve, reject) => {let res = _this.db?.objectStoreNames.contains(dbTable) as booleanconsole.log('hasTable this.db? =====>', this.db)console.log('hasTable =====>', res)resolve(res);})}// 关闭数据库close(): Promise<boolean>  {let _this = this;return new Promise((resolve, reject) => {_this.db?.close();resolve(true);})}// 数据库建表 sql:'CREATE TABLE IF NOT EXISTS dbTable("id" varchar(50),"name" TEXT) // 创建 CREATE TABLE IF NOT EXISTS 、 dbTable 是表名,不能用数字开头、括号里是表格的表头createTable(dbTable: string, data: string[]): Promise<boolean> {if(!data || data.length <= 0){return new Promise((resolve, reject) => { reject("创建失败,索引不能为空") })}let _this = this;return new Promise((resolve, reject) => {// executeSql: 创建表const objectStore = _this.db?.createObjectStore(dbTable,{ keyPath: 'id' });data.forEach((key:any) => {objectStore?.createIndex(key, key,  {unique: false})})resolve(true)})}// 数据库删表 sql:'DROP TABLE dbTable'dropTable(dbTable: string): Promise<boolean> {return new Promise((resolve, reject) => {reject(false);})}// 向表格里添加数据 sql:'INSERT INTO dbTable VALUES('x','x','x')'   对应新增// 或者 sql:'INSERT INTO dbTable ('x','x','x') VALUES('x','x','x')'   具体新增// 插入 INSERT INTO  、 dbTable 是表名、根据表头列名插入列值insertTableData(dbTable: string, data:Record<string,any>): Promise<boolean> {// 判断有没有传参if (dbTable !== undefined && data) {// 判断传的参是否有值if (!isEmpty(data)) {let _this = this;return new Promise((resolve, reject) => {// 添加数据到对象存储空间let transaction = _this.db?.transaction([dbTable], 'readwrite');const objectStore = transaction?.objectStore(dbTable);let request = objectStore?.add(data) as IDBRequest;// 写入数据的事件监听request.onsuccess = function (event) {resolve(true)console.log('数据写入成功');};request.onerror = function (event) {reject("数据写入失败: " + event?.target?.error?.message)console.log('数据写入失败: event =====》 ', event);}})} else {return new Promise((resolve, reject) => { reject("错误添加") })}} else {return new Promise((resolve, reject) => { reject("错误添加") })}}// 根据条件向表格里添加数据  有数据更新、无数据插入// (建表时需要设置主键) 例如 --- "roomid" varchar(50) PRIMARY KEYinsertOrReplaceData(dbTable: string, data: Record<string,any>):Promise<boolean> {// 判断有没有传参if (dbTable !== undefined && data) {if (!isEmpty(data)) {return new Promise((resolve, reject) => {// 表格添加数据reject(false);})}else {return new Promise((resolve, reject) => { reject("错误添加") })}} else {return new Promise((resolve, reject) => { reject("错误添加") })}}// 查询获取数据库里的数据 sql:'SELECT * FROM dbTable WHERE lname = 'lvalue''// 查询 SELECT * FROM 、 dbTable 是表名、 WHERE 查找条件 lname,lvalue 是查询条件的列名和列值selectTableData(dbTable:string,  condition: Record<string,any>): Promise<any> {if (dbTable !== undefined) {// 第一个是表单名称,后两个参数是列表名,用来检索return new Promise((resolve, reject) => {reject(false);})} else {return new Promise((resolve, reject) => { reject("错误查询") });}}// 删除表里的数据 sql:'DELETE FROM dbTable WHERE lname = 'lvalue''// 删除 DELETE FROM 、 dbTable 是表名、 WHERE 查找条件 lname,lvalue 是查询条件的列名和列值deleteTableData(dbTable:string, condition: Record<string,any>): Promise<boolean> {if (dbTable !== undefined) {return new Promise((resolve, reject) => {reject(false);})} else {return new Promise((resolve, reject) => { reject("错误删除") });}}// 修改数据表里的数据 sql:"UPDATE dbTable SET 列名 = '列值',列名 = '列值' WHERE lname = 'lvalue'"// 修改 UPDATE 、 dbTable 是表名, data: 要修改的列名=修改后列值, lname,lvalue 是查询条件的列名和列值updateTableData(dbTable:string, data: Record<string,any>, condition: Record<string,any>): Promise<boolean> {return new Promise((resolve, reject) => {reject(false);})}// 获取指定数据条数  sql:"SELECT * FROM dbTable ORDER BY 'id' DESC LIMIT 15 OFFSET 'num'"// dbTable 表名, ORDER BY 代表排序默认正序, id 是排序的条件 DESC 代表倒序,从最后一条数据开始拿// LIMIT 15 OFFSET '${num}',这句的意思是跳过 num 条拿 15 条数据, num 为跳过多少条数据是动态值// 例 初始num设为0,就从最后的数据开始拿15条,下次不拿刚获取的数据,所以可以让num为15,这样就能一步一步的拿完所有的数据pullSQL(dbTable: string, id:string, current: number, size:number): Promise<any> {return new Promise((resolve, reject) => {reject(false);})}
}export default IndexDbAdapter;

动态选取

db-plugins

import SqliteAdapter from './db/sqlite/sqliteAdapter';
import IndexDbAdapter from './db/indexedDb/indexedDbAdapter';
import { DbConfig, tableConfig } from '@/enums/DbEnums'
import  LocalDB from '@/class/DbClass'let localDB : LocalDB;
// #ifdef APP-PLUS
//  App 环境使用 sqlite 适配器localDB = new LocalDB(new SqliteAdapter(DbConfig.Name, DbConfig.Path), 'sqlite', true);
// #endif
// #ifdef  MP-WEIXIN
// 小程序环境使用内存适配器,自定义实现// #endif
// #ifdef H5
//  浏览器 环境使用 indexeddb 适配器localDB = new LocalDB(new IndexDbAdapter(DbConfig.Name, DbConfig.Path), 'indexedDb', true);
// #endifconsole.log('当前环境注册的本地数据库为',localDB.name)// 初始化表
localDB.initDb(tableConfig)
export default localDB;

api应用

testService

import {request , CallBackFunType} from '@/utils/request'
import { HttpPath } from '@/enums/constant'
import localDB from '@/plugins/db-plugins'
import type LocalDB from '@/class/DbClass'
import { DbTable, DbConfig } from '@/enums/DbEnums'
import BaseApi from '@/class/baseApiClass'class TestApi extends BaseApi{constructor(table: string, localDB:LocalDB){super(table, localDB)}public save(data: {id: string ,name: string, value: string}) {return request({'url': HttpPath.App + '/dict/type','method': 'post',data}, async (requestConfig: any) => {console.log('离线回调操作: ', requestConfig)const res = await this.verifyTable(true);return new Promise<CallBackFunType<any>>((resolve, reject) => {if(res.code != 200){reject(res)}else{// 执行数据库操作this.localDB.Db().insertTableData(DbTable.Test, data).then((res) => {if(res){resolve(new CallBackFunType({}).success())}else {reject(new CallBackFunType({}).fail())}}).catch((e:any) => {reject(e)})}})})}
}export default new TestApi(DbTable.Test, localDB);

页面使用

<template><view>测试</view>
</template><script lang="ts" setup>import { onLoad } from '@dcloudio/uni-app';import TestApi from '@/api/testService'onLoad(() => {TestApi.save({id:'1231',name: '2321', value: 'dasdas'}).then((res:any) => {console.log(res)})})
</script><style lang="scss">
</style>

执行效果 以浏览器(indexedDb)为例

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

相关文章:

uniapp 本地数据库多端适配实例(根据运行环境自动选择适配器)

项目有个需求&#xff0c;需要生成app和小程序&#xff0c;app支持离线数据库&#xff0c;如果当前没有网络提醒用户开启离线模式&#xff0c;所以就随便搞了下&#xff0c;具体的思路就是&#xff1a; 一个接口和多个实现类&#xff08;类似后端的模板设计模式&#xff09;&am…...

百度觉醒,李彦宏渴望光荣

文 | 大力财经 作者 | 魏力 2025年刚刚开年&#xff0c;被一家名为DeepSeek的初创公司强势改写。在量化交易出身的创始人梁文锋的带领下&#xff0c;这支团队以不到ChatGPT 6%的训练成本&#xff0c;成功推出了性能可与OpenAI媲美的开源大模型。 此成果一经问世&#xff0c;…...

【算法工程】大模型局限性新发现之解决能连github但无法clone项目的问题

最近&#xff0c;linux服务器遇到一个奇怪的问题&#xff0c;能ping通github&#xff0c;但是无法clone git项目&#xff0c;尝试了各种大模型&#xff0c;都提到代理啥的问题&#xff0c;发现没有一个能解决问题。 后来尝试设置 http.sslVerify 为 false&#xff0c;才解决问题…...

SOME/IP-SD -- 协议英文原文讲解3

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 5.1.2.4…...

软件测试八股文,软件测试常见面试合集【附答案】

PS&#xff1a;加上参考答案有几十万字&#xff0c;答案就没有全部放上来了&#xff0c;高清打印版本超过400多页&#xff0c;评论区留言直接获取 1、你的测试职业发展是什么? 2、你认为测试人员需要具备哪些素质 3、你为什么能够做测试这一行 4、测试的目的是什么? 5、…...

数据结构秘籍(一)线性数据结构

1.数组 数组&#xff08;Array&#xff09;是一种很常见的数据结构。它由相同类型的元素&#xff08;element&#xff09;组成&#xff0c;并且是使用一块连续的内存来存储。 我们直接可以利用元素的索引&#xff08;index&#xff09;计算出该元素对应的存储地址。 数组的特…...

TFChat:腾讯大模型知识引擎(DeepSeek R1)+飞书机器人实现AI智能助手

效果 TFChat项目地址 https://github.com/fish2018/TFChat 腾讯大模型知识引擎用的是DeepSeek R1&#xff0c;项目为sanic和redis实现&#xff0c;利用httpx异步处理流式响应&#xff0c;同时使用buffer来避免频繁调用飞书接口更新卡片的网络耗时。为了进一步减少网络IO消耗&…...

使用消息队列怎样防止消息重复?

大家好&#xff0c;我是君哥。 使用消息队列时&#xff0c;我们经常会遇到一个可能对业务产生影响的问题&#xff0c;消息重复。在订单、扣款、对账等对幂等有要求的场景&#xff0c;消息重复的问题必须解决。 那怎样应对重复消息呢&#xff1f;今天来聊一聊这个话题。 1.三…...

MySQL安装多版本与版本切换

起因 今天在将一个项目部署到本地&#xff0c;想着是先找到一个功能差不多的开源项目&#xff0c;再在这基础之上进行改动&#xff0c;找到的这个项目使用的MySQL版本是MySQL5.7&#xff0c;应该是比较古早的项目了&#xff0c;但是我现在装的是8.4版本的&#xff0c;所以涉及…...

Docker02 - 深入理解Docker

深入理解Docker 文章目录 深入理解Docker一&#xff1a;Docker镜像原理1&#xff1a;镜像加载原理1.1&#xff1a;unionFS1.2&#xff1a;加载原理 2&#xff1a;分层理解 二&#xff1a;容器数据卷详解1&#xff1a;什么是容器数据卷2&#xff1a;使用数据卷3&#xff1a;具名…...

检查SSH安全配置-sshd服务端未认证连接最大并发量配置

介绍 MaxStartups参数指到SSH守护进程的未经身份验证的最大并发连接数。 逻辑依据 为防止系统因大量待处理的身份验证连接尝试而出现拒绝服务的情况&#xff0c;请使用 MaxStartups 的速率限制功能来保护 sshd 登录的可用性&#xff0c;并防止守护进程不堪重负。 检查方法 …...

HarmonyOS Design 介绍

HarmonyOS Design 介绍 文章目录 HarmonyOS Design 介绍一、HarmonyOS Design 是什么&#xff1f;1. 设计系统&#xff08;Design System&#xff09;2. UI 框架的支持3. 设计工具和资源4. 开发指南5. 与其他设计系统的对比总结 二、HarmonyOS Design 特点 | 应用场景1. Harmon…...

C++中的多重继承

在 C 中&#xff0c;多重继承是一种允许一个类同时继承多个基类的特性。这意味着派生类可以继承多个基类的属 性和方法。 多重继承增加了语言的灵活性&#xff0c;但同时也引入了额外的复杂性&#xff0c;特别是当多个基类具有相同 的成员时。 基本概念 在多重继承中&#xff…...

Java基础第14天-坦克大战【1】

Java绘图坐标体系 像素 计算机在屏幕上显示的内容都是由屏幕上的每一个像素组成的。如&#xff0c;计算机显示器的分辨率是800x600&#xff0c;表示计算机屏幕上的每一行由800个点组成&#xff0c;共有600行&#xff0c;整个计算机屏幕共有480000个像素。像素是一个密度单位。…...

Java线程池入门04

1. 提交任务的两种方式 executorsubmit 2. executor executor位于Executor接口中 public interface Executor {void executor(Runnable command); }executor提交的是无返回值的任务 下面是一个具体的例子 package LearnThreadPool; import java.util.concurrent.ExecutorSe…...

【论文笔记-ECCV 2024】AnyControl:使用文本到图像生成的多功能控件创建您的艺术作品

AnyControl&#xff1a;使用文本到图像生成的多功能控件创建您的艺术作品 图1 AnyControl的多控制图像合成。该研究的模型支持多个控制信号的自由组合&#xff0c;并生成与每个输入对齐的和谐结果。输入到模型中的输入控制信号以组合图像显示&#xff0c;以实现更好的可视化。 …...

计算机毕业设计 ——jspssm519Springboot 的幼儿园管理系统

作者&#xff1a;程序媛9688 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等。 &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff08;免费咨询指导选题&#xff09;&#xf…...

山东大学软件学院人工智能导论实验之知识库推理

目录 实验目的&#xff1a; 实验代码&#xff1a; 实验内容&#xff1a; 实验结果 实验目的&#xff1a; 输入相应的条件&#xff0c;根据知识库推理得出相应的知识。 实验代码&#xff1a; def find_data(input_process_data_list):for epoch, data_process in enumerat…...

【Uniapp-Vue3】点击将内容复制到剪切板

具体使用方法在官网&#xff1a; uni-app官网https://uniapp.dcloud.net.cn/api/system/clipboard.html大致使用方法如下&#xff1a; // value是需要复制的值 function copyValue (value) { uni.setClipboardData({data: value,success: res>{// 复制成功逻辑},fail:err&…...

英伟达 Isaac Sim仿真平台体验【2】

一、产品基础信息 仿真平台&#xff1a;NVIDIA Isaac Sim 4.1.0硬件配置&#xff1a;NVIDIA RTX 4090 2 (24GB显存)核心特性&#xff1a; Omniverse内核的多GPU物理加速原生PyTorch/TensorFlow集成支持基于USD的场景构建体系 二、GPU加速仿真实战 ▶ 多球体跌落测试 操作步…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

DiscuzX3.5发帖json api

参考文章&#xff1a;PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下&#xff0c;适配我自己的需求 有一个站点存在多个采集站&#xff0c;我想通过主站拿标题&#xff0c;采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...

深入理解 C++ 左值右值、std::move 与函数重载中的参数传递

在 C 编程中&#xff0c;左值和右值的概念以及std::move的使用&#xff0c;常常让开发者感到困惑。特别是在函数重载场景下&#xff0c;如何合理利用这些特性来优化代码性能、确保语义正确&#xff0c;更是一个值得深入探讨的话题。 在开始之前&#xff0c;先提出几个问题&…...

基于django+vue的健身房管理系统-vue

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.8数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat12开发软件&#xff1a;PyCharm 系统展示 会员信息管理 员工信息管理 会员卡类型管理 健身项目管理 会员卡管理 摘要 健身房管理…...