objectbox数据库

汪皓
2023-12-01

一、引入

在项目build文件中

repositories {
    google()
    jcenter()
    mavenCentral()
}
dependencies {
    classpath 'com.android.tools.build:gradle:4.0.2'
    classpath "io.objectbox:objectbox-gradle-plugin:2.9.1"
}

在app的build文件中

apply plugin: 'io.objectbox'

设置so库防止LinkageError崩溃

ndk {
    //设置支持的SO库架构
    abiFilters 'armeabi', "armeabi-v7a"
}

可选:Kotlin

对于使用Kotlin的Android项目,请务必添加kotlin-kapt:

apply plugin: 'kotlin-android' // if using Kotlin
apply plugin: 'kotlin-kapt' // if using Kotlin
apply plugin: 'io.objectbox' // apply last

可选:高级设置

ObjectBox插件使用合理的默认值并自动检测大多数配置。 但是,如果需要,您可以使用高级设置选项配置模型文件路径,MyObjectBox包,启用使用高级设置选项。

Advanced Setup - ObjectBox Docs

二、实体类

@Entity
public class User {

    @Id
    public long id;

    @Index
    public String accountNumber;

    public String name;

    public String password;
}

@Entity批注将Java类User标识为可持久化实体(数据库表名)。

@Id实体必须具有一个long类型的属性才能有效地获取或引用对象。自增id

@Index: 因为在ObjectBox中主键是必须设置为long类型的id, 当我们业务上需要另外主键时, 可以再标注@Index

@NameInDb: 字段在数据库中的命名

@Transient: 忽略字段, 不在表中生成

@ToOne:做一对一的关联注解,例如示例中表示一张学生表(Student)关联一张班级表(Class),此外还有一对多,多对多的关联,例如Class的示例:

@Entity
public class Class{
    @Id
    long id;
    
    @Backlink(to = "classToOne")
    public ToMany<Student> studentEntitys;
}

@ToMany:做一对多的关联注解,如示例中表示一张班级表(Class)关联多张学生表(Student)

@Backlink:表示反向关联

需要注意的是:默认情况下,id是会被objectbox管理的,也就是自增id,如果你想手动管理id需要在注解的时候加上@Id(assignable = true)即可。当你在自己管理id的时候如果超过long的最大值,objectbox 会报错。id=0的表示此对象未被持久化,id的值不能为负数。

三、初始化

MyObjectBox类是objectbox自动生成的,需要通过Build> Make project操作来生成,在此之前,需要创建至少一个带有@Entity注解的实体类,才能正常创建MyObjectBox

public class ObjectBox {

    private static BoxStore boxStore;

    public static void init(Context context) {
        boxStore = MyObjectBox.builder()
                .androidContext(context.getApplicationContext())
                .build();
    }

    public static BoxStore get() { return boxStore; }
}

在Application中初始化

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        ObjectBox.init(this);
    }
}

四、使用

4.1准备

Box<User> box = ObjectBox.get().boxFor(User.class);
User user=new User();

4.2增

user.accountNumber = "896159476";
user.name = "小工";
user.password = "123456";
box.put(user);

4.3查

List<User> userQuery =  box.query().equal(User_.accountNumber,"896159476").build().find();

查找首个名字为Joe,并且其出生日期大于1970年,并且其最后一个名字的第一个字母为O的所有用户

QueryBuilder<User> builder = userBox.query();
builder.equal(User_.firstName, "Joe")
        .greater(User_.yearOfBirth, 1970)
        .startsWith(User_.lastName, "O");
List<User> youngJoes = builder.build().find();

条件操作符

between :两者之间
contains :包含
equal : 相等
notEqual :不相等
startWith :以什么开头
endWith :以什么结尾
greater :大于
less :小于
in :包含
notIn :不包含
isNull :是否null
isNotNull :是否不null
and :条件与
or :条件或
order :按某属性升序排列返回
orderDesc :按某属性降序返回

4.4删

