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

Kotlin 跨平台 SqliteNow 全平台数据持久化方案

Kotlin 跨平台 SqliteNow 全平台数据持久化方案1. 环境与依赖配置1.0 创建一个Kotlin 多平台项目1.1 版本声明libs.versions.toml1.2 项目级插件配置build.gradle.kts1.3 模块级依赖配置app/shared/build.gradle.kts1.4 Web 平台配置Webpack1.5 WasmJs 平台资源复制配置2 创建数据库2.0 添加数据库构建脚本2.1 添加学生的Kotlin类2.2 添加学生表和基础查询语句2.3 测试你的数据库3. 测试数据库3.0 在JVM平台测试数据库3.1 在Web Js平台测试数据库3.2 在Web Wasm平台测试数据库3.3 Web平台常见错误修复SqliteNow 是一款面向 Kotlin MultiplatformKMP的全平台 SQLite 持久化库它通过编译时 SQL 验证、类型安全的查询构建器以及跨平台Android、iOS、Desktop、Web的统一 API为 KMP 项目提供了高效、可靠的数据存储解决方案。本文将以一个学生信息管理为例详细介绍如何从零开始集成 SqliteNow完成表结构定义、数据操作并在 JVMDesktop与 WebJS/Wasm平台上验证数据持久化效果。项目源码本文涉及的多平台库源地址可在 GitHub - sqlitenow-kmp 查看。详情教程可在 GitHub sqlitenow-kmp wiki 查看。1. 环境与依赖配置1.0 创建一个Kotlin 多平台项目在IntelliJ IDEA 2026.1.2中创建一个Kotlin多平台项目, 项目目录如下1.1 版本声明libs.versions.toml首先在项目的gradle/libs.versions.toml中声明所需库的版本[versions] android-minSdk 26 # sqlitenow 需要最低SDK版本 26 kotlin 2.3.21 sqlite 2.6.2 sqlitenow 0.9.1 kotlinx-datetime 0.8.0 kotlinx-serialization-json 1.11.0 [libraries] sqlite-bundled { module androidx.sqlite:sqlite-bundled, version.ref sqlite } sqlitenow-core { module dev.goquick.sqlitenow:core, version.ref sqlitenow } kotlinx-datetime { module org.jetbrains.kotlinx:kotlinx-datetime, version.ref kotlinx-datetime } kotlinx-serialization-json { module org.jetbrains.kotlinx:kotlinx-serialization-json, version.ref kotlinx-serialization-json } [plugins] sqlitenow { id dev.goquick.sqlitenow, version.ref sqlitenow } kotlinSerialization { id org.jetbrains.kotlin.plugin.serialization, version.ref kotlin }1.2 项目级插件配置build.gradle.kts在项目根目录的build.gradle.kts中声明插件apply false 表示不在根项目直接应用plugins{alias(libs.plugins.sqlitenow)applyfalsealias(libs.plugins.kotlinSerialization)applyfalse}1.3 模块级依赖配置app/shared/build.gradle.kts在共享模块app/shared的build.gradle.kts中应用插件并配置平台特定依赖, 然后同步项目plugins{alias(libs.plugins.sqlitenow)alias(libs.plugins.kotlinSerialization)}kotlin{sourceSets{androidMain.dependencies{implementation(libs.sqlite.bundled)}iosMain.dependencies{implementation(libs.sqlite.bundled)}jvmMain.dependencies{implementation(libs.sqlite.bundled)}commonMain.dependencies{implementation(libs.sqlitenow.core)implementation(libs.kotlinx.datetime)implementation(libs.kotlinx.serialization.json)}}}1.4 Web 平台配置Webpack对于 Web 平台JS 目标需要在app/webApp模块中配置 Webpack以正确处理 SQL.js 的 WASM 资源。创建webpack.config.d/sqljs.jsconfig.resolve{fallback:{fs:false,path:false,crypto:false,}};config.moduleconfig.module||{};config.module.rulesArray.isArray(config.module.rules)?config.module.rules:[];config.module.rules.push({test:/sql-wasm\.wasm$/,type:asset/resource,});constCopyWebpackPluginrequire(copy-webpack-plugin);config.plugins.push(newCopyWebpackPlugin({patterns:[../../node_modules/sql.js/dist/sql-wasm.wasm]}));1.5 WasmJs 平台资源复制配置对于 WebAssemblyWasmJs目标需在共享模块的构建脚本中添加资源复制任务确保 WASM 文件能被正确打包。在app/shared/build.gradle.kts的kotlin块后添加kotlin{sourceSets{webMain.dependencies{implementation(devNpm(copy-webpack-plugin,11.0.0))implementation(npm(sql.js,1.13.0))}}}tasks.namedProcessResources(wasmJsProcessResources){valrootBuildDirrootProject.layout.buildDirectoryvalsqlitenowPathwasm/node_modules/sqlitenow-kmp-library-corevalmoveFileListlistOf(sql-wasm.wasm,sqlitenow-sqljs.js,sqlitenow-indexeddb.js)moveFileList.forEach{fileName-from(rootBuildDir.file($sqlitenowPath/$fileName))}duplicatesStrategyDuplicatesStrategy.INCLUDE}构建完成后检查app/shared/build/processedResources/wasmJs/main中是否包含以下三个文件sql-wasm.wasm,sqlitenow-sqljs.js,sqlitenow-indexeddb.js2 创建数据库2.0 添加数据库构建脚本在app/shared模块级别build.gradle.kts的中添加数据库构建脚本sqliteNow{databases{create(AppDatabase){packageName.set(com.example.sqliteNow)debugfalse}}}2.1 添加学生的Kotlin类在app/shared/commonMain中创建sql目录, 然后在该目录下创建AppDatabase目录与构建脚本中名称相同最后在AppDatabase目录下, 创建schema和queries目录在app/shared/commonMain中创建Student.kt文件, 表示数据库中的学生实例packageorg.example.kmpsqlitenowdemoimportkotlinx.datetime.LocalDateimportkotlinx.serialization.SerializableSerializableenumclassGender{MALE,FEMALE}dataclassStudent(valid:Long0,valname:String,valage:Int,valgender:Gender,valbirthDate:LocalDate)2.2 添加学生表和基础查询语句在schema目录中, 创建一个学生表student.sqlCREATETABLEIFNOTEXISTSstudent(idINTEGERPRIMARYKEYNOTNULL,nameTEXTNOTNULL,ageINTEGERNOTNULL,-- {fieldgender, propertyTypeorg.example.kmpsqlitenowdemo.Gender, adaptercustom}genderTEXTNOTNULL,-- {fieldbirthDate, propertyTypekotlinx.datetime.LocalDate, adaptercustom}birthDateTEXTNOTNULL);在queries目录中创建student目录然后创建一个查询全部语句selectAll.sql-- { queryResultStudentEntity }SELECT*FROMstudent;在queries/student目录中创建一个添加学生的语句add.sqlINSERTINTOstudent(name,age,gender,birthDate)VALUES(:name,:age,:gender,:birthDate);最后同步项目运行 Gradle 任务生成数据库代码./gradlew :app:shared:generateAppDatabase2.3 测试你的数据库在app/shared/commonMain中创建testDatabase.kt文件, 用于测试数据库, 如果没有学生George, 那么会添加, 然后输出学生表packageorg.example.kmpsqlitenowdemoimportcom.example.sqliteNow.AppDatabaseimportcom.example.sqliteNow.StudentQueryimportcom.example.sqliteNow.VersionBasedDatabaseMigrationsimportdev.goquick.sqlitenow.common.resolveDatabasePathimportdev.goquick.sqlitenow.core.util.fromSqliteDateimportdev.goquick.sqlitenow.core.util.toSqliteDateimportkotlinx.coroutines.delayimportkotlinx.datetime.LocalDateimportkotlinx.serialization.json.Jsonimportkotlin.time.Duration.Companion.millisecondssuspendfuntestDatabase(){valdbAppDatabase(dbNameresolveDatabasePath(dbNamedatabase.db,appNameKmpSqliteNowDemo),migrationVersionBasedDatabaseMigrations(),studentAdaptersAppDatabase.StudentAdapters(genderToSqlValue{gender-Json.encodeToString(gender)},sqlValueToGender{string-Json.decodeFromString(string)},birthDateToSqlValue{localDate-localDate.toSqliteDate()},sqlValueToBirthDate{string-LocalDate.fromSqliteDate(string)}))db.open()println([Database] opened)valstudentListdb.student.selectAll.asList()println([Database] studentList:$studentList)if(studentList.find{it.nameGeorge}null){valparamsStudentQuery.Add.Params(nameGeorge,age19,genderGender.MALE,birthDateLocalDate(year2003,month7,day27))db.student.add(params)println([Database] add George successful)}valnowStudentListdb.student.selectAll.asList()println([Database] nowStudentList:$nowStudentList)delay(1000.milliseconds)db.close()println([Database] closed)}在app/shared/commonMain中App.kt文件的App函数下, 添加下面代码, 用于测试数据库funApp(){LaunchedEffect(Unit){testDatabase()}// ...}3. 测试数据库3.0 在JVM平台测试数据库然后先在desktop平台运行一下, 会产生以下输出[Database] opened [Database] studentList: [] [Database] add George successful [Database] nowStudentList: [StudentEntity(id1, nameGeorge, age19, genderMALE, birthDate2003-07-27)] [Database] closed重新运行输出结果如下, 说明学生George成功添加到了数据库中, 完成了持久化[Database] opened [Database] studentList: [StudentEntity(id1, nameGeorge, age19, genderMALE, birthDate2003-07-27)] [Database] nowStudentList: [StudentEntity(id1, nameGeorge, age19, genderMALE, birthDate2003-07-27)] [Database] closed3.1 在Web Js平台测试数据库在web Js平台也运行一下[SqliteNow][OPFS] Using Origin Private File System persistence for database.db [SqliteNow] No persisted snapshot for database.db [SqlJs] loading sql.js module… [SqlJs] sql.js module loaded [SqlJs] Opening database.db with empty in-memory database [Database] opened [Database] studentList: [] [Database] add George successful [Database] nowStudentList: [StudentEntity(id1, nameGeorge, age19, genderMALE, birthDate2003-07-27)] [Database] closed重新运行结果如下[SqliteNow][OPFS] Using Origin Private File System persistence for database.db [SqliteNow] Restored 8192 bytes for database.db [SqlJs] loading sql.js module… [SqlJs] sql.js module loaded [SqlJs] Opening database.db from persisted snapshot (8192 bytes) [Database] opened [Database] studentList: [StudentEntity(id1, nameGeorge, age19, genderMALE, birthDate2003-07-27)] [Database] nowStudentList: [StudentEntity(id1, nameGeorge, age19, genderMALE, birthDate2003-07-27)] [Database] closed说明学生George成功添加到了数据库中, 完成了持久化3.2 在Web Wasm平台测试数据库在web WasmJs平台也运行一下(sqlitenow) [sqlitenow] [SqliteNow][IndexedDB] Using IndexedDB persistence for database.db [SqliteNow] No persisted snapshot for database.db (sqlitenow) [sqlitenow] [SqlJs][Wasm] Loading sql.js module… (sqlitenow) [sqlitenow] [SqlJs][Wasm] sql.js module ready (sqlitenow) [sqlitenow] [SqlJs][Wasm] Kotlin opening database.db without snapshot (new database) [Database] opened [Database] studentList: [] [Database] add George successful [Database] nowStudentList: [StudentEntity(id1, nameGeorge, age19, genderMALE, birthDate2003-07-27)] [Database] closed重新运行结果如下(sqlitenow) [sqlitenow] [SqliteNow][IndexedDB] Using IndexedDB persistence for database.db [SqliteNow] Restored 8192 bytes for database.db (sqlitenow) [sqlitenow] [SqlJs][Wasm] Loading sql.js module… (sqlitenow) [sqlitenow] [SqlJs][Wasm] sql.js module ready (sqlitenow) [sqlitenow] [SqlJs][Wasm] Kotlin opening database.db with snapshot bytes8192 [Database] opened [Database] studentList: [StudentEntity(id1, nameGeorge, age19, genderMALE, birthDate2003-07-27)] [Database] nowStudentList: [StudentEntity(id1, nameGeorge, age19, genderMALE, birthDate2003-07-27)] [Database] closed说明学生George成功添加到了数据库中, 完成了持久化3.3 Web平台常见错误修复如果在web平台中出现打开数据库后找不到student表的错误或者表格字段错误等等请在浏览器设置中清除浏览数据在尝试这将清除你在开发环境浏览器中保留的IndexedDB如果Web Wasm平台出现下面错误请运行位于web平台中的 Gradle 自定义任务tasks.namedProcessResources(wasmJsProcessResources){valrootBuildrootProject.layout.buildDirectoryvalsqlitenowPathwasm/node_modules/sqlitenow-kmp-library-corefrom(rootBuild.file($sqlitenowPath/sqlitenow-sqljs.js),rootBuild.file($sqlitenowPath/sql-wasm.wasm),rootBuild.file($sqlitenowPath/sqlitenow-indexeddb.js))duplicatesStrategyDuplicatesStrategy.INCLUDE}错误截图如下

