-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Java|Kotlin 增删查改
增删查改是数据库最常用的功能,因此 WCDB Java/Kotlin 对其进行了特别的封装,使其通过一行代码即可完成操作。
插入操作有 insertObject
、 insertOrReplaceObject
、insertOrIgnoreObject
三类接口。故名思义,前者只是单纯的插入数据,当数据出现冲突时会失败,而后者在主键冲突等约束冲突出现时,新数据会覆盖旧数据。
以已经完成模型绑定的类 Sample
为例:
//Java
Sample sample = new Sample();
sample.id = 1;
database.insertObject(sample, DBSample.allFields(), "sampleTable"); // 插入成功
database.insertObject(sample, DBSample.allFields(), "sampleTable"); // 插入失败,因为主键 id = 1 已经存在
sample.content = "insertOrReplace";
database.insertOrReplaceObject(sample, DBSample.allFields(), "sampleTable"); // 插入成功,且 content 的内容会被替换为 "insertOrReplace"
sample.content = "insertOrIgnore";
database.insertOrIgnoreObject(sample, DBSample.allFields(), "sampleTable"); // 插入成功,但 content 的内容不会更改,还是 "insertOrReplace"
//Kotlin
val sample = Sample()
sample.id = 1
database.insertObject(sample, DBSample.allFields(), "sampleTable") // 插入成功
database.insertObject(sample, DBSample.allFields(), "sampleTable") // 插入失败,因为主键 id = 1 已经存在
sample.content = "insertOrReplace"
database.insertOrReplaceObject(sample, DBSample.allFields(), "sampleTable") // 插入成功,且 content 的内容会被替换为 "insertOrReplace"
sample.content = "insertOrIgnore"
database.insertOrIgnoreObject(sample, DBSample.allFields(), "sampleTable") // 插入成功,但 content 的内容不会更改,还是 "insertOrReplace"
关于自增插入,可参考模型绑定 - 自增属性一章。
insert
方法的原型为:
// insert、insertOrReplace、insertOrIgnore只有方法名不同,其他参数都一样。
public <T> void insertObject(
T object, // 需要插入的对象
Field<T>[] fields, // 需要插入的字段
String tableName // 表名
) throws WCDBException
这里需要特别注意的是 fields
参数,它是 Field
对象的数组。我们会在语言集成查询进一步介绍。这里只需了解,它可以传入模型绑定中定义的字段,传入所有字段可以直接用DBSample.allFields()
,也可以传入部分字段,这样只会插入指定的字段,这就构成了部分插入。
以下是一个部分插入的例子:
//Java
Sample sample = new Sample();
sample.id = 1;
sample.content = "insert";
database.insertObject(sample, new Field[]{DBSample.id}, "sampleTable");// 部分插入,没有指定content字段
//Kotlin
val sample = Sample()
sample.id = 1
sample.content = "insert"
database.insertObject(sample, arrayOf(DBSample.id), "sampleTable") // 部分插入,没有指定content字段
这个例子中,指定了只插入 id
字段,因此其他没有指定的字段,会使用 模型绑定中定义的默认值 或 空 来代替。这里 content
没有定义默认值,因此其数据为空。
除了插入单个对象的接口,也有插入多个对象的系列接口: insertObjects
、 insertOrReplaceObjects
、insertOrIgnoreObjects
。这类接口第一个参数可以传入Collection<T>
集合类型数据,这批对象要么一起插入成功,要么一起插入失败。
//Java
Sample sample2 = new Sample();
sample2.id = 2;
sample2.content = "insert2";
Sample sample3 = new Sample();
sample3.id = 3;
sample3.content = "insert3";
database.insertObjects(Arrays.asList(sample2, sample3), DBSample.allFields(), "sampleTable");
//Kotlin
val sample2 = Sample()
sample2.id = 2
sample2.content = "insert2"
val sample3 = Sample()
sample3.id = 3
sample3.content = "insert3"
database.insertObjects(listOf(sample2, sample3), DBSample.allFields(), "sampleTable")
插入是最常用且比较容易操作卡顿的操作,因此 WCDB Java/Kotlin 对其进行了特殊处理。 当插入的对象数大于 1 时,WCDB Java/Kotlin 会自动开启事务,进行批量化地插入,以获得更好的性能。
删除操作主要是通过deleteObjects
系列方法,它支持不同的传入参数组合,其中参数最全的一个方法声明为:
public void deleteObjects(
String tableName, // 表名
Expression condition, // 符合删除的条件
OrderingTerm order, // 排序的方式
long limit, // 删除的个数
long offset // 从第几个开始删除
) throws WCDBException
删除方法会删除表内的数据,并通过 condition
、order
、limit
和 offset
参数来确定需要删除的数据的范围。
这四个组合起来可以理解为:将 tableName
表内,满足 condition
的数据,按照 order
的方式进行排序,然后从头开始第 offset
行数据后的 limit
行数据删除。
以下是删除接口的示例代码:
// 删除 sampleTable 中所有 identifier 大于 1 的行的数据
database.deleteObjects("sampleTable", DBSample.id.gt(1));
// 删除 sampleTable 中 identifier 降序排列后的前 2 行数据
database.deleteObjects("sampleTable", DBSample.id.order(Order.Desc), 2);
// 删除 sampleTable 中 description 非空的数据,按 identifier 降序排列后的前 3 行的后 2 行数据
database.deleteObjects("sampleTable", DBSample.content.notNull(), DBSample.id.order(Order.Desc), 2, 3);
// 删除 sampleTable 中的所有数据
database.deleteObjects("sampleTable");
这里的 condition
参数作为Expression
的对象,可以是数字、字符串、字段或其他更多的组合,可以表达任意sqlite支持的表达式,我们会在语言集成查询进一步介绍。
删除接口不会删除表本身,开发者需要调用
dropTable(String)
接口删除表。
更新数据库的时候可以使用Java/Kotlin对象来更新数据库,也可以直接使用具体值来更新。
使用Java/Kotlin对象的接口为updateObject
系列方法,可以通过fields
参数指定更新的字段,使用condition
、orders
、limit
、offset
参数来指定更新范围。下面是参数最全的方法的原型:
public <T> void updateObject(
T object, //更新的对象
Field<T>[] fields, //需要更新的字段
String tableName, //更新的表名
Expression condition,//筛选条件
OrderingTerm order, //排序方式
long limit, //更新的个数
long offset //从第几个开始更新
) throws WCDBException
以下是更新操作的示例代码:
//Java
Sample sample = new Sample();
sample.content = "update";
// 将 sampleTable 中所有 id 大于 1 且 content 字段不为空 的行的 content 字段更新为 "update"
database.updateObject(
sample,
new Field[]{DBSample.content},
"sampleTable",
DBSample.id.gt(1).and(DBSample.content.notNull()));
// 将 sampleTable 中前三行的 content 字段更新为 "update"
database.updateObject(
sample,
new Field[]{DBSample.content},
"sampleTable",
DBSample.id.order(Order.Asc),
3);
//Kotlin
val sample = Sample()
sample.content = "update"
// 将 sampleTable 中所有 id 大于 1 且 content 字段不为空 的行的 content 字段更新为 "update"
database.updateObject(
sample,
arrayOf(DBSample.content),
"sampleTable",
DBSample.id.gt(1).and(DBSample.content.notNull())
)
// 将 sampleTable 中前三行的 content 字段更新为 "update"
database.updateObject(
sample,
arrayOf(DBSample.content),
"sampleTable",
DBSample.id.order(Order.Desc),
3
)
使用值来更新主要是updateValue
和updateRow
两个系列接口。前者使用单个值来更新,这里的值可以是各种支持ORM的java基础类型,也可以是封装了这些基础类型的Value
对象;后者是使用一行数据来更新,一行数据用Value
组来表示。
updateValue
和updateRow
同样也可以通过columns
参数指定更新的字段,使用condition
、orders
、limit
、offset
参数来指定更新范围。下面是参数最全的接口的原型:
public void updateValue(
Value value, //更新的值
Column column, //指定更新的列,Column是Field的基类
String tableName, //更新的表名
Expression condition, //筛选条件
OrderingTerm order, //排序方式
long limit, //更新的个数
long offset //从第几个开始更新
) throws WCDBException
public void updateRow(
Value[] row, //更新的行数据
Column[] columns, //指定更新的列,Column是Field的基类
String tableName, //更新的表名
Expression condition, //筛选条件
OrderingTerm order, //排序方式
long limit, //更新的个数
long offset //从第几个开始更新
) throws WCDBException
而 "with row" 接口则是通过 row 来对数据进行更新。row 是遵循 ColumnEncodable
协议的类型的数组。ColumnEncodable
协议会在后续[自定义字段映射类型][Swift-Custom-ORM-Column-Type]中进一步介绍。这里只需了解,能够进行字段映射的类型基本都遵循 ColumnEncodable
协议。
因此,与 "with object" 对应的示例代码为:
//Java
// 将 sampleTable 中所有 id 大于 1 且 content 字段不为空 的行的 content 字段更新为 "update"
database.updateValue(
"update",
DBSample.content,
"sampleTable",
DBSample.id.gt(1).and(DBSample.content.notNull()));
// 将 sampleTable 中前三行的 content 字段更新为 "update"
database.updateRow(
new Value[]{new Value("update")},
new Column[]{DBSample.content},
"sampleTable",
DBSample.id.order(Order.Asc),
3);
//Kotlin
// 将 sampleTable 中所有 id 大于 1 且 content 字段不为空 的行的 content 字段更新为 "update"
database.updateValue(
"update",
DBSample.content,
"sampleTable",
DBSample.id.gt(1).and(DBSample.content.notNull())
)
// 将 sampleTable 中前三行的 content 字段更新为 "update"
database.updateRow(
arrayOf(Value("update")),
arrayOf(DBSample.content),
"sampleTable",
DBSample.id.order(Order.Asc),
3
)
查找接口接口较多,但大部分都是为了简化操作而提供的便捷接口,和更新接口类似,实现上主要分为对象查找和值查找两大类接口。
getFirstObject
和 getAllObjects
系列接口都是对象查找的接口,他们直接返回已进行模型绑定的对象。它们都可以使用fields
来指定查询的字段,使用condition
、orders
、limit
、offset
参数来指定查询范围。
getFirstObject
等价于 limit
为 1 时的 getAllObjects
接口。不同的是,它直接返回 Object
对象,而不是一个数组,使用上更便捷。它们的参数最全版本的接口原型为:
public <T> T getFirstObject(
Field<T>[] fields, //指定查询的字段,查询所有字段可以用DBxxx.allFields()
String tableName, //查询的表名
Expression condition, //筛选条件
OrderingTerm order, //排序方式
long limit, //查询的个数
long offset //从第几个开始读取
) throws WCDBException
public <T> List<T> getAllObjects(
Field<T>[] fields, //指定查询的字段,查询所有字段可以用DBxxx.allFields()
String tableName, //查询的表名
Expression condition, //筛选条件
OrderingTerm order, //排序方式
long limit, //查询的个数
long offset //从第几个开始读取
) throws WCDBException
以下是对象查找操作的示例代码:
//Java
// 返回 sampleTable 中的所有数据
List<Sample> allObjects = database.getAllObjects(DBSample.allFields(), "sampleTable");
// 返回 sampleTable 中 identifier 小于 5 或 大于 10 的行的数据
List<Sample> objects = database.getAllObjects(DBSample.allFields(), "sampleTable",
DBSample.id.lt(5).or(DBSample.id.gt(10)));
// 返回 sampleTable 中 identifier 最大的行的数据
Sample object = database.getFirstObject(DBSample.allFields(), "sampleTable",
DBSample.id.order(Order.Desc));
// 返回 sampleTable 中的所有id字段,返回结果中的content内容为空
List<Sample> partialObjects = database.getAllObjects(new Field[]{DBSample.id}, "sampleTable");
//Kotlin
// 返回 sampleTable 中的所有数据
val allObjects = database.getAllObjects(DBSample.allFields(), "sampleTable")
// 返回 sampleTable 中 identifier 小于 5 或 大于 10 的行的数据
val objects = database.getAllObjects(DBSample.allFields(), "sampleTable",
DBSample.id.lt(5).or(DBSample.id.gt(10)))
// 返回 sampleTable 中 identifier 最大的行的数据
val `object` = database.getFirstObject(DBSample.allFields(),"sampleTable",
DBSample.id.order(Order.Desc))
// 返回 sampleTable 中的所有id字段,返回结果中的content内容为空
val partialObjects: List<Sample> = database.getAllObjects(arrayOf(DBSample.id), "sampleTable")
值查询有下面四类接口,这些接口都可以使用condition
、orders
、limit
、offset
参数来指定查找范围,以及使用columns
参数来指定查找的字段:
getValue
-
getOneColumn
,以及它的特定类型变体:getOneColumnInt
、getOneColumnLong
、getOneColumnFloat
、getOneColumnDouble
、getOneColumnString
、getOneColumnBLOB
getOneRow
getAllRows
试考虑,表中的数据可以想象为一个矩阵的存在,假设其数据如下:
identifier | description |
---|---|
1 | "sample1" |
2 | "sample1" |
3 | "sample2" |
4 | "sample2" |
5 | "sample2" |
在不考虑 condition
、orderList
、limit
和 offset
参数的情况下:
-
getAllRows
接口获取整个矩阵的所有内容,即返回值为二维数组。 -
getOneRow
接口获取某一横行的数据,即返回值为一维数组。 -
getOneColumn
接口获取某一纵列的数据,即返回值为一维数组。 -
getValue
接口获取矩阵中某一个格的内容。
以下是值查询操作的示例代码:
//Java
// 获取所有内容
List<Value[]> allRows = database.getAllRows(DBSample.allFields(), "sampleTable");
System.out.print(allRows.get(2)[0].getInt());// 输出 3
// 获取第二行
Value[] secondRow = database.getOneRow(DBSample.allFields(), "sampleTable", DBSample.id.order(Order.Desc), 1);
System.out.print(secondRow[0]);// 输出 3
// 获取第二行 content 列的值
List<Value> contentColumn = database.getOneColumn(DBSample.content, "sampleTable");
System.out.print(contentColumn.get(2).getText());// 输出 sample2
// 直接获取第二行 content 列的字符串值,性能更好
List<String> contentStrings = database.getOneColumnString(DBSample.content, "sampleTable");
System.out.print(contentStrings.get(2));//输出 sample2
// 获取第二列第二行的值
Value value = database.getValue(DBSample.content, "sampleTable", DBSample.id.order(Order.Asc), 1);
System.out.print(value.getText());
// 获取 identifier 的最大值
Value maxId = database.getValue(DBSample.id.max(), "sampleTable");
System.out.print(maxId.getInt());// 输出 5
//Kotlin
// 获取所有内容
val allRows = database.getAllRows(DBSample.allFields(), "sampleTable")
print(allRows[2][0].int) // 输出 3
// 获取第二行
val secondRow = database.getOneRow(DBSample.allFields(),"sampleTable", DBSample.id.order(Order.Desc), 1)
print(secondRow[0]) // 输出 3
// 获取第三行 content 列的值
val contentColumn = database.getOneColumn(DBSample.content, "sampleTable")
print(contentColumn[2].text) // 输出 sample2
// 直接获取第二行 content 列的字符串值,性能更好
val contentStrings = database.getOneColumnString(DBSample.content, "sampleTable")
print(contentStrings[2]) //输出 sample2
// 获取第二列第二行的值
val value = database.getValue(DBSample.content, "sampleTable", DBSample.id.order(Order.Asc), 1)
print(value.text)
// 获取 identifier 的最大值
val maxId = database.getValue(DBSample.id.max(), "sampleTable")
print(maxId.int) // 输出 5
- 欢迎使用 WCDB
- 基础教程
- 进阶教程
- 欢迎使用 WCDB
- 基础教程
- 进阶教程
- 欢迎使用 WCDB
- 基础教程
- 进阶教程
- 欢迎使用 WCDB
- 基础教程
- 进阶教程