20个不稳定版本 (3个重大更改)
0.4.5 | 2024年4月5日 |
---|---|
0.4.4 | 2024年3月17日 |
0.3.3 | 2024年3月11日 |
0.2.3 | 2024年3月8日 |
0.1.5 | 2024年3月8日 |
#280 在 数据库接口
每月下载量 275
59KB
772 行
NanoDB
NanoDB是一个简单、轻量级、易于使用的Rust JSON数据库。它旨在用于不需要完整数据库的小型到中型项目。它提供了一种简单易用的API来读取和写入JSON数据。NanoDB提供了以下功能
- 简单API:易于操作的JSON数据接口。
- 原子操作:通过原子读取和写入保证数据一致性。
- 树结构:支持使用专用树进行针对性和修改。
- 异步I/O:通过非阻塞I/O提高性能。
- 线程安全:适用于多线程使用。
树
NanoDB区分了三种专门的树类型,每种类型都设计用于在不同的环境中高效、安全地与JSON数据交互。
- 树:该结构封装了原始JSON数据的克隆子树。这个克隆表示原始数据的一个特定部分,由JSON结构中的指定路径指向。这使能够针对数据的一个离散部分进行操作,而不会影响数据库中的其余数据。如果需要,NanoDB允许将树合并回主数据库。
- ReadGuardedTree:基于基本的Tree结构,ReadGuardedTree包括一个读取锁机制。这种增强允许多个线程同时进行并发读取操作,同时保证在这些操作期间数据保持不变。该机制允许存在多个ReadGuardedTree,只要它们只用于读取,从而确保数据一致性而不会阻碍访问性。
- WriteGuardedTree:类似于ReadGuardedTree,但有一个关键的区别:它具有写入锁以方便原子写入操作。这个排他性锁确保在任何给定时间只有一个WriteGuardedTree可以执行写入操作,从而防止可能导致数据不一致或竞争条件的并发修改。这种严格的控制机制对于在更新时保持数据库的完整性至关重要。
这些专门的树结构是NanoDB设计的基础,使并发数据访问和修改安全之间达到平衡。通过为每种树类型明确划分角色和访问控制,NanoDB确保了在读取密集型或写入密集型场景下数据的完整性和一致性。
示例
查看示例文件夹以获取更多信息。
use nanodb::{error::NanoDBError, nanodb::NanoDB, trees::tree::Tree};
use serde::Deserialize;
use serde_json::{json, Map, Value};
//...
#[derive(Deserialize)]
pub struct MyStruct {
name: String,
versions: Vec<f64>,
}
let json_data = r#"{
"key1": "Welcome!",
"key2": 42,
"key3": {
"name": "NanoDB",
"versions": [1.0, 2.0, 3.0]
},
"key4": [1, 2, 3],
"key5": ["Welcome", "to", "NanoDB"]
}"#;
let mut db = NanoDB::new_from("examples/data/data2.json", json_data).unwrap();
// Basic reads (working with cloned sub-tree)
let text: String = db.data().await.get("key1")?.into()?;
let number: i64 = db.data().await.get("key2")?.into()?;
let object: MyStruct = db.data().await.get("key3")?.into()?;
let array: Vec<i64> = db.data().await.get("key4")?.into()?;
// Basic inserts
db.insert("age", 42).await?; // shorthand for db.update().await.insert("age", 42)?;
db.insert("crates", vec!["tokio", "serde"]).await?;
db.insert("some_map", Map::new()).await?;
db.insert("person", json!({"name": "Donald"})).await?;
db.write().await?; // write to file if needed
// Atomic CRUD operations and advanced data manipulation
db.update().await.remove("age")?;
db.update().await.get("key3")?.insert("key", "value")?;
db.update().await.get("key3")?.get("versions")?.push(42.0)?;
db.update().await.get("key4")?.for_each(|v| {
*v = Value::from(v.as_i64().unwrap() * 2i64);
})?;
db.write().await?; // write to file if needed
// Atomic reader (read() returns a read lock on the db)
let versions: Vec<String> = db.read().await.get("key5")?.into()?;
let number: i64 = db.read().await.get("key4")?.at(0)?.into()?;
// Tree methods and merging
let mut my_tree: Tree = db.data().await.get("key3")?;
my_tree.insert("language", "Rust")?;
db.insert_tree(my_tree).await?;
db.write().await?;
// Advanced write locks
let mut write_lock = db.update().await;
write_lock.insert("key1", "Welcome to NanoDB")?;
write_lock.insert("key1", "Welcome to NanoDB again")?;
write_lock.release_lock(); // release the lock manually to avoid deadlocks
let mut another_write_lock = db.update().await;
assert_eq!(
another_write_lock.get("key1")?.into::<String>().unwrap(),
"Welcome to NanoDB again"
);
贡献
欢迎并鼓励贡献!贡献形式多样。您可以
依赖项
~4–15MB
~184K SLoC