List<User> userQuery =  box.query().equal(User_.accountNumber,"123456").build().find();
box.remove(userQuery.get(0).id);

4.5改

List<User> userQuery =  box.query().equal(User_.accountNumber,"123456").build().find();
user.id = userQuery.get(0).id;
user.accountNumber = "123456";
user.name = "小工";
user.password = "123456";
box.put(user);

五、数据库的其他操作

5.1数据库的数据升级

当我们需要新增和删除字段时,直接操作实体类即可,不需要做特殊的更改

如果需要重命名字段名或实体类名,可以按照如下步骤操作:

第一步:给需要修改的类名加上@UID注解

@Entity
@Uid
public class MyName { ... }

第二步:编译项目,编译将失败,并且会给你一个UID

error: [ObjectBox] UID operations for entity "MyName": [Rename] apply the current UID using @Uid(6645479796472661392L) - [Change/reset] apply a new UID using @Uid(4385203238808477712L)

第三步:将Rename后面的UID放入到要修改的类中:

@Entity
@Uid(6645479796472661392L)
public class MyName { ... }

第四步:进行数据的修改

@Entity
@Uid(6645479796472661392L)
public class MyNewName { ... }

更改数据属性或重命名字段名同理操作。

5.2表关系

@ToOne和@ToMany可以看作JAVA中的T和List的关系,拿班级和学生举例,设置相关的学生对象如下:

Class class = new Class(); //先创建一个班级
Student student = new Student();
student.name = "Jay";
student.classToOne.setTarget(class);  //设置一对一的target对象,字段参见以上示例
long studentId = StudentBox.put(student);

获取该学生的班级信息:

Student student = StudentBox.get(studentId);
Class class = student.classToOne.getTarget();

而一对多的关系更为简单,你可以像List集合一样去操作它:

Class class_ = new Class(); //先创建一个班级
Student s1 = new Student(); //添加一个学生
student.name = "Jay";

Student s2 = new Student();
s2.name = "Android";

class_ .studentEntitys.add(s1);
class_ .studentEntitys.add(s2);
Box classBox = BaseApp.getInstence().getBoxStore().boxFor(Class.class);
classBox.put(class);

这样的话一张Class表中就有两个学生表的数据了,查询的话可以获取该Class的实体,随后像遍历List集合一样去遍历studentEntitys字段,objectBox提供的方法和List集合几乎一样,这里就不做示例了。

5.3求和等操作

使用Query对象即可进行求和等操作,通过QueryBuilder的build()方法即可得到。随后调用sumDouble()等方法传入求和条件即可。我们获取实体类或实体类集合也是使用的该对象获取。

复用Query和查询参数Parameters

复用第一个query,通过设置query的参数值,来描述第二个,第三个查询。

Query<User> query = userBox.query().equal(User_.firstName, "").build();
List<User> joes = query.setParameter(User_.firstName, "Joe").find();
List<User> jakes = query.setParameter(User_.firstName, "Jake").find();

限制、偏移和分页(Limit, Offset, and Pagination)

跳过第10条,从第11条开始,查询总数为5的结果

Query<User> query = userBox.query().equal(UserProperties.FirstName, "Joe").build();
List<User> joes = query.find(/** offset by */ 10, /** limit to */ 5 /** results */);

offset :第一个 偏移量结果被跳过。 

limit :返回此查询的数量。

懒加载

什么事懒加载?

我指定了查询条件,可以获得大量的数据。但是这些大量的数据获取到,是需要大量的时间。考虑到性能和用户体验,我们通常采取的做法是:这些大量的数据我们先不去全部获取,而是你使用到了具体的某个数据的时候,再去到数据库中获取。

Query提供了findLazy() 和 findLazyCached() 来达到懒加载的目的,这些方法返回了一个加强版的list:LazyList(当你去获取其中摸个元素的时候,它才会主动到数据库中加载数据)

