项目介绍
iBoxDB 是一个高能效的应用程序数据库,提供事务支持,使用数据库表的风格存取任意结构的文档对象数据,包含无须安装配置的 JAVA 与 .NET 数据库引擎。
iBoxDB 提供一个优雅设计的编程接口,让应用程序无缝地与数据引擎溶为一体, 你能方便地把它发布到移动设备, 桌面设备和服务器上, 然后让它帮助你存取各种有结构的,或者无结构的数据,具备保持数据一致性的能力。
双引擎数据库
支持 JAVA C# Android Unity Xamarin Mono ASP.NET Linux
特性
- NoSQL 增删改查
- 键表与键值表
- 唯一或可重复的索引
- 唯一或可重复的复合索引
- SQL 风格数据查询语言
- 数据库事务支持
- 并发控制,多线程安全
- 多进程安全
- 内存管理
- 主从和多主的数据库热同步
- 自动创建数据库文件
- 支持磁盘永久保存和全内存快速保存
- 零配置, 复制直接运行, 全受控代码
- 动态列支持
- 带不同索引的多个数据类型能存到同一个表中
- 持久化 + 对象影射 + 缓存 + 嵌入式, 一站式解决方案
- Ason, 快速动态对象实例化
- 结果集支持 LINQ 与 STREAM
- 事务抱团
- 快读查询
- 更新自增
- 查询追溯
- 两级事务隔离
- 高性能无外部系统依赖
- JAVA6+ .NET2+
示例
每个 BOX 都是一个完全隔离的独立数据空间
using(var box = auto.Cube())
{
//select, insert, update, delete ...
//replace()=(insert or update)
var result = box.Commit();
}
try(Box box = auto.cube()){
...
CommitResult r = box.commit();
}
普通对象操作
box["Member"].Insert(new Member() {
ID=box.NewId(),
Name = "Andy",
Password = EncodePassowrd("123")
}
);
Member m = new Member();
m.ID = box.newId();
m.setName("Kevin");
box.d("Member").insert(m);
动态列的文档数据
//Game : Dictionary<string, object>
game["GameType"] = "ACT";
box["Product"].Insert(game);
//Game extends HashMap<String,Object>
game.put("GameType", "ACT");
box.d("Product").insert(game);
键-值风格的查询
box["Table", 2L].Select<Member>();
//支持复合键
box["Table2", 99, "ABC"].Select<Product>();
box.d("Table", 3L).select(Member.class);
//支持复合键
box.d("Table2", 88, "ABC").select(Product.class);
复合键支持
config.ensureTable(Item.class, "Item", "UID", "Type")
SQL 风格数据查询
//from TABLE where A>? & B<=? order by C limit 0,10
box.Select<Member>("from Member where Name==?", "MyName");
//from [table] where [condition]
// order by [field1] desc,[field2] limit [0,10]
//[Condition:] == != < <= > >= & | ( )
//[IFunction:] =[F1,F2,F3]
box.select(Member.class, "from Member where Name==?", "MyName");
查询
box.Select("from Member");
查询选项
//先加载到内存,使用 “*”.
//因为操作系统有预读,这选项一般不需要,
box.Select("*from Member");
//查询追溯 使用 “!”.
box.Select("!from Member");
弱类型支持
//使用强类型
box.select("from Table where Id > ?" , 1L);
//使用弱类型
box.select("from Table where Id > ?" , new Variant("1"));
支持索引提升查询速度,平均快一百倍
//索引
config.EnsureIndex<Member>("Member", "Field1")
config.ensureIndex(Member.class, "Member", isUnique,"Field1")
//复合索引
config.EnsureIndex<Member>("Member", "Field1","Field2")
config.ensureIndex(Member.class, "Member", isUnique,"Field1","Field2")
//两种索引都可以加速查询,随意选择.
//但一个查询只会加载一个索引,
//同时使用两个会产生浪费.
//一般索引已经足够快.
//复合索引一般用于关联表主键,两个条件相等的情况
box.Select("from Member where Field1 == ? & Field2 == ?",arg1,arg2)
//Id 在左边一般会更快
box.Select("from Member where Id == ? & Field == ?",id,arg)
//主键同时也是主索引,可以创建复合索引包含主键
//但主键是唯一的,所以第二个字段一般很少用到
config.EnsureIndex(..., "Id","Field")
//交换顺序在一些情况下可能有用
config.EnsureIndex(..., "Field","Id")
//具体可查看数组比较的方法
//键值数据库一定有主键
//合并结果会比 OR 条件更快,
//取决于数据集的大小与索引设置.
//where Id == ? | Id == ? | Id == ?
foreach(var id in [ 1, 2, 3 ])
combiner.Add( box.Select("from Member where Id == ?",id) )
自定义查询函数
box.Select<Member>("from Member where [Tags]", new IFunction("Value"));
自定义表-对象绑定
public bool Insert(Member m){
return auto.Insert(nameof(Member), m);
}
兼容 LINQ (.NET)
from o in box.Select<Class>("from Class")
where o.Text.Contains(text)
select o;
兼容 Stream (Java8)
StreamSupport.stream(db.select("from Table").spliterator(), true)
.collect(Collectors.groupingBy((l) -> l.get("GroupID"),
Collectors.summingLong((l) -> (Long) l.get("Value"))));
Ason 和 原型对象
//定义原型, Id 是 Long
Ason prototype = new Ason("Id:", 0L, "Name:", "Guest");
Ason record = prototype.select();
//设置 Id 为 String,
record.set("Id", "123");
//自动转为定义原型的 Long
System.out.println("Output: " + record.get("Id").getClass());
//输出: class java.lang.Long
数据库热备份
auto.GetDatabase().CopyTo(bakAddr, bakRoot, buffer)
快读查询
//从小文件中直接查询数据,
//不用启动数据库引擎
IEnumerable records = DB.Select(fileAddress)
事务抱团
//三个事务一起提交
long huggersBuffer = 1024L * 1024L * 32L;
box1.Commit(huggersBuffer);
box2.Commit(huggersBuffer);
box3.Commit();
可编程热同步,下载文件了解详细内容
//主-主
BoxData.masterReplicate();
//主-从
BoxData.slaveReplicate();
更新自增
| 作用域 | 触发条件 | 数据类型 | 数据来源 | |
|---|---|---|---|---|
| 更新自增 | 索引 | 插入/更新 | 长整数 | Database NewId (MaxPos,1) |
| 主键自增 | 主键 | 插入 | 数字 | Table Max (ID)+1 |
查询追溯
| 线程 | 用法 | |
|---|---|---|
| 查询追溯 | 不阻塞 | 读写不同的数据行 |
| 数据锁 | 阻塞 | 读写同一数据行 |
Snapshot-Serializable 两级事务
| 程序区域 | 隔离级别 |
|---|---|
| 应用程序 | Snapshot |
| 数据库 | Serializable |
using(var box = auto.Cube()){
//Snapshot...
box.Commit( ()=>{
//Serializable...
});
}
数据持久层
| IO |
|---|
|
数据库路径设置
C# & JAVA, 把数据库文件放到项目工作目录外会有更好性能//在虚拟机里,不同的路径有很大的读写速度差别.
//先创建目录,再放入数据库.
//new File(path).mkdirs();
//Directory.CreateDirectory(path)
iBoxDB.LocalServer.DB.Root("/data/");
在扫描软件中把数据库根目录设置为例外,可以加快读写速度
ASP.NET Cross Platform
iBoxDB.LocalServer.DB.Root(MapPath("~/App_Data/"));
Xamarin
iBoxDB.LocalServer.DB.Root(System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal));
Unity3D
iBoxDB.LocalServer.DB.Root(Application.persistentDataPath);
Android
iBoxDB.LocalServer.DB.root(android.os.Environment.getDataDirectory()
.getAbsolutePath() + "/data/" + packageName + "/");
JSP WebApplication
@WebListener()
public class StartListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
String path = System.getProperty("user.home") + "/data/";
new File(path).mkdirs();
iBoxDB.LocalServer.DB.root(path);
}
}
Godot
<PackageReference Include="iBoxDB" Version="" />
var dir = Godot.OS.GetUserDataDir();
dir = Path.Combine(dir, "DBROOT");
Directory.CreateDirectory(dir);
DB.Root(dir)
jMonkeyEngine
File dir = JmeSystem.getStorageFolder(StorageFolderType.Internal);
dir = new File(dir, "ProjectName");
dir = new File(dir, "DatabaseName");
dir.mkdir();
DB.root(dir.getAbsolutePath());
快速入门 C# and JAVA
using IBoxDB.LocalServer;
var db = new DB();
db.GetConfig().EnsureTable<Record>("Table", "Id");
AutoBox auto = db.Open();
auto.Insert("Table", new Record { Id = 1L, Name = "Andy" });
var record = auto.Get<Record>("Table", 1L);
record.Name = "Kelly";
auto.Update("Table", record);
auto.Delete("Table", 1L);
import iboxdb.localserver.*;
DB db = new DB();
db.getConfig().ensureTable(Record.class, "Table", "Id");
AutoBox auto = db.open();
auto.insert("Table", new Record(1L, "Andy"));
Record record = auto.get(Record.class, "Table", 1L);
record.Name = "Kelly";
auto.update("Table", record);
auto.delete("Table", 1L);
内存使用
DatabaseConfig cfg = db.getConfig();
//缓存,小于三分一总内存
cfg.CacheLength = cfg.mb(1024L);
//移动设备 64MB
cfg.CacheLength = cfg.mb(64L);
//读线程, 在小缓存机器中设置 8+
cfg.ReadStreamCount = 8;
//写线程, 在小缓存机器中设置 4- 或者 1
cfg.WriteStreamCount = 1;
安装使用
.NET: 在项目中引用 NETDB/iBoxDB.DLL
Java: 在项目中引用 JavaDB/iBoxDB.jar
与 MySQL 的性能参照
iBoxDB
Insert: 1,000,000 AVG: 47,016 objects/s
Update: 1,000,000 AVG: 25,558 objects/s
Delete: 1,000,000 AVG: 42,714 objects/s
MySQL
Insert: 1,000,000 AVG: 5,514 objects/s
Update: 1,000,000 AVG: 5,109 objects/s
Delete: 1,000,000 AVG: 6,044 objects/s
数据类型支持
| .NET | JAVA |
|---|---|
|
|
| ORM | |
|
|
DatabaseConfig cfg;
//创建表
ensureTable(Record.class, "Table", "Id");
//创建长度为 32 的索引
ensureIndex(Record.class, "Table", "Name(32)");
//如果要索引 byte[] 或其它,
//使用 ToBase64String(byte[]) 转换为字符串 String.
.NET AOT 注册类型
public static object Register
<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
where T : new()
{
return new T();
}
//触发 DynamicallyAccessedMemberTypes.All
Register<T1>();
EnsureTable<T1>("T1", "Id");
全平台支持