数据库操作与数据管理——Rust 与 SQLite 的集成
第六章:数据库操作与数据管理
第一节:Rust 与 SQLite 的集成
在本节中,我们将深入探讨如何在 Rust 中使用 SQLite 数据库,涵盖从基本的 CRUD 操作到事务处理、数据模型的构建、性能优化以及安全性考虑等方面。SQLite 是一个轻量级的关系型数据库,适合嵌入式应用和小型项目。我们将利用 rusqlite 库高效地与 SQLite 进行交互。
1. 使用 rusqlite 进行基本 CRUD 操作
1.1 rusqlite 库的引入
首先,在 Cargo.toml 文件中添加 rusqlite 依赖:
[dependencies]
rusqlite = { version = "0.26", features = ["bundled"] }
1.2 连接到 SQLite 数据库
use rusqlite::{params, Connection, Result};fn connect_to_db() -> Result<Connection> {let conn = Connection::open("my_database.db")?;Ok(conn)
}
1.3 创建表
在执行任何 CRUD 操作之前,我们需要定义数据表。
fn create_table(conn: &Connection) -> Result<()> {conn.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY,name TEXT NOT NULL,age INTEGER NOT NULL)",[],)?;Ok(())
}
1.4 插入数据(Create)
我们可以通过以下代码插入数据到表中:
fn insert_user(conn: &Connection, name: &str, age: i32) -> Result<()> {conn.execute("INSERT INTO users (name, age) VALUES (?1, ?2)",params![name, age],)?;Ok(())
}
1.5 查询数据(Read)
查询数据可以使用 query_map 方法:
fn fetch_users(conn: &Connection) -> Result<Vec<(i32, String, i32)>> {let mut stmt = conn.prepare("SELECT id, name, age FROM users")?;let user_iter = stmt.query_map([], |row| {Ok((row.get(0)?, row.get(1)?, row.get(2)?))})?;let mut users = Vec::new();for user in user_iter {users.push(user?);}Ok(users)
}
1.6 更新数据(Update)
fn update_user_age(conn: &Connection, id: i32, new_age: i32) -> Result<()> {conn.execute("UPDATE users SET age = ?1 WHERE id = ?2",params![new_age, id],)?;Ok(())
}
1.7 删除数据(Delete)
fn delete_user(conn: &Connection, id: i32) -> Result<()> {conn.execute("DELETE FROM users WHERE id = ?1", params![id])?;Ok(())
}
2. 处理事务与连接池
2.1 事务的基本操作
使用事务可以确保一系列数据库操作的原子性。
fn transaction_example(conn: &Connection) -> Result<()> {conn.execute("BEGIN TRANSACTION", [])?;insert_user(conn, "Alice", 30)?;insert_user(conn, "Bob", 25)?;conn.execute("COMMIT", [])?;Ok(())
}
2.2 处理错误与回滚
在执行事务时,如果出现错误,我们应该回滚事务。
fn safe_transaction(conn: &Connection) -> Result<()> {let transaction = conn.transaction()?;transaction.execute("INSERT INTO users (name, age) VALUES (?1, ?2)", params!["Charlie", 28])?;// 故意造成错误transaction.execute("INSERT INTO users (name, age) VALUES (?1, ?2)", params![None::<String>, 28])?;transaction.commit()?;Ok(())
}
2.3 使用连接池
使用连接池可以提高性能,允许多个线程安全地共享数据库连接。
use r2d2::Pool;
use r2d2_sqlite::SqliteConnectionManager;fn create_pool() -> Pool<SqliteConnectionManager> {let manager = SqliteConnectionManager::new("my_database.db");Pool::builder().build(manager).unwrap()
}
3. 数据模型与查询构建
3.1 定义数据模型
使用 Rust 结构体表示数据模型,使数据操作更加明确。
#[derive(Debug)]
struct User {id: i32,name: String,age: i32,
}
3.2 从数据库映射到模型
编写函数将数据库记录映射到模型:
fn map_row_to_user(row: &rusqlite::Row) -> User {User {id: row.get(0).unwrap(),name: row.get(1).unwrap(),age: row.get(2).unwrap(),}
}
3.3 动态查询构建
使用 rusqlite 的 Query 来构建动态查询,以支持不同的查询条件。
fn fetch_users_with_conditions(conn: &Connection, min_age: Option<i32>) -> Result<Vec<User>> {let mut query = String::from("SELECT id, name, age FROM users");let mut params: Vec<&(dyn rusqlite::ToSql + 'static)> = Vec::new();if let Some(age) = min_age {query.push_str(" WHERE age >= ?");params.push(&age);}let mut stmt = conn.prepare(&query)?;let user_iter = stmt.query_map(params, |row| map_row_to_user(row))?;let mut users = Vec::new();for user in user_iter {users.push(user?);}Ok(users)
}
3.4 连接模型与业务逻辑
通过将数据库操作封装在服务层,将数据模型与业务逻辑分离,确保代码的可维护性。
struct UserService {conn: Connection,
}impl UserService {fn new(conn: Connection) -> Self {UserService { conn }}fn add_user(&self, name: &str, age: i32) -> Result<()> {insert_user(&self.conn, name, age)}fn get_all_users(&self) -> Result<Vec<User>> {fetch_users(&self.conn)}
}
4. 性能优化
4.1 使用索引
在处理大量数据时,使用索引可以显著提高查询速度。
fn create_index(conn: &Connection) -> Result<()> {conn.execute("CREATE INDEX idx_user_name ON users (name)", [])?;Ok(())
}
4.2 批量插入
在插入大量数据时,可以使用批量插入来提高性能。
fn batch_insert(conn: &Connection, users: Vec<(String, i32)>) -> Result<()> {let tx = conn.transaction()?;for (name, age) in users {tx.execute("INSERT INTO users (name, age) VALUES (?1, ?2)", params![name, age])?;}tx.commit()?;Ok(())
}
4.3 减少数据库往返
尽量减少与数据库的交互次数,可以通过使用预处理语句或批量操作实现。
5. 安全性考虑
在进行数据库操作时,确保数据的安全性和完整性是至关重要的。以下是一些重要的安全性考虑因素,帮助开发者在使用 Rust 与 SQLite 进行数据库操作时,最大程度地保护应用程序和用户数据。
5.1 防止 SQL 注入
SQL 注入是数据库安全中最常见的攻击方式之一。攻击者通过在 SQL 查询中插入恶意代码,从而获取、修改或删除数据。为了防止 SQL 注入,采用参数化查询是最有效的方法。
fn safe_insert_user(conn: &Connection, name: &str, age: i32) -> Result<()> {conn.execute("INSERT INTO users (name, age) VALUES (?1, ?2)",params![name, age],)?;Ok(())
}
关键点:
- 参数化查询:总是使用参数化查询而不是将用户输入直接拼接到 SQL 字符串中。
- 使用库功能:利用
rusqlite提供的安全 API,避免手动构建 SQL 字符串。
5.2 数据加密
对于敏感数据,尤其是用户的个人信息、信用卡号码等,应该使用加密技术进行存储。Rust 提供了多个加密库,比如 aes、rust-crypto 等,可以轻松实现数据的加密和解密。
use aes::{Aes128, NewBlockCipher, BlockEncrypt, BlockDecrypt};
use aes::block_cipher_trait::generic_array::GenericArray;fn encrypt_data(data: &[u8], key: &[u8; 16]) -> Vec<u8> {let cipher = Aes128::new(GenericArray::from_slice(key));let mut block = GenericArray::clone_from_slice(data);cipher.encrypt_block(&mut block);block.to_vec()
}fn decrypt_data(encrypted_data: &[u8], key: &[u8; 16]) -> Vec<u8> {let cipher = Aes128::new(GenericArray::from_slice(key));let mut block = GenericArray::clone_from_slice(encrypted_data);cipher.decrypt_block(&mut block);block.to_vec()
}
关键点:
- 选择合适的加密算法:选择适合您应用程序需求的加密算法,AES 是一个普遍推荐的选择。
- 密钥管理:确保密钥的安全存储与管理,避免将密钥硬编码到代码中。
5.3 用户输入验证
确保所有用户输入都经过严格验证,避免不合法或恶意数据进入数据库。这包括检查数据类型、长度、格式等。
fn validate_user_input(name: &str, age: i32) -> Result<()> {if name.len() > 50 {return Err(rusqlite::Error::UserFunctionError("Name too long".into()));}if age < 0 {return Err(rusqlite::Error::UserFunctionError("Invalid age".into()));}Ok(())
}
关键点:
- 使用正则表达式:对复杂输入(如电子邮件、电话号码)使用正则表达式进行验证。
- 长度和类型检查:确保输入的数据类型和长度符合预期,防止意外错误和数据损坏。
5.4 身份验证与授权
确保只有经过身份验证的用户才能访问敏感数据或执行重要操作。可以使用 JWT(JSON Web Tokens)或 OAuth 2.0 等现代身份验证方法。
fn verify_user(token: &str) -> Result<bool> {// 此处可使用 JWT 解码和验证逻辑Ok(true) // 简化示例
}
关键点:
- 确保安全的认证流程:实现安全的登录流程,使用 HTTPS 保护数据传输。
- 最小权限原则:每个用户和角色应仅能访问其工作所需的数据,避免不必要的权限。
5.5 日志记录与监控
有效的日志记录和监控可以帮助识别和响应安全事件。记录所有的数据库操作、异常和潜在的安全威胁。
fn log_operation(action: &str) {// 记录数据库操作println!("Operation logged: {}", action);
}
关键点:
- 详细的日志记录:记录操作的时间、执行者和操作内容,便于后续审计。
- 监控与警报:设置监控系统,及时警报异常活动,例如频繁的失败登录尝试。
小结
在数据库操作中,安全性是一个不容忽视的重要方面。通过防止 SQL 注入、加密敏感数据、验证用户输入、实施身份验证和授权机制以及有效的日志记录和监控,可以显著提高应用程序的安全性。务必在开发过程中将这些安全性考虑融入设计中,以保护用户数据和应用程序的完整性。
进一步学习
- 深入研究 Rust 的安全特性:了解 Rust 语言如何在编译时避免许多常见的安全漏洞。
- 数据库安全最佳实践:研究数据库安全的行业标准和最佳实践。
- 加密算法的选择与实现:探索不同加密算法的优缺点,并尝试在 Rust 中实现更多的加密技术。

相关文章:
数据库操作与数据管理——Rust 与 SQLite 的集成
第六章:数据库操作与数据管理 第一节:Rust 与 SQLite 的集成 在本节中,我们将深入探讨如何在 Rust 中使用 SQLite 数据库,涵盖从基本的 CRUD 操作到事务处理、数据模型的构建、性能优化以及安全性考虑等方面。SQLite 是一个轻量…...
Ubuntu 24.10 安装Deepseek(Ollama+openwebui)
一、Ollama安装 1.在线安装 curl -fsSL https://ollama.com/install.sh | sh 如果curl工具没有安装先执行如下命令 sudo apt install curl 验证curl是否安装成功 curl --version 安装的过程中会提示输入当前系统登录用户的密码。 安装提示success后,验证安装 ollama -…...
【漫话机器学习系列】084.偏差和方差的权衡(Bias-Variance Tradeoff)
偏差和方差的权衡(Bias-Variance Tradeoff) 1. 引言 在机器学习模型的训练过程中,我们常常面临一个重要的挑战:如何平衡 偏差(Bias) 和 方差(Variance),以提升模型的泛…...
STM32的HAL库开发---高级定时器---输出比较模式实验
一、高级定时器输出比较模式实验原理 定时器的输出比较模式总共有8种,本文使用其中的翻转模式,当TIMXCCR1TIMXCNT时,翻转OC1REF的电平,OC1REF为输出参考信号,高电平有效,OC1REF信号连接到0C1上面ÿ…...
[论文阅读] Knowledge Fusion of Large Language Models
Knowledge Fusion of Large Language Models (FuseLLM) Methodology 整体Pipeline如下图所示 不同的动物代表不同的LLM。左边第一,第二分别是Ensemble以及Weight Merging方法。最右侧为本文提出的FuseLLM。 Ensemble: 融合多个models的预测结果,比如…...
elementui:el-table支持搜索、切换分页多选功能,以及数据回显
1、el-table相关代码,需注意:row-key"(row) > { return row.id }" 以及 :reserve-selection"true" <div class"boxList"><div class"search-form"><!-- 搜索表单 --><el-form :inline"true&q…...
(ICLR=2025)生成的表征对齐:训练扩散Transformer比你想象的更简单
生成的表征对齐:训练扩散Transformer比你想象的更简单 paper是KAIST发表在ICLR 2025的工作 paper title:REPRESENTATION ALIGNMENT FOR GENERATION: TRAINING DIFFUSION TRANSFORMERS IS EASIER THAN YOU THINK Code:链接 ABSTRACT 最近的研究表明&…...
白嫖RTX 4090?Stable Diffusion:如何给线稿人物快速上色?
大家都知道,在设计的初期,我们通常会先绘制草图,然后再进行上色处理,最终才开始进行最终的设计工作。在这个上色的过程中,配色是至关重要的一环。这不仅方便了内部同事的评审,也让产品方和客户可以直观地了…...
Bash (Bourne-Again Shell)、Zsh (Z Shell)
文章目录 1. 历史背景2. 主要区别3. 功能对比自动补全插件和主题路径扩展提示符定制 4. 性能5. 使用场景6. 如何切换 Shell7. 总结 以下是 Bash 和 Zsh 之间的主要区别,列成表格方便对比: 特性BashZsh默认Shell大多数Linux发行版默认ShellmacOS默认She…...
pikachu[皮卡丘] 靶场全级别通关教程答案 以及 学习方法 如何通过渗透测试靶场挑战「pikachu」来精通Web渗透技巧? 一篇文章搞完这些问题
目录 Pikachu靶场 部署 暴力破解漏洞 学习地址: 靶场练习: 基于表单的暴力破解 验证码绕过(on server) 验证码绕过(on Client) token防爆破? XSS跨站脚本攻击 学习地址: 靶场练习: 反射型xss(get) 反射性xss(post) 存储型xss DOM型xss xss盲打 x…...
汽车零部件工厂如何借助安灯呼叫按钮盒提升生产响应速度
在现代汽车零部件工厂的生产环境中,高效的信息传递和快速的响应速度是确保生产顺畅运行的关键。然而,传统的口头呼喊或现场沟通方式往往存在信息传递慢、现场嘈杂、责任人难以及时找到等问题,尤其在设备故障或缺料时,这些问题会导…...
【0404】Postgres内核 实现分配一个新的 Object ID (OID)
文章目录 1. 分配一个新 Object ID (OID)1.1 ShmemVariableCache 中 nextOid1.2 写一个 NEXTOID log record1. 分配一个新 Object ID (OID) Postgres内核中分配一个新的 Oid 是由函数 GetNewObjectId() 实现。该函数声明于 transam.h,实现于 varsup.c 源文件。 对于 GetNewO…...
Idea 2024.3 使用CodeGPT插件整合Deepseek
哈喽,大家好,我是浮云,最近国产大模型Deepseek异常火爆,作为程序员我也试着玩了一下,首先作为简单的使用,大家进入官网,点击开始对话即可进行简单的聊天使用,点击获取手机app即可安装…...
「vue3-element-admin」告别 vite-plugin-svg-icons!用 @unocss/preset-icons 加载本地 SVG 图标
🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template 🌺 仓库主页: GitCode︱ Gitee ︱ Github 💖 欢迎点赞 👍 收藏 ⭐评论 …...
C++自研3D教程OPENGL版本---动态批处理的基本实现
又开始找工作了,借机休息出去旅行两个月,顺便利用这段时间整理下以前写的东西。 以下是一个简单的动态批处理实现: #include <GL/glew.h> #include <GLFW/glfw3.h> #include <iostream> #include <vector>// 顶点结…...
docker /var/lib/docker/overlay2目录把磁盘空间占满问题
1、查看服务器磁盘空间 df -h果然100%了,docker系统文件把磁盘空间占满了。 2、进入overlay2目录,查找那个容器工作目录占用最高 cd /var/lib/docker/overlay2du -h --max-depth1详见下图 好家伙占用110G!复制目录名称2c3c48ccac533c5d4a366d45a19bb9…...
SOA(面向服务架构)全面解析
1. 引言 什么是SOA(面向服务架构) SOA(Service-Oriented Architecture,面向服务架构)是一种将应用程序功能以“服务”的形式进行模块化设计的架构风格。这些服务是独立的功能模块,它们通过定义明确的接口…...
华为交换机堆叠配置
一、CSS堆叠集群配置(框式交换机) 1、通过集群卡连接方式组建集群 [SwitchA] set css mode css-card \\配置集群卡连接方式 [SwitchA] set css id 1 \\配置成员交换机的集群ID(缺省值为1) [SwitchA] set css priority 100 \\配…...
蓝桥杯备赛——进制转化相关问题
目录 一、基础概念 二、问题研究(1) 代码解读: 1. transfer 函数 代码功能概述 详细步骤 2. main 函数 代码功能概述 详细步骤 三、运用递归解决 (一) 代码如下: 代码解读: &#…...
Nginx配置 ngx_http_proxy_connect_module 模块及安装
1、配置完互联网yum源后,安装相关依赖软件包 [root@server soft]# yum install -y patch pcre pcre-devel make gcc gcc-c++ openssl openssh [root@server soft]# yum install openssl* 2、解压缩软件,加载模块 [root@server soft]# ls nginx-1.20.2 nginx-1.20.2.tar.gz …...
WebSocket推送数据快,条数多导致前端卡顿问题解决
WebSocket推送数据快,条数多导致前端卡顿问题解决 前言方案优化消息频率使用高效的数据格式Protobuf 和 MessagePack的对比 启用压缩前端性能优化 WebSocket使用注意事项连接管理处理断开连接负载均衡监控和维护日志记录定期维护安全最佳实践限流 最后 前言 在项目…...
网络爬虫技术如何影响网络安全的
随着网络的发展和网络爬虫技术的普及,一些人收集某些需要的信息,会使用网络爬虫进行数据抓取。网络爬虫一方面会消耗网络系统的网络资源,同时可能会造成核心数据被窃取,因此对企业来讲如何反爬虫显得非常重要。 一、什么是网络爬…...
基于蒙特卡洛思想生成电动汽车充电负荷曲线
本程序基于蒙特卡洛思想生成电动汽车充电负荷曲线,利用第十一届电工杯所提供的数据(充电开始时间,充电电量,充电功率)得到一万台电动汽车充电负荷曲线。蒙特卡洛只是解决问题的一种思想,本程序可为其他利用…...
Redis深入学习
目录 Redis是什么? Redis使用场景 Redis线程模型 Redis执行命令是单线程的为什么还这么快? Redis持久化 Redis 事务 Key 过期策略 Redis 和 mysql 如何保证数据一致? 缓存穿透 缓存击穿 缓存雪崩 Redis是什么? redis是一…...
kamailio中路由模块汇总
功能模块描述请求路由 (request_route)主要处理进入的SIP请求,包含初步检查、NAT检测、CANCEL请求处理、重传处理等。处理通过REQINIT、NATDETECT、RELAY等子模块的调用。CANCEL处理对CANCEL请求进行处理,包括更新对话状态并检查事务。如果事务检查通过&…...
EasyExcel 导出合并层级单元格
EasyExcel 导出合并层级单元格 一、案例 案例一 1.相同订单号单元格进行合并 合并结果 案例二 1.相同订单号的单元格进行合并2.相同订单号的总数和总金额进行合并 合并结果 案例三 1.相同订单号的单元格进行合并2.相同订单号的商品分类进行合并3.相同订单号的总数和总金额…...
青少年编程与数学 02-009 Django 5 Web 编程 01课题、概要
青少年编程与数学 02-009 Django 5 Web 编程 01课题、概要 一、Django 5Django 5 的主要特性包括: 二、MVT模式三、官方网站四、内置功能数据库 ORM(对象关系映射)用户认证和授权表单处理模板引擎URL 路由缓存框架国际化和本地化安全性功能管…...
Oracle认证大师(OCM)学习计划书
Oracle认证大师(OCM)学习计划书 一、学习目标 Oracle Certified Master(OCM)是Oracle官方认证体系中的最高级别认证,要求考生具备扎实的数据库管理技能、丰富的实战经验以及解决复杂问题的能力。本计划旨在通过系统化的…...
2.7学习
crypto buu-还原大师 仔细阅读题目,这里有一段字符串,但是其中有四个大写字母被替换成了‘?’,那么我们写脚本:首先将四个问号均换成26个大写字母并且组成不同的组合, 所以有四个循环让四个问号都遍历26个…...
oracle ORA-27054报错处理
现象 在oracle执行expdp,rman备份,xtts的时候,由于没有足够的本地空间,只能使用到NFS的文件系统但有时候会出现如下报错 ORA-27054: NFS file system where the file is created or resides is not mounted with correct options根据提示信…...