再说下findLazyCached(),如其名,它在内存里面缓存了你从数据库中获取的数据。下次你再起获得它的时候,它直接从缓存里面获取数据,加快数据的命中速度。

聚合函数

有时你不想从查询中返回对象,而是得到一个属性的聚合值。ObjectBox支持以下方法(每个都以属性作为参数): 

min / minDouble:查找最小值。 

max / maxDouble:查找最大值。 

sum / sumDouble:计算所有值的总和。( ? Note: the non-double version detects overflows and throws an exception in that case.) 

avg : 计算所有值的平均值(double类型)。

另外,可以直接通过调用count()来获得结果的数量。

六、示例

示例:查询商品

long unit_id;
if (unitId == null || unitId.equals("")) {
    unit_id = 0;
} else {
    unit_id = Long.parseLong(unitId);
}

int onsales;
if (state.equals("")) {
    onsales = 0;
} else {
    onsales = Integer.parseInt(state);
}

Box<Product> box = ObjectBox.get().boxFor(Product.class);
//构造查询条件
QueryBuilder<Product> builder = box.query();
//如果类型为0即全部查询,否则查询该条件
if (category != 0) {
    builder.equal(Product_.category, category);
}
if (season != 0) {
    builder.equal(Product_.season, season);
}
if (brand != 0) {
    builder.equal(Product_.brand, brand);
}
if (gender != 0) {
    builder.equal(Product_.gender, gender);
}
if (unit_id != 0) {
    builder.equal(Product_.unitId, unit_id);
}
builder.equal(Product_.onsales, onsales);
//多个条件模糊查询输入的文字
builder.contains(Product_.phoneticInitial, prodName)
        .or().contains(Product_.productName, prodName)
        .or().contains(Product_.phoneticInitialAll, prodName)
        .or().contains(Product_.productCode, prodName)
        .or().contains(Product_.barcode, prodName);
//分页查询
List<Product> list = builder.build()
        .find((currentPage - 1) * pageSize, pageSize);

示例:新增商品

Box<Product> box = ObjectBox.get().boxFor(Product.class);
for (Product product : products) {
    box.put(product);
}

示例:修改商品

Box<Product> box = ObjectBox.get().boxFor(Product.class);
Query<Product> query = box.query().equal(Product_.productId, 0).build();
for (Product product : products) {
    try {
        Product findUnique = query.setParameter(Product_.productId, product.getProductId())
                .findUnique();
        if (findUnique == null) {
            box.put(product);
        } else {
            findUnique.setMerchantId(product.getMerchantId());
            findUnique.setOrgMerchantId(product.getOrgMerchantId());
            findUnique.setCoverUrl(product.getCoverUrl());
            findUnique.setPhoneticInitial(product.getPhoneticInitial());
            findUnique.setPhoneticInitialAll(product.getPhoneticInitialAll());
            findUnique.setProductName(product.getProductName());
            findUnique.setProductCode(product.getProductCode());
            findUnique.setBarcode(product.getBarcode());
            findUnique.setEntryPrice(product.getEntryPrice());
            findUnique.setWholesalePrice(product.getWholesalePrice());
            findUnique.setRetailPrice(product.getRetailPrice());
            findUnique.setMerchantPrice(product.getMerchantPrice());
            findUnique.setCreateTime(product.getCreateTime());
            findUnique.setUpdateTime(product.getUpdateTime());
            findUnique.setOnsales(product.getOnsales());
            findUnique.setSeason(product.getSeason());
            findUnique.setBrand(product.getBrand());
            findUnique.setGender(product.getGender());
            findUnique.setCategory(product.getCategory());
            findUnique.setConstituent(product.getConstituent());
            findUnique.setUnitId(product.getUnitId());
            box.put(findUnique);
        }
    } catch (NonUniqueResultException e) {
        e.printStackTrace();
        long[] ids = query.setParameter(Product_.productId, product.getProductId())
                .findIds();
        box.remove(ids);
        box.put(product);
    }
}

 类似资料: