跳到内容
CrossFly 是 100% 开源在 GitHub 关注我们
CrossFlyCrossFly
开始使用

本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。

如何在 SQLite 中进行参数化 CRUD

目的。 使用位置参数(?)执行 INSERT/UPDATE/DELETE 和 SELECT,避免字符串拼接(它会导致 SQL 注入和引号错误)。请注意 CrossFly 的两种索引约定。

⚠️ 索引。 在绑定参数时,索引从 1 开始(? 第 1、2、… 个)。在从 cursor 读取列时,索引从 0 开始(getString(0) = 第一列)。这是有意为之,并且与 SQLite 的原生 API 一致。

使用的 API

  • SqliteDb.execute(String sql, Object... params) —— 准备语句、执行 bindAll(params)(bind 从 1 开始)、执行单个 INSERT/UPDATE/DELETE,并返回受影响的行数(int)。类型会被推断:Integer/Long/Short/Byte→整数,Float/Double→实数,Boolean→0/1,byte[]→BLOB,null→NULL,否则 toString()→TEXT。
  • SqliteDb.query(String sql, Object... params) —— 返回一个已打开的 SqliteCursor(bind 从 1 开始)。调用方必须关闭(使用 try-with-resources)。
  • SqliteCursor.next() —— 前进到下一行;如果有行则返回 true。
  • SqliteCursor.getInt(col)/getLong/getDouble/getString/getBlob/isNull(col) —— 类型化的 getter,列从 0 开始。
  • SqliteDb.queryLong(sql, defaultValue, params) —— 快捷方式:第一行第一列作为 long,若无行则返回 defaultValue。
  • SqliteDb.queryString(sql, params) —— 快捷方式:第一行第一列作为 String,若无行则返回 null。
  • SqliteDb.lastInsertRowid() —— 最后一次 INSERT 的 rowid(long)。SqliteDb.changes() —— 最后一条语句更改的行数。

完整示例(复制、粘贴并运行)

package com.exemplo;

import dev.crossfly.ui.*;                     // Window
import dev.crossfly.ui.layout.*;             // VerticalLayout
import dev.crossfly.sqlite.*;                // SqliteDb, SqliteCursor

/** 可执行的主界面。将 launcher 指向此类(classname)并运行:gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      try (SqliteDb db = SqliteDb.open("app.db"))
      {
         db.exec("CREATE TABLE IF NOT EXISTS person(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");

         // CREATE — 位置参数(? 第 1 = name,? 第 2 = age)
         int inserted = db.execute("INSERT INTO person(name, age) VALUES(?, ?)", "Alice", 30);
         long id = db.lastInsertRowid();            // 生成的 rowid
         System.out.println(inserted + " linha(s), id=" + id);

         // READ — cursor:列从 0 开始
         try (SqliteCursor c = db.query("SELECT name, age FROM person WHERE age > ?", 18))
         {
            while (c.next())
               System.out.println(c.getString(0) + " = " + c.getInt(1));   // col 0 = name,col 1 = age
         }

         // READ 标量 — 快捷方式
         long total = db.queryLong("SELECT count(*) FROM person", 0);
         String nome = db.queryString("SELECT name FROM person WHERE id = ?", id);

         // UPDATE — 返回受影响的行数
         int updated = db.execute("UPDATE person SET age = ? WHERE id = ?", 31, id);

         // DELETE
         int deleted = db.execute("DELETE FROM person WHERE id = ?", id);
      }
   }
}

下面的代码片段仅展示核心部分。要运行它,请将其放入上面的 MainWindow 骨架中。

最小片段

// 已在源码验证:execute(bind 从 1 开始)、query + cursor(getters 从 0 开始)、queryLong/queryString
import dev.crossfly.sqlite.*;

try (SqliteDb db = SqliteDb.open("app.db"))
{
   db.exec("CREATE TABLE IF NOT EXISTS person(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");

   // CREATE — 位置参数(? 第 1 = name,? 第 2 = age)
   int inserted = db.execute("INSERT INTO person(name, age) VALUES(?, ?)", "Alice", 30);
   long id = db.lastInsertRowid();            // 生成的 rowid
   System.out.println(inserted + " linha(s), id=" + id);

   // READ — cursor:列从 0 开始
   try (SqliteCursor c = db.query("SELECT name, age FROM person WHERE age > ?", 18))
   {
      while (c.next())
         System.out.println(c.getString(0) + " = " + c.getInt(1));   // col 0 = name,col 1 = age
   }

   // READ 标量 — 快捷方式
   long total = db.queryLong("SELECT count(*) FROM person", 0);
   String nome = db.queryString("SELECT name FROM person WHERE id = ?", id);

   // UPDATE — 返回受影响的行数
   int updated = db.execute("UPDATE person SET age = ? WHERE id = ?", 31, id);

   // DELETE
   int deleted = db.execute("DELETE FROM person WHERE id = ?", id);
}

深入了解

这个页面有帮助吗?