ObjectBox的探究
ObjectBox的介绍
ObjectBox是一个专门为物联网和移动设备打造出的非常快速的面向对象的数据库,它有一下几个特点
- ObjectBox是小于1MB的,所以非常适用于移动App和小的物联网设备,
- ObjectBox是第一个高性能,NoSQL,并且兼容ACID的边缘数据库
- 目前已经有8万多个APP使用ObjectBox,
- ObjectBox比我们经常使用的SQlite数据库快10倍。
- 当数据更改时,不需要做手动的迁移
- 多平台支持,C,java,swift,go
- 边缘计算: 在靠近物或数据源头的一侧,就近提供端服务
- NoSQl(not only SQL): 非关系型数据库,原有的关系型数据库管理系统(RDBMSs)单机无法满足数据容量的需求,很多时候需要使用集群解决问题,但是RDBMS的join,union操作,一般不支持分布式集群,所以NoSQL就出来了,它几个特点:非关系型的、分布式的、开源的、水平可扩展的
- ACID:指数据库管理系统在写入和更新数据的时候,保证事物的正确可靠,必须具有的四个特性,原子性,一致性,隔离性,持久性
ObjectBox使用说明(Java版本)
接入ObjectBox
在根目录的build.gradle
,添加
buildscript {ext.objectboxVersion = '2.3.3'respositories {jcenter()}dependencies {// Android Gradle Plugin 3.0.0 or later supportedclasspath 'com.android.tools.build:gradle:3.3.1'classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"}
}
在APP或者module的build.gradle
加入
apply plugin: 'com.android.application'
apply plugin: 'io.objectbox' // apply last
然后在你的Application中初始化
public class MyApplication extends Application {private static MyApplication mApplication;private BoxStore boxStore;@Overridepublic void onCreate() {super.onCreate();mApplication = this;initDB();}private void initDB(){boxStore=MyObjectBox.builder().androidContext(mApplication.getApplicationContext()).build();AccountManager.getInstance().setCurrentAccountFromDB();}public static MyApplication getMyApplication() {return mApplication;}public BoxStore getBoxStore() {return boxStore;}
}
基本的注解介绍
这个相信使用过ORM类型数据库的都知道的
@Entity
public class Student{@Id public long id;public String name;public int grade;public int classId;
}
- @Id
ObjectBox的实体必须要有一个long类型的@Id属性,为了方便获取和引用对象,当然也可以使用java.lang.Long
,但是官方不推荐使用。默认的情况下,一旦entity持久化,Objectbox就会分配一个ID给这个实体,可以不用管。(Tips:我们可以通过Id是不是0来判断,是否这个实体持久化,Id只有两个值是意外的:0和-1,0代表了为持久化,-1只在代码内部使用)
当然想自己赋值给Id属性也可以,设置一下Id注释
@Id(assignable = true)
long id;
这个允许我们赋值任何有效的Id(除0,-1),赋值0就意味着让ObjectBox赋值
2. 其他类型值
ObjectBox获取实体属性的数据,不用加注解,但是需要保证下面两种情况之一
- 成员属性的访问权限至少是“package-private”(包访问权限),只对自己包内所有类可见
- 提供标准的getter和setter方法(这个标准就是使用IDE自动生成的)
@Entity
public class Student {@Idprivate long id;@NameInDb("NAME")private String name;@NameInDb("GRADE")private int grade;@Indexprivate int classId;@Transientprivate String className;private static int dormitoryId;public long getId() {return id;}public void setId(long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getGrade() {return grade;}public void setGrade(int grade) {this.grade = grade;}public int getClassId() {return classId;}public void setClassId(int classId) {this.classId = classId;}
}
<1> @NameInDb("NAME")
这个定义在数据库当中该属性的名称,定义这个之后,后面更改Java层面的属性名并不影响数据库
<2> @Transient
和序列化的时候一样,标记这个属性不会被持久化
<3> static
属性也不会被持久化
<4> @Index
为对应的数据库列创建数据库索引(注:目前不支持byte[],float和double),这里作者还引入了Index type索引值的概念,之前的Index使用的都是属性值,现在可以对属性值进行 hash来构建index,比如String类型,因为作者觉得挺耗费空间
@Index(type = IndexType.VALUE)
private String name;
这里的IndexType有四个值:
- IndexType.DEFAULT不指定默认为DEFAULT,根据属性的值去使用最佳的索引方式(对于String类型使用hash,其他就直接使用值)
- IndexType.VALUE使用属性的值构建索引
- IndexType.HASH使用32位的hash值去构建索引,相比较64,hash冲突可能出现,但是实际并不会有性能上影响,优先使用这个
- IndexType.HASH64使用64位long类型去构建索引,这个需要更过的存储空间,往往不是最好的选择
(5)@Unique
表明在数据库当中,这个属性的值为唯一,否则抛出UniqueViolationException
数据之间的关系
这个关系定义为:对象指向其他的对象,他们之间就叫有关系,有两种关系To one ,To many,这里需要注意两个概念source object定义关系的对象,target object被引用的关系对象
To-one关系
一对一关系中:我们有三个方法来设置关系:
setTarget(entity)
让entity成为新的target,也可以是在数据库中已经存在的,null就是清除关系
setTargetId(entityId)
这个Id是数据库中已经存在的实体Id,0代表清除关系
setAndPutTarget(entity)
让entity成为新的target,并且把entity放进数据库中,如果原对象之前不在数据库中,在调用setAndPutTarget()之前需要调用attach
Son son=new Son();
sonBox.attach(order);//需要填写
son.customer.setAndPutTarget(father);
//Father.java 具体使用案例
@Entity
public class Father{@Id public long id;
}
//Son.java
@Entity
public class Son{@Id public long id;public ToOne<Father> father;
}//在代码中如何添加
Father father=new Father();
Son son=new Son();
son.father.setTarget(father);
long sonId=boxStore.boxFor(Son.class).put(son);
//在代码中如何获取
Son son=boxStore.boxFor(Son.class).get(sonId);
Father father=son.father.getTarget(father);
如果Father对象不在数据库当中,那么就会把Father放进去,如果存在,就只是建立一个之间的关系
但是如果我们的**target对象的Id是自己赋值的即@Id(assignable =true)
**那么就不会自动插入,需要我们自己手动执行如下代码
fatherBox=boxStore.boxFor(Father.class);
sonBox=boxStore.boxFor(Son.class);
father.id=110;
fatherBox.put(father);
son.father.setTarget(father);
sonBox.put(son);
我们也可以废除之间的关系,但是并不会在数据库中删除掉对应的target对象
son.father.setTarget(null);
sonBox.put(son);
ToOne关系的实现原理
我们可以查看我们项目的objectbox-models/default.json
看到其实是在Son类里面增加了一个fatherId的属性,可以通过@TargetIdProperty(String),修改这个名称。如下所示:
@Entity
public class Son {@Idpublic long id;@TargetIdProperty("son_father_id")public ToOne<Father> father;
}
提高性能的技巧
如何提高性能?首先我们需要明白,我们使用ToOne
的father对象的时候,代码里面是没有初始化这段代码的,son.father.setTarget(father);
比如这一句,并没有报NullPointerException错误,因为在代码执行前,ObjectBox Gradle 插件在构造函数的时候,添加了初始化这个target entity的初始化工作。
为了提高性能,我们应该提供一个全属性的构造函数(包含target的Id,这个隐含属性可以在工程目录的object-models/defaoult.json
里面找到)
To-Many关系
To-Many关系里面两种:一种是one-to-many,一种是many-many
(对于To-many关系,在第一次请求的时候会被延迟的执行,然后缓存到to-many的source对象里面去,所以,对关系的get方法后续不会从数据库中查询到)
OneToMany
我们使用注解@Backlink
实现
//Father.java
@Entity
public class Father{@Id public long id;@Backlink(to = "father")public ToMany<Son> sons;
}
//son.java
@Entity
public class Son{@Id public long id;public ToOne<Father> father;
}
//如何添加
Father father=new Father();
father.sons.add(new Son());
father.sons.add(new Son());
long fatherId=boxStore.boxFor(Father.class).put(father);
添加的规则也一样,如果@Id(assignable = true
,那么不会自动插入,需要在添加之前执行,ObjectBox只放被引用对象ID为0的实体
//如果是source entity使用 @Id(assignable = true
father.id=12;
fatherBox.attach(father);
father.sons.add(son);
fatherBox.put(father);
//如果是target entity使用
son.id=12;
sonBox.put(son);
father.sons.add(son);
fatherBox.put(son);
//get
Father father=fatherBox.boxFor(Father.class).get(fatherId);
for(Son son: father.sons){//TODO ....
}
//Remove
Son son=father.orders.remove();
//参数既可以是son,也可以是数字
ManyToMany
使用注解ToMany
@Entity
public class Teacher{@Id public long id;
}
@Entity
publci class Student{@Id publci long id;public ToMany<Teacher> teachers;
}
//添加数据
Teacher teacher1 = new Teacher();
Teacher teacher2 = new Teacher();Student student1 = new Student();
student1.teachers.add(teacher1);
student1.teachers.add(teacher2);Student student2 = new Student();
student2.teachers.add(teacher1);
student2.teachers.add(teacher2);boxStore.boxFor(Student.class).put(student1,student2);
//get
Student student1 = boxStore.boxFor(Student.class).get(student1.id);
for(Teacher teacher : student1.teachers){//TODO
}//remove
student1.teachers.remove(0);
student1.teachers.applyChangesToDb();
如果想知道,一个老师有什么学生,可以写
// Teacher.java
@Entity
public class Teacher{@Id public long id;@Backlink(to = "teachers") // backed by the to-many relation in Studentpublic ToMany<Student> students;}
// Student.java
@Entity
public class Student{@Id public long id;public ToMany<Teacher> teachers;}
查询
因为使用的是非关系型数据库,所以这里的查询通过构建一个QueryBuilder操作,下面只是一个小例子,具体的API可以看下源码
QueryBuilder<User> builder = userBox.query();
builder.equal(User_.firstName,"Joe).greater(User_.yearOfBirth,1970).startsWith(User_.lastName,"0");
List<User> youngJoes = builder.build().find();
Lazy loading results
为了避免加载查询结果太快,query提供了findLazy()和findLazyCached方法,返回LazyList
注: LazyList: 线程安全,不可修改的List,
数据观察,DataObservers
private DataSubscriptionList subscriptions = new DataSubscriptionList();
Query<Task> query = taskBox.query().equal(Task_.complete, false).build();
query.subscribe(subscriptions).on(AndroidScheduler.mainThread()).observer(data -> updateUi(data));
- 这条Query执行语句在后台执行
- 一旦query执行,之后,observer就会得到数据
- 无论何时 Task对象在未来改变了,这个query语句会再执行一遍
- 一旦结果更新了,就去提交给Observer
- observer调用在主线程,可以通过on指定
- subscribe(subscriptions)这个是用来跟踪所有的订阅,想取消观察,可以直接调用这个取消所有观察
- 这个subscribe只是默认会给两次通知,第一次subscribe之后执行,第二次是数据改变的时候,这个可以改变比如你只想要数据改变的时候需要在
subscribe()
之后调用onlyChanges()
通用的应该是这个:
DataObserver<Class<Task>> taskObserver = new DataObserver<Class<Task>>() {@Override public void onData(Class<Note> data) {// do something}
};
boxStore.subscribe(Task.class).observer(taskObserver);Query<Task> query = taskBox.query().equal(Task_.completed, false).build();
subscription = query.subscribe().observer(data -> updateUi(data));
线程调度
Query<Task> query = taskBox.query().equal(Task_.complete, false).build();
query.subscribe().on(AndroidScheduler.mainThread()).observer(data -> updateUi(data));
on()就是告知我们想要在哪个线程我们Observer被观察到
query默认在后台线程执行
数据流的改变
boxStore.subscribe().transform(clazz -> return boxStore.boxFor(clazz).count()).observer(count -> updateCount(count));
我们可以在transform中对数据进行转换,比如查询出来的结果可能是List,但是你只关心数量int,就可以转换一下
支持RxJava
但是需要引入,官方封装好的三方库,操作就和RxJava一样了
implementation "io.objectbox:objectbox-rxjava:$objectboxVersion"
ObjectBox的探究相关推荐
- Android肝帝战纪之ObjectBox移动数据库框架探究与实现
ObjectBox移动数据库框架 ObjectBox Github链接: 点击此处链接到Github 介绍 ObjectBox是移动端数据库框架,灵感来自于NoSql,速度非常快,号称是市面上最快的移 ...
- 吴恩达《深度学习》第四门课(2)卷积神经网络:实例探究
2.1为什么要进行实例探究 (1)就跟学编程一样,先看看别人怎么写的,可以模仿. (2)在计算机视觉中一个有用的模型,,用在另一个业务中也一般有效,所以可以借鉴. (3)本周会介绍的一些卷积方面的经典 ...
- 异步编程之Promise(2):探究原理
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- Lucene.net中文分词探究
一.中文分词方式: 中文分词几种常用的方式: A. 单字分词 单字分词,顾名思义,就是按照中文一个字一个字地进行分词.如:我们是中国人,效果:我/们/是/中/国/人. B. 二分法 二分法,就是按两个 ...
- 查询在应用程序运行得很慢, 但在SSMS运行得很快的原因探究
原文:查询在应用程序运行得很慢, 但在SSMS运行得很快的原因探究 查询在应用程序运行得很慢, 但在SSMS运行得很快的原因探究 -理解性能疑点 1 引言 内容来自http://www.so ...
- 中文NLP的分词真有必要吗?李纪为团队四项任务评测一探究竟 | ACL 2019
作者| Yuxian Meng.Xiaoya Li.Xiaofei Sun.Qinghong Han.Arianna Yuan. Jiwei Li 译者 | Rachel 责编 | Jane 出品 | ...
- 聚类分析案例:探究用户对物品类别的喜好细分降维
聚类分析案例:探究用户对物品类别的喜好细分降维 数据如下: order_products__prior.csv:订单与商品信息 字段:order_id, product_id, add_to_cart ...
- 如何优化计算机网络课程,计算机论文:探究如何优化计算机网络课程教学方法.docx...
计算机论文:探究如何优化计算机网络课程教学方法 一.引言 计算机网络的飞速发展不但加速了全球信息化的进程,也使我们的生活方式发生了深刻的变革.我们正处在一个数字化.网络化.信息化的时代,网络已经成为经 ...
- 求数的绝对值一定是正数_「口袋数学」绝对值的几何意义探究及应用,培优课程...
哈喽,大家好!我们又见面了,欢迎继续关注[轩爸辅导]的[口袋数学].日更[每日一学][每日一练],帮助孩子日积月累,考出好的成绩.配套辅导,哪里不会学哪里,哪里出错练哪里,帮助孩子提高效率. 从数轴上 ...
- 探究!一个数据包在网络中的心路历程
来自:小林coding 前言 想必不少小伙伴面试过程中,会遇到「当键入网址后,到网页显示,其间发生了什么」的面试题. 还别说,这真是挺常问的这题,前几天坐在我旁边的主管电话面试应聘者的时候,也问了这个 ...
最新文章
- Asp.net团队疯了(同时发布WebMatrix, Razor, MVC3和Orchard)
- 我为什么暂时放弃了React Native
- 公司最喜欢什么样的程序员?
- 程序媛计划——python正则表达式
- 微信小程序访问云数据库
- java类中serialversionuid 作用 是什么?举个例子说明
- 软件测试实验报告下载 实验一到实验五
- 计算机网络严楠,安徽工程大学
- android sdk httppost,android6.0SDK 删除HttpClient的相关类的解决方法
- 机房收费系统重构版:那个系统我们一起遇到的问题
- Ubuntu 搭建Facebook ATC弱网测试环境 使用路由器搭建ATC
- Ubuntu永久修改IP、临时修改IP
- 服务器机器系统,Angel:一种新型分布式机器学习系统
- 类名与样式是否为并列关系
- java 中介模式_java设计模式-中介者模式
- canvas教程7-炫彩小球
- STM32 Cubemax(十一) ——JY901陀螺仪数据的读取与简单数据处理
- 反问疑问_反问疑问句的语法
- Jquery-canvas动态粒子背景动画-适用于登陆注册页面背景
- 《程序设计基础》 第五章 函数 6-6 字符金字塔 (15 分)