- 人工智能
- AI 技能
- 文档
- 开发工具
【免费下载链接】DocAgent
UpdateResult是仓颉标准库std.database.sql包中专门承载数据变更类 SQL 语句执行结果的接口,它通过rowCount与lastInsertId两个属性,让开发者能够准确获知每次INSERT、UPDATE、DELETE语句影响的行数以及自增主键等信息。阅读本文后,你将掌握UpdateResult的接口定义、属性语义,以及结合Statement.update()在实际增删改场景中的完整用法。
接口定位:数据变更语句的结果载体
std.database.sql包为仓颉语言提供了访问数据库的通用接口,配合数据库驱动Driver完成对数据库的各项操作。在该包中,SQL 语句的执行结果被划分为两类接口:
QueryResult:执行SELECT查询语句产生的结果接口,用于遍历查询到的数据行;UpdateResult:执行INSERT、UPDATE、DELETE语句产生的结果接口,用于反映数据变更的执行效果。
二者的分工在包总览(database_sql_package_overview.md)与模块说明(readme.md)中均有明确记载:UpdateResult归入"SQL 语句执行"分组,紧邻Statement与QueryResult。也就是说,凡是会修改数据库内容的语句,其返回值类型基本都是UpdateResult。
接口定义与成员属性
在 API 参考文档 database_sql_package_interfaces.md 中,UpdateResult的完整定义为:
public interface UpdateResult { prop lastInsertId: Int64 prop rowCount: Int64 }接口本身不继承任何父类型,仅声明两个只读属性,其语义如下表所示(源自 UpdateResult_interface.md):
| 属性 | 原型 | 说明 |
|---|---|---|
lastInsertId | prop lastInsertId: Int64 | 执行INSERT语句自动生成的最后 row ID,如果不支持则 row ID 为 0。 |
rowCount | prop rowCount: Int64 | 执行INSERT、UPDATE、DELETE语句影响的行数。 |
任何继承该接口的class、interface、struct,都需要遵守上述属性的类型与语义约定。
prop lastInsertId:获取自动生成的主键 ID
lastInsertId的类型为Int64(对应核心库 Int64),用于获取执行INSERT语句时数据库自动生成的最后一条 row ID。
需要特别注意的边界行为:当数据库驱动不支持该能力时,返回值为0。因此在实际业务中,lastInsertId的值并不总是可靠的"自增主键",是否支持取决于具体数据库驱动实现,建议先验证驱动能力再做主键回填等业务逻辑。
prop rowCount:获取影响行数
rowCount的类型同样为Int64,表示INSERT、UPDATE、DELETE语句实际影响的数据行数。它是判断语句是否真正生效的通用手段:
- 执行
UPDATE时,若rowCount为0,通常表示没有匹配到满足WHERE条件的记录; - 执行
DELETE时,rowCount直接反映被删除的行数; - 执行
INSERT时,单行插入的rowCount一般为1。
实战:从 Statement.update() 获取更新结果
UpdateResult是Statement接口中update()方法的返回类型。在 API 文档 Statement_interface.md 中,Statement预执行接口定义了如下两个更新入口:
| 名称 | 原型 | 说明 |
|---|---|---|
update | (): UpdateResult | 执行 sql 语句,得到更新结果。 |
update(deprecated) | (params: Array<SqlDbType>): UpdateResult | 执行 sql 语句,得到更新结果。未来版本即将废弃不再使用,可使用update()替代。 |
典型的调用链是:DriverManager.getDriver()获取驱动 →Driver.open()打开数据源 →Datasource.connect()获取连接 →Connection.prepareStatement(sql)预执行语句 →Statement.set<T>()绑定参数 →Statement.update()得到UpdateResult。下面结合仓库中的官方示例逐一演示。
插入数据并读取结果
以下代码来自示例文档 db_operations.md,演示了连续执行两次插入并打印rowCount与lastInsertId:
import std.database.sql.* main() { // 获取数据库连接示例 let drv = DriverManager.getDriver("opengauss") ?? return let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", []) let conn = ds.connect() // 插入数据 1 var stmt = conn.prepareStatement("INSERT INTO test VALUES(?, ?)") stmt.set<String>(0, "li lei") stmt.set<Int32>(1, 12) var ur = stmt.update() println("Update Result: ${ur.rowCount} ${ur.lastInsertId}") // 插入数据 2 stmt.set<String>(0, "han meimei") stmt.set<Int32>(1, 13) ur = stmt.update() println("Update Result: ${ur.rowCount} ${ur.lastInsertId}") stmt.close() }其中set<String>(0, ...)、set<Int32>(1, ...)将仓颉原生类型绑定到 SQL 语句的?占位符,调用update()后返回的ur.rowCount即本次插入影响的行数,ur.lastInsertId为数据库自动生成的最后 row ID。
更新与删除数据
同一示例文档中的更新与删除操作同样借助UpdateResult反馈执行效果:
import std.database.sql.* main() { // 获取数据库连接示例 let drv = DriverManager.getDriver("opengauss") ?? return let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", []) let conn = ds.connect() // 更新操作示例 var stmt = conn.prepareStatement("update test set age = ? where name = ?") stmt.set<Int32>(0, 15) stmt.set<String>(1, "li lei") var ur = stmt.update() println("Update Result: ${ur.rowCount} ${ur.lastInsertId}") stmt.close() }import std.database.sql.* main() { // 获取数据库连接示例 let drv = DriverManager.getDriver("opengauss") ?? return let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", []) let conn = ds.connect() // 删除操作示例 var stmt = conn.prepareStatement("delete from test where name = ?") stmt.set<String>(0, "li lei") var ur = stmt.update() println("Update Result: ${ur.rowCount} ${ur.lastInsertId}") stmt.close() }从示例可见,无论是更新还是删除,rowCount都是判断匹配行数的最直接依据。
建表、删表等 DDL 场景
update()同样可以执行不返回数据集的 DDL 语句,返回的UpdateResult同样提供执行反馈。示例 db_modify_table.md 中演示了删表与建表:
import std.database.sql.* main() { // 获取数据库链接示例 let drv = DriverManager.getDriver("opengauss") ?? return let opts = [ ("cachePrepStmts", "true"), ("prepStmtCacheSize", "250"), ("prepStmtCacheSqlLimit", "2048") ] let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", opts) let conn = ds.connect() // 删除和创建表 var stmt = conn.prepareStatement("DROP TABLE IF EXISTS test") var ur = stmt.update() println("Update Result: ${ur.rowCount} ${ur.lastInsertId}") stmt.close() stmt = conn.prepareStatement("CREATE TABLE test(id SERIAL PRIMARY KEY, name VARCHAR(20) NOT NULL, age INT)") ur = stmt.update() println("Update Result: ${ur.rowCount} ${ur.lastInsertId}") stmt.close() }示例中的建表语句为id SERIAL PRIMARY KEY,这正是lastInsertId得以生效的典型场景——SERIAL自增列由数据库自动生成主键值。
深入:如何可靠获取插入后的主键 ID
lastInsertId依赖驱动支持,若驱动不支持则固定返回0。如果需要稳妥地在插入后拿到主键,仓库示例还提供了一种通用的替代方案:在 SQL 语句中使用RETURNING子句,再通过Statement.query()以QueryResult形式读取返回的主键列。见 db_operations.md:
import std.database.sql.* main() { // 获取数据库连接示例 let drv = DriverManager.getDriver("opengauss") ?? return let ds = drv.open("opengauss://testuser:testpwd@localhost:5432/testdb", []) let conn = ds.connect() // 如果需要在插入数据后返回插入的 id 值,可以参考如下方式: let sql = "INSERT INTO test (name, age) VALUES (?,?) RETURNING id, name" try (stmt = conn.prepareStatement(sql)) { stmt.set<String>(0, "li lei") stmt.set<Int32>(1, 12) let qr = stmt.query() while (qr.next()) { println("id = ${qr.get<Int32>(0)}, name=${qr.get<String>(1)}") } } catch (e: Exception) { e.printStackTrace() } stmt.close() }因此,在业务设计中可以按需选择:
- 仅需确认语句执行成功/影响行数:使用
update()+rowCount; - 需要拿到自动生成的主键:优先使用
RETURNING+query(),或在驱动支持的前提下使用lastInsertId(注意不支持时为0的约定)。
与 QueryResult 的分工与注意事项
UpdateResult与QueryResult分别面向"数据变更"与"数据查询"两类语句,二者都是Statement接口的返回值类型。实践中需要注意以下几点:
- 类型对齐:
rowCount与lastInsertId均为Int64。在包总览 database_sql_package_overview.md 的 SQL 与仓颉类型对照表中,BIGINT对应Int64、INTEGER对应Int32,因此读取行数、ID 这类数值结果时按对应类型取值即可。 lastInsertId的兼容性:接口文档明确约定"如果不支持则 row ID 为 0",因此不能假设每次插入后该属性都有意义;对不支持自增列或驱动不提供该能力的数据库,应以0兜底处理。- 语句执行失败的处理:
Statement.update()在执行过程中发生异常(如网络中断、服务器超时、参数个数不正确)时会抛出 SqlException,异常对象携带数据库供应商返回的errorCode与五字符sqlState,可用于错误定位与排查。 - 资源释放:从示例中可以看到,
Statement在使用完毕后均调用stmt.close()释放资源;在多语句、长连接场景下应养成良好的关闭习惯。
小结
UpdateResult是仓颉std.database.sql包中处理数据变更语句结果的核心接口:rowCount提供通用的影响行数反馈,lastInsertId提供驱动能力允许时的自增主键获取。结合Statement.update()与仓库中的官方示例,即可在插入、更新、删除乃至建表、删表等各类语句执行后,准确掌握数据库端的执行效果;如需稳妥获取插入主键,可进一步采用RETURNING子句配合QueryResult读取。相关完整 API 与示例可继续查阅:
- 接口完整定义:database_sql_package_interfaces.md
- 语句执行接口:Statement_interface.md
- 增删改实战示例:db_operations.md
- 建表删表示例:db_modify_table.md
- 人工智能
- AI 技能
- 文档
- 开发工具
【免费下载链接】DocAgent
相关推荐
仓颉标准库 database.sql 预执行接口 Statement 详解:参数绑定、查询与更新的完整实践
仓颉标准库 database.sql 预执行接口 Statement 详解:参数绑定、查询与更新的完整实践 导读 std.database.sql 是仓颉标准库
人工智能AI 技能文档开发工具仓颉 std.database.sql 实战:Insert、Update、Delete 与 Select 数据库操作语句执行指南
仓颉 std.database.sql 实战:Insert、Update、Delete 与 Select 数据库操作语句执行指南 本篇基于仓颉标准库 std.d
文档知识库教程OpenHarmony仓颉标准库 database.sql 异常处理指南:SqlException 类全解析
仓颉标准库 database.sql 异常处理指南:SqlException 类全解析 本篇指南围绕仓颉标准库 std.database.sql 包中唯一的内置
人工智能AI 技能文档开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考