本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。
使用 SQLite 持久化
在 CrossFly 中持久化结构化数据的规范方式是 dev.crossfly.sqlite 模块 ——
它是对原生库 cfsqlite(SQLite3MultipleCiphers)的一层薄封装。它取代了旧的
dev.crossfly.sql(JDBC)。
在绘制线程之外运行数据库,并用
Component.onUI(...)回到 UI(见 后台工作)。SqliteDb、SqliteStmt和SqliteCursor都是AutoCloseable→ 请使用 try-with-resources。
打开 / 关闭
try (SqliteDb db = SqliteDb.open("app.db")) {
db.exec("CREATE TABLE IF NOT EXISTS cliente(id INTEGER PRIMARY KEY, nome TEXT, idade INTEGER)");
// … 使用 db …
} // 自动关闭
工厂方法:SqliteDb.open(String)、open(String, int flags)、open(String, byte[] key)(加密)、
openMemory()。
参数化 CRUD
// INSERT/UPDATE/DELETE → execute(sql, params...) 返回受影响的行数
db.execute("INSERT INTO cliente(nome, idade) VALUES(?, ?)", "Ana", 30);
db.execute("UPDATE cliente SET idade=? WHERE id=?", 31, 1);
// SELECT → query(sql, params...) 返回一个游标
try (SqliteCursor c = db.query("SELECT id, nome, idade FROM cliente WHERE idade > ?", 18)) {
while (c.next()) {
long id = c.getLong(0); // ⚠️ 游标的 getter 是从 0 开始的
String nome= c.getString(1);
int idade = c.getInt(2);
}
}
// 单一值:
long total = db.queryLong("SELECT COUNT(*) FROM cliente", 0);
String nome = db.queryString("SELECT nome FROM cliente WHERE id=?", 1);
⚠️ 索引的坑:绑定从 1 开始,getter 从 0 开始
| 操作 | 起始基准 | 示例 |
|---|---|---|
参数绑定(SqliteStmt) |
从 1 开始 | stmt.bindString(1, nome) |
列getter(SqliteCursor) |
从 0 开始 | cursor.getString(0) |
这是该模块最常见的错误 —— ? 从 1 开始,结果集的列从 0 开始。
事务与批量写入
db.transaction(() -> { // 自动 begin/commit(异常时 rollback)
db.execute("INSERT INTO cliente(nome) VALUES(?)", "A");
db.execute("INSERT INTO cliente(nome) VALUES(?)", "B");
});
// 手动的 begin/commit/rollback 也存在:
db.begin(); /* … */ db.commit();
// 批量写入(内部复用 statement):
List<Object[]> linhas = List.of(new Object[]{"A", 1}, new Object[]{"B", 2});
db.bulkInsert("INSERT INTO cliente(nome, idade) VALUES(?, ?)", linhas);
可复用的预编译 statement
try (SqliteStmt st = db.prepare("INSERT INTO cliente(nome, idade) VALUES(?, ?)")) {
for (Cliente c : lista) {
st.bindAll(c.nome, c.idade); // 或 bindString(1, ...).bindInt(2, ...)
st.step();
st.reset(); // 复用 statement
}
}
可选加密
byte[] chave = obterChave(); // 你的密钥 (byte[])
try (SqliteDb db = SqliteDb.open("secreto.db", chave)) { // 默认使用 ChaCha20-Poly1305 加密
// … 加密的数据库 …
db.rekey(novaChave); // 更换密钥(或传入另一个以移除)
}
不提供密钥 = 普通 SQLite,零开销。支持的加密算法包括 CHACHA20(默认)、
SQLCIPHER、AES256CBC 等(Sqlite.Cipher)。
键/值表(取代旧的轻量持久化)
轻量持久化(Settings.appSettings)已被移除。对于标志/主题/上次登录,一张
键/值表即可解决:
db.exec("CREATE TABLE IF NOT EXISTS kv(k TEXT PRIMARY KEY, v TEXT)");
db.execute("INSERT OR REPLACE INTO kv(k, v) VALUES(?, ?)", "tema", "escuro");
String tema = db.queryString("SELECT v FROM kv WHERE k=?", "tema");
见文件与偏好设置。
最佳实践
- 始终使用 try-with-resources(db、stmt、cursor)—— 避免泄漏原生句柄。
- 批量写入 →
transaction(...)/bulkInsert(...)(快数个数量级)。 - 数据库操作放在绘制线程之外;结果用
onUI(...)返回。
常见错误
- 弄反起始基准:
?是从 1 开始,cursor 的列是从 0 开始。 - 在绘制线程上运行查询,导致 UI 卡死。
- 忘记关闭 cursor/statement(泄漏原生资源)。
另见
这个页面有帮助吗?感谢你的反馈!