相关文章:

Kotlin 跨平台 SqliteNow 全平台数据持久化方案

Kotlin 跨平台 SqliteNow 全平台数据持久化方案1. 环境与依赖配置1.0 创建一个Kotlin 多平台项目1.1 版本声明(libs.versions.toml)1.2 项目级插件配置(build.gradle.kts)1.3 模块级依赖配置(app/shared/build.gradle.…...

5大长期记忆系统终极横评!谁是AI Agent的「最强大脑」

🚀 5大长期记忆系统终极横评!谁是AI Agent的「最强大脑」? AI Agent 的「长期记忆」能力,决定了它能否真正拥有"持续学习"和"深度理解"的核心竞争力。 我们耗时数周,对 虾觅 Xiami、AgentMemory…...

一多操作系统的生命体架构与当前主流开发语言的区别

这套架构与当前主流开发语言的区别,本质上就是**“造物主”与“工匠”**的区别。 目前的编程语言(无论是 C、Java 还是 Python)都是在教计算机**“怎么做”(How),而一多 OS 的生物学构架是在告诉系统“要什…...

7天深度拆解:openpilot自动驾驶系统技术实现与二次开发指南

7天深度拆解:openpilot自动驾驶系统技术实现与二次开发指南 【免费下载链接】openpilot openpilot is an operating system for robotics. Currently, it upgrades the driver assistance system on 300 supported cars. 项目地址: https://gitcode.com/GitHub_Tr…...

戴森球计划工厂蓝图架构深度解析:构建高效星际生产线的核心策略

戴森球计划工厂蓝图架构深度解析:构建高效星际生产线的核心策略 【免费下载链接】FactoryBluePrints 游戏戴森球计划的**工厂**蓝图仓库 项目地址: https://gitcode.com/GitHub_Trending/fa/FactoryBluePrints FactoryBluePrints 项目作为戴森球计划游戏中最…...

BilibiliDown:简单三步掌握B站视频下载的终极指南

BilibiliDown:简单三步掌握B站视频下载的终极指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/Bi…...

华硕笔记本G-Helper显示管理全攻略:从色彩异常到专业校准的5步解决方案

华硕笔记本G-Helper显示管理全攻略:从色彩异常到专业校准的5步解决方案 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivob…...

GDScriptDecomp:让Godot游戏逆向工程变得触手可及

GDScriptDecomp:让Godot游戏逆向工程变得触手可及 【免费下载链接】gdsdecomp Godot reverse engineering tools 项目地址: https://gitcode.com/GitHub_Trending/gd/gdsdecomp 你是否曾遇到过这样的情况:手头有一个Godot引擎开发的游戏&#xff…...

Windows 环境下 NVM 安装与 Node.js 版本管理完全指南

💡 为什么需要 NVM? 作为前端开发者,你是否遇到过这些困扰: 场景痛点新项目要求 Node 20,老项目依赖 Node 16频繁卸载重装,浪费时间团队协作时环境不一致代码在同事电脑上跑不通全局安装的依赖版本冲突升…...

计算机图形学——四、光栅化与消隐

第四章 光栅转化与消隐 重点总结 一、光栅转化(Rasterization) 定义:把用数学描述的图形(如三角形)变成屏幕上一个个像素点。 1. 多边形扫描转换 顶点表示 → 点阵表示:把多边形的顶点坐标,转成…...

c#string字符串

//API 应用程序接口 内置函数 //字符串的属性 string a "abcd";//表示字符串中 字符的个数Console.WriteLine(a.Length);//字符串是可以通过 索引 取值的 因为string类内部顶一个一个索引器char c a[2];Console.WriteLine(c);string s1 "abc";st…...

四大音乐平台一键解析:免费开源music-api打破会员壁垒

四大音乐平台一键解析:免费开源music-api打破会员壁垒 【免费下载链接】music-api Music API 项目地址: https://gitcode.com/gh_mirrors/mu/music-api 在音乐流媒体平台林立的今天,你是否曾被各大平台的会员壁垒所困扰?想听周杰伦的歌…...

有哪些AI论文软件是真的适配学科专业,而不是模板套话?

在 AI 写作技术迅猛发展的今天,各类论文工具层出不穷,看似能快速完成写作任务,实则多数是内容空洞、逻辑混乱、格式随意的“模板复制器”,生成的文章缺乏专业深度,充斥着机械化的表达方式。真正具备学术价值的 AI 论文…...

开发AI应用时利用Taotoken实现多模型聚合与路由策略

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 开发AI应用时利用Taotoken实现多模型聚合与路由策略 应用场景类,面向正在构建复杂AI应用的架构师或开发者,…...

3步掌握React Easy Crop:从零到精通的图像裁剪完整指南

3步掌握React Easy Crop:从零到精通的图像裁剪完整指南 【免费下载链接】react-easy-crop A React component to crop images/videos with easy interactions 项目地址: https://gitcode.com/gh_mirrors/re/react-easy-crop 你是否在为React应用中的图片裁剪…...

FlashAttention 在昇腾NPU上的极致优化

刚接触 FlashAttention 那会,我被一个困惑砸懵了:明明 Attention 机制的计算量已经是 O(n) 了,业界还在拼命优化它,图什么? 直到我看见一组数据才明白——训练一个 1750 亿参数的 GPT-3,光是 Attention 计…...

GeoSeg:突破性混合Transformer架构实现高效遥感图像语义分割

GeoSeg:突破性混合Transformer架构实现高效遥感图像语义分割 【免费下载链接】GeoSeg UNetFormer: A UNet-like transformer for efficient semantic segmentation of remote sensing urban scene imagery, ISPRS. Also, including other vision transformers and C…...

2026第四届“盘古石杯“晋级赛 手机取证 手搓复盘(write up)

手机取证1. 分析黄志远phone.E01检材,黄志远手机总共安装了多少款短视频应用?[答案格式:1]apk 分析里面,4 个。当时把 b 站也算上了2. 分析黄志远phone.E01检材,黄志远手机安装的龙虾应用的包名是什么?[答案…...

当AI推理遭遇通信瓶颈时,NIXL如何重新定义高性能数据传输架构?

当AI推理遭遇通信瓶颈时,NIXL如何重新定义高性能数据传输架构? 【免费下载链接】nixl NVIDIA Inference Xfer Library (NIXL) 项目地址: https://gitcode.com/gh_mirrors/ni/nixl 在大规模分布式AI推理场景中,数据传输和通信瓶颈已成为…...

为什么我总是想很多,却很难开始做?

为什么我总是想很多,却很难开始做? 有一种人,脑子从来停不下来。 走路在想,洗澡在想,睡前还在想。 想人生方向,想技术路线,想项目结构,想商业模式,想内容选题&#xff0c…...

2026年亲测AI论文写作软件指南(高效定稿版)

为解决学术写作中效率与合规两大核心痛点,本文精选8款高适配性 AI 论文写作工具(按综合优先级排序),围绕中文学术规范适配、真实参考文献生成、格式标准化、高性价比四大核心维度进行测评,同时配套分场景精准选型方案与…...

如何在C加加项目中快速接入Taotoken的多模型API服务

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 如何在C项目中快速接入Taotoken的多模型API服务 对于使用C进行开发的工程师而言,直接调用HTTP API是集成第三方服务最灵…...

FastGithub:5分钟告别GitHub龟速访问,开发效率提升3倍的终极方案

FastGithub:5分钟告别GitHub龟速访问,开发效率提升3倍的终极方案 【免费下载链接】FastGithub github定制版的dns服务,解析访问github最快的ip 项目地址: https://gitcode.com/gh_mirrors/fa/FastGithub 你是否经历过这样的场景&#…...

(毕业必看)实测好用的一键生成论文工具,毕业生收藏备用

毕业季论文写作真的太难了吗?选题卡壳、文献找不全、写起来没思路、查重反复修改、格式总出错…… 这份实测好用的AI论文工具合集,涵盖中英文写作、全流程辅助、专项功能、免费与高性价比类型,从开题到定稿全程帮你搞定,毕业生快收…...

C251嵌入式开发:Flash到RAM函数复制技术详解

1. 项目概述 在嵌入式开发中,有时我们需要将某些关键函数从Flash存储器复制到RAM中执行。这种需求通常出现在需要对Flash进行擦写操作的场景中,比如固件在线升级(OTA)或参数存储区重配置时。本文将详细介绍如何在C251开发环境中实…...

三星固件下载神器Bifrost:跨平台一站式解决方案深度解析

三星固件下载神器Bifrost:跨平台一站式解决方案深度解析 【免费下载链接】Bifrost Cross-platform tool for downloading Samsung mobile device firmware. 项目地址: https://gitcode.com/gh_mirrors/sa/Bifrost Bifrost是一款基于Kotlin Multiplatform构建…...

Infineon C167芯片Flash编程与MEMTOOL使用指南

1. C167系列芯片片上Flash编程方法解析在嵌入式系统开发中,片上Flash编程是每个工程师都需要掌握的核心技能。对于使用Infineon C167系列微控制器的开发者来说,了解如何可靠地编程片上Flash存储器尤为重要。本文将详细介绍使用MEMTOOL工具进行C167芯片Fl…...

ESP32如何实现专业级音频录制?探索开源录音解决方案

ESP32如何实现专业级音频录制?探索开源录音解决方案 【免费下载链接】esp32_SoundRecorder ESP32 Sound recorder with simple code in arduino-esp32. (I2S interface) 项目地址: https://gitcode.com/gh_mirrors/es/esp32_SoundRecorder 在物联网和嵌入式开…...

模型火箭仿真终极指南:OpenRocket从零开始完整教程

模型火箭仿真终极指南:OpenRocket从零开始完整教程 【免费下载链接】openrocket Model-rocketry aerodynamics and trajectory simulation software 项目地址: https://gitcode.com/GitHub_Trending/op/openrocket 你是否曾仰望星空,梦想着亲手设…...

机器人路径规划:安全性与最优性的平衡算法解析

1. 路径规划中的安全性与最优性平衡难题在机器人导航领域,路径规划算法始终面临一个核心矛盾:如何同时保证路径的最优性和安全性。传统A*算法追求最短路径,却常常让机器人贴着障碍物边缘行走;而基于Voronoi图的规划方法虽然能最大…...