ObjectBox数据库是greenrobot团队开发的全新非关系型数据库框架,具有如下特点:
1、超快速:号称胜过测试过的所有嵌入式数据库;
2、面向对象的API:没有rows、columns和SQL,完全从0开始的对象;
3、反应性:对数据变化的反应简单而强大,使用ObjectBox中数据观察器或与RxJava集成;
4、多平台支持:已经支持安卓和java、ios和MacOs正在集成;
5、简单的线程:ObjectBox返回的对象可以在所有线程中运行;
6、不需要手动模式迁移:ObjectBox负责添加,删除和重命名属性的新对象版本,意味着数据库的升级不再需要我们自己管理版本号,ObjectBox内部会自动帮我们管理;
7、ObjectBox小于1MB,因此它是移动应用程序、小型IoT设备和IoT网关的理想解决方案。
1、project根目录下build.gradle (project 级别)添加如下配置:
buildscript {
...
ext.objectboxVersion = '2.8.1'
dependencies {
...
classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
}
}
2、浏览ObjectBox数据
2.1如果需要通过浏览器(PC端或移动端)查看ObjectBox存储的数据,需执行下面操作:
a、在module根目录下build.gradle (module 级别)添加如下配置:
dependencies {
...
// 使用浏览器查看数据的依赖,官方建议仅在 debug 版本依赖,所以做以下区分
debugImplementation "io.objectbox:objectbox-android-objectbrowser:$objectboxVersion"
releaseImplementation "io.objectbox:objectbox-android:$objectboxVersion"
}
// 注意下面的内容必须放到 dependencies 语句块的后面(文件末尾),否则编译报错
apply plugin: 'io.objectbox'
b、在Application的onCreate()中添加如下代码:
if (BuildConfig.DEBUG) {// 官方建议仅在debug下开启数据浏览
new AndroidObjectBrowser(boxStore).start(app);// 注:boxStore的获取需要先创建实体类
}
c、在AndroidManifest.xml中添加相应权限:
<!-- Required to provide the web interface -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Required to run keep-alive service when targeting API 28 or higher -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
d、手机需要连接adb,浏览器访问http://localhost:8090/index.html (该地址由ObjectBrowser 日志得到)。如果访问不到,那么程序安装后,打开命令行输入以下命令adb forward tcp:8090 tcp:8090后再次尝试。
I/ObjectBrowser: ObjectBrowser started: http://127.0.0.1:8090/index.html
I/ObjectBrowser: Command to forward ObjectBrowser to connected host: adb forward tcp:8090 tcp:8090
2.2如果不需要通过浏览器查看ObjectBox存储的数据,需要在module根目录下build.gradle (module 级别)添加如下配置:
apply plugin: 'com.android.application'
// after applying Android plugin
apply plugin: 'io.objectbox'
3、解决Caused by: java.lang.ClassNotFoundException: kotlin.text.Charsets 编译报错
a、尝试clean project后make project。反复多次后如果仍报错,则尝试步骤b;
b、尝试在module根目录下build.gradle (module 级别)中添加下面配置:
dependencies {
...
// Optional -- manually add native ObjectBox library to override auto-detection
testImplementation "io.objectbox:objectbox-linux:$objectboxVersion"
}
@Entity:这个对象需要持久化。
@Id:这个对象的主键,必须是long类型,默认情况下,id是会被objectbox管理的,也就是自增id,如果你想手动管理id需要在注解的时候加上@Id(assignable = true)即可。当你在自己管理id的时候如果超过long的最大值,objectbox 会报错,且id的值不能为负数。当id等于0时objectbox会认为这是一个新的实体对象,因此会新增到数据库表中。
@Index:这个对象中的索引。对经常大量进行查询的字段创建索引,会提高你的查询性能。目前@Index不能用来标识类型为 byte[]、float、double的字段。在2.0版本之前,ObjectBox 只能用@Index标识的字段的值做索引,在2.0版本之后则可以指定为不同类型来优化索引的效率。@Index(type = xxx)目前支持的类型有:默认(String 类型将默认指定为 HASH,其他类型将被指定为 VALUE)、IndexType.VALUE(使用字段的值做索引)、IndexType.HASH(使用32位的hash来构建索引,小概率会出现冲突但不影响效率)、IndexType.HASH64(使用64位的hash构建,自然会比32位占用更多空间)。
@Transient:如果你有某个字段不想被持久化,可以使用此注解,那么该字段将不会保存到数据库
@NameInDb:有的时候数据库中的字段跟你的对象字段不匹配的时候,可以使用此注解。
@ToOne:做一对一的关联注解,例如下面示例中表示一张User表关联一张Addr表。
@ToMany:做一对多的关联注解,如示例中表示一张Addr表关联多张User表。
@Backlink:表示反向关联。
@Relation:做一对多,多对一的注解。
@Unique:被标识的字段必须唯一,2.0+支持。在存入过程中,如果被@Unique标识的字段重复则会抛出UniqueViolationException异常。
ObjectBox 的实体类必需一个空参数的构造函数,否则会在运行时报错: Entity is expected to have a no-arg constructor。另外,官网文档中提到,提供一个包括了全部属性的构造函数将会提升性能。
ObjectBox在构建时需要访问实体类的属性,所以其属性要求有如下两个选择:
(1) 要求属性至少标识为package private(包访问权限),而不能使private。
(2) 如果要标识为private,则要求提供标准的getter和setter方法(这个标准就是使用IDE自动生成的)。
@Entity
public class User {
@Id
@NameInDb(“_id”)
private long id;
@NameInDb(“name”)
private String name;
@NameInDb(“gender”)
private String gender;
@NameInDb(“age”)
private int age;
// ? 为什么不能指定在数据库中的别名
public ToOne<Addr> address;
}
@Entity
public class Addr {
@Id
@NameInDb(Constants.Addr.ID)
private long id;
@NameInDb(Constants.Addr.COUNTRY)
private String country;
@NameInDb(Constants.Addr.CITY)
private String city;
@NameInDb(Constants.Addr.STREET)
private String street;
@Backlink(to = "address")
public ToMany<User> users;
}
private BoxStore boxStore; //数据库表的管理者
private final String BD_NAME = "user";
@Override
public void onCreate() {
super.onCreate();
boxStore = MyObjectBox.builder().androidContext(this).name(BD_NAME).build();
}
public BoxStore getBoxStore(){
return boxStore;
}
public static ObjectBoxApp getApplication() {
return this;
}
BoxStore boxStore = ObjectBoxApp.getApplication().getBoxStore();
Box<User> usersBox = boxStore.boxFor(User.class);
// 新增单条记录
User user = new User().setName("张三").setAge(25).setGender("男");
Addr addr = new Addr().setCountry("中国").setCity("深圳").setStreet("南山");
user.address.setTarget(addr);
usersBox.put(user);
// 批量新增
for(User user: allUsers) {
modify(user); // modifies properties of given user
}
box.put(allUsers);
BoxStore boxStore = ObjectBoxApp.getApplication().getBoxStore();
Box<User> usersBox = boxStore.boxFor(User.class);
usersBox.query().equal(User_.name, "李四").build().remove();
usersBox.removeAll();
BoxStore boxStore = ObjectBoxApp.getApplication().getBoxStore();
Box<User> usersBox = boxStore.boxFor(User.class);
User user = usersBox.query().equal(User_.name, "张三").build().findFirst();
List<User> users = usersBox.query().build().find();
BoxStore boxStore = ObjectBoxApp.getApplication().getBoxStore();
Box<User> usersBox = boxStore.boxFor(User.class);
User user = usersBox.query().equal(User_.name, "张三").build().findFirst();
if (user != null) {
user.setName("李四");
usersBox.put(user);
}
@ToOne和@ToMany可以看作JAVA中的T和List的关系。如上面例子中User和Addr:
public ToOne<Addr> address;
@Backlink(to = "address")
public ToMany<User> users;
Addr addr = new Addr().setCountry("中国").setCity("深圳").setStreet("南山");
user.address.setTarget(addr);
addr = user.address.getTarget();
User user1 = new User();
User user2 = new User();
Addr addr = new Addr();
addr.users.add(user1);
addr.users.add(user2);
boxStore.boxFor(Addr.class).put(addr);
(https://docs.objectbox.io/advanced/data-model-updates)
当我们需要新增、删除属性或者重命名类名、属性名时,直接操作实体类即可,默认情况下旧的数据会丢失,为了保留旧数据则可使用@Uid注解。
a、给需要修改的类名加上@Uid注解
@Entity
@Uid
public class User {
...
}
b、编译项目,编译将失败,并且会给你一个Uid
错误: [ObjectBox] UID operations for entity "User": [Rename] apply the current UID using @Uid(8056120966789605000L) - [Change/reset] apply a new UID using @Uid(2661598794239301979L)
2 个错误
c、将[Rename]后面的UID放入到要修改类的@Uid后面
@Entity
@Uid(8056120966789605000L)
public class User {
...
}
d、修改实体类类名
@Entity
@Uid(8056120966789605000L)
public class NewUser {
...
}
a、在要修改的属性上加上@Uid注解
@Entity
public class User {
...
@Uid
@NameInDb(Constants.User.GENDER)
private String gender;
}
b、编译项目,编译将失败,并且会给你一个Uid
错误: [ObjectBox] UID operations for property "User.gender": [Rename] apply the current UID using @Uid(2215757294699215868L) - [Change/reset] apply a new UID using @Uid(2071166115147421803L)
2 个错误
c、将[Change/reset]部分中的UID应用到该属性@Uid后面,然后修改其类型
@Entity
public class User {
...
@Uid(2071166115147421803L)
@NameInDb(Constants.User.GENDER)
private int gender;
}
Box实例下的put和remove的执行实际上已经是事务的。除此之外显性的使用事务也是可以的,ObjectBox 提供了几个api:
API | 说明 |
runInTx | 在给定的 runnable 中运行的事务 |
runInReadTx | 只读事务,不同于 runInTx,允许并发读取 |
runInTxAsync | 运行在一个单独的线程中执行,执行完成后,返回 callback |
callInTx | 与runInTx 相似,不同的是可以有返回值 |
参考博客:https://www.pianshen.com/article/9581153796/
参考博客:https://www.jianshu.com/p/5b348c9a7315
官网文档:https://docs.objectbox.io/getting-started
官网文档:https://docs.objectbox.io/advanced/data-model-updates