Flutter——數據庫Drift開發詳細教程(七)

目錄

  • 入門
    • 設置
  • 漂移文件
    • 入門
    • 變量
    • 數組
    • 定義表
      • 支持的列類型
      • 漂移特有的功能
  • 導入
  • 嵌套結果
  • LIST子查詢
  • Dart 互操作
    • SQL 中的 Dart 組件
    • 類型轉換器
    • 現有的行類
    • Dart 文檔注釋
  • 結果類名稱
  • 支持的語句

入門

Drift 提供了一個dart_api來定義表和編寫 SQL 查詢。尤其當您已經熟悉 SQL 時,直接在 SQL 中使用CREATE TABLE語句定義表可能會更方便。得益于 Drift 內置的強大 SQL 解析器和分析器,您仍然可以運行類型安全的 SQL 查詢,并支持自動更新流和所有其他 Drift 功能。SQL 的有效性在構建時進行檢查,Drift 會為每個表和 SQL 語句生成匹配的方法。

設置

添加漂移依賴項的基本設置與 dart_apis 的設置一致。具體描述請參閱設置頁面。

不同之處在于表和查詢的聲明方式。為了讓Drift識別SQL,需要將其放入.drift文件中。在此示例中,我們.drift在數據庫類旁邊使用了一個名為的文件tables.drift:

-- this is the tables.drift file
CREATE TABLE todos (id INT NOT NULL PRIMARY KEY AUTOINCREMENT,title TEXT,body TEXT,category INT REFERENCES categories (id)
);CREATE TABLE categories (id INT NOT NULL PRIMARY KEY AUTOINCREMENT,description TEXT
) AS Category; -- see the explanation on "AS Category" below/* after declaring your tables, you can put queries in here. Justwrite the name of the query, a colon (:) and the SQL: */
todosInCategory: SELECT * FROM todos WHERE category = ?;/* Here's a more complex query: It counts the amount of entries per
category, including those entries which aren't in any category at all. */
countEntries:SELECTc.description,(SELECT COUNT(*) FROM todos WHERE category = c.id) AS amountFROM categories cUNION ALLSELECT null, (SELECT COUNT(*) FROM todos WHERE category IS NULL);

Drift 會為您的表生成 Dart 類,這些類的名稱基于表名。默認情況下,Drift 會去除s表尾的空格。這在大多數情況下都適用,但在某些情況下(例如categories上表)則不行。我們希望生成一個 Category類(而不是Categorie),所以我們告訴 Drift 生成一個不同的名稱,并AS 在末尾添加聲明。

將漂移文件集成到數據庫很簡單,只需將其添加到 注釋include的參數中即可**@DriftDatabase**。tables這里可以省略該參數,因為沒有 Dart 定義的表需要添加到數據庫中。

import 'dart:io';import 'package:drift/drift.dart';
// These imports are used to open the database
import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;part 'database.g.dart';(// relative import for the drift file. Drift also supports `package:`// importsinclude: {'tables.drift'},
)
class AppDb extends _$AppDb {AppDb() : super(_openConnection());int get schemaVersion => 1;
}LazyDatabase _openConnection() {// the LazyDatabase util lets us find the right location for the file async.return LazyDatabase(() async {// put the database file, called db.sqlite here, into the documents folder// for your app.final dbFolder = await getApplicationDocumentsDirectory();final file = File(p.join(dbFolder.path, 'db.sqlite'));return NativeDatabase.createInBackground(file);});
}

要生成database.g.dart包含**_$AppDb** 超類的文件,請dart run build_runner build在命令行上運行。

漂移文件

Drift 文件是一項新功能,允許您使用 SQL 編寫所有數據庫代碼。但與您傳遞給簡單數據庫客戶端的原始 SQL 字符串不同,Drift
文件中的所有內容都經過 Drift 強大的 SQL 分析器驗證。這使您能夠更安全地編寫 SQL 查詢:Drift
會在構建過程中發現其中的錯誤,并為其生成類型安全的 dart_api,這樣您就無需手動讀取結果。

入門

要使用此功能,我們需要創建兩個文件:database.dart和tables.drift。 Dart 文件僅包含設置數據庫的最少代碼:

import 'package:drift/drift.dart';
import 'package:drift/native.dart';part 'database.g.dart';(include: {'tables.drift'},
)
class MyDb extends _$MyDb {// This example creates a simple in-memory database (without actual// persistence).// To store data, see the database setups from other "Getting started" guides.MyDb() : super(NativeDatabase.memory());int get schemaVersion => 1;
}

我們現在可以在漂移文件中聲明表和查詢:

CREATE TABLE todos (id INT NOT NULL PRIMARY KEY AUTOINCREMENT,title TEXT NOT NULL,content TEXT NOT NULL,category INTEGER REFERENCES categories(id)
);CREATE TABLE categories (id INT NOT NULL PRIMARY KEY AUTOINCREMENT,description TEXT NOT NULL
) AS Category; -- the AS xyz after the table defines the data class name-- You can also create an index or triggers with drift files
CREATE INDEX categories_description ON categories(description);-- we can put named SQL queries in here as well:
createEntry: INSERT INTO todos (title, content) VALUES (:title, :content);
deleteById: DELETE FROM todos WHERE id = :id;
allTodos: SELECT * FROM todos;

使用 運行構建運行器后dart run build_runner build,drift 將寫入database.g.dart 包含_$MyDb超類的文件。讓我們看看我們得到了什么:

  • 生成的數據類(Todo和Category)以及用于插入的配套版本(更多信息請參閱Dart Interop)。默認情況下,drift
    會從類的表名中去掉尾部的“s”。這就是為什么我們AS Category在第二個表上使用 —— 否則它就會被 Categorie這樣調用。
  • 運行查詢的方法:
  • 一個Future createEntry(String title, String
    content)方法。它使用提供的數據創建一個新的待辦事項條目,并返回所創建條目的 ID。
  • Future deleteById(int id):根據 ID 刪除待辦事項條目,并返回受影響的行數。
  • Selectable
    allTodos()。它可用于獲取或查看所有待辦事項。它可以與allTodos().get()和 一起
    使用allTodos().watch()。
  • 不匹配表的選擇語句的類。在上面的例子中,該類AllTodosResult包含所有字段 todos以及相關類別的描述。

變量

在命名查詢中,您可以像在 SQL 中一樣使用變量。我們支持常規變量 ( ?)、顯式索引變量 ( ?123) 和冒號命名變量 ( :id)。我們不支持使用 @ 或 $ 聲明的變量。編譯器將嘗試通過查看變量的上下文來推斷其類型。這使得 Drift 能夠為您的查詢生成類型安全的 API,變量將作為參數寫入您的方法。

當變量類型不明確時,分析器可能無法解析該變量的類型。對于這些情況,你也可以指定變量的顯式類型:

myQuery(:variable AS TEXT): SELECT :variable;

除了基類型之外,還可以聲明類型可為空:

myNullableQuery(:variable AS TEXT OR NULL): SELECT :variable;

最后,你可以在 Dart 中使用命名參數時聲明一個變量是必需的。為此,請添加一個REQUIRED關鍵字:

myRequiredQuery(REQUIRED :variable AS TEXT OR NULL): SELECT :variable;

named_parameters 請注意,這僅在啟用構建選項時才有效。此外,默認情況下需要非空變量。

數組

如果要檢查某個值是否在值數組中,可以使用IN ?。這不是有效的 SQL,但 Drift 會在運行時對其進行語法糖解析。因此,對于以下查詢:

entriesWithId: SELECT * FROM todos WHERE id IN ?;

Drift 會生成一個Selectable entriesWithId(List ids)方法。運行后entriesWithId([1,2])會生成SELECT * … id IN (?1, ?2)并綁定相應的參數。為了確保其按預期工作,Drift 施加了兩個小限制:

  1. 沒有顯式變量:WHERE id IN ?2將在構建時被拒絕。由于變量已擴展,因此為其提供單個索引是無效的。
  2. 變量后沒有更高的顯式索引:運行 WHERE id IN ? OR title = ?2也會被拒絕。擴展變量可能會與顯式索引沖突,這就是
    Drift 禁止這樣做的原因。當然,它id IN ? OR title = ?會按預期工作。

定義表

在.drift文件中,您可以使用CREATE TABLE語句定義表,就像在 SQL 中編寫一樣。

支持的列類型

就像 sqlite 本身一樣,我們使用此算法 根據聲明的類型名稱來確定列類型。

此外,類型名為BOOLEAN或DATETIME的 列,其 Dart 對應類型為bool或DateTime。布爾值存儲為INTEGER(0或1)。日期時間存儲為 unix 時間戳(INTEGER)或 ISO-8601 時間戳(TEXT),具體取決于可配置的構建選項。對于在 Dart 中應表示為 的整數BigInt(即,為了在編譯為 JS 時更好地兼容大數),請使用 類型定義列INT64。

ENUM()Dart 枚舉可以通過使用引用 Dart 枚舉類的類型自動按其索引進行存儲:

enum Status {none,running,stopped,paused
}import 'status.dart';CREATE TABLE tasks (id INTEGER NOT NULL PRIMARY KEY,status ENUM(Status)
);

有關存儲枚舉的更多信息,請參閱類型轉換器頁面。除了使用按索引映射枚舉的整數之外,您還可以按名稱存儲它們。為此,請使用ENUMNAME(…)而不是ENUM(…)。

有關所有支持類型的詳細信息,以及如何在日期時間模式之間切換的信息,請參閱本節。

表達式中還支持其他特定于漂移的類型(BOOLEAN、和) DATETIME, 這對于視圖很有幫助:ENUMENUMNAMECAST

CREATE VIEW with_next_status ASSELECT id, CAST(status + 1 AS ENUM(Status)) AS statusFROM tasksWHERE status < 3;

漂移特有的功能

為了支持 Drift 的 dart_api,CREATE TABLEDrift 文件中的語句可以使用 Dart 特有功能的特殊語法。當然,Drift 會CREATE TABLE 在運行語句之前刪除這些特殊語法。

  • 您可以通過附加到語句來為表或定義的查詢定義自定義行類。WITH YourDartClassCREATE TABLE
  • 或者,您可以使用AS DesiredRowClassName來更改由漂移生成的行類的名稱。
  • 自定義行類和自定義表名也適用于視圖,例如 CREATE VIEW my_view AS DartName AS SELECT …;。
  • 在列定義中,MAPPED BY可用于將轉換器應用于 該列。
  • 類似地,JSON KEY可以使用約束來定義在將該表的一行序列化為 JSON 時將使用的鍵漂移。
  • 最后,AS getterName可以用作列約束來覆蓋 Dart 中該列的生成名稱。當 SQL
    中該列的名稱所啟發的默認列名與生成的表類的其他成員沖突時,此功能非常有用。

導入

您可以將導入語句放在文件頂部drift:

import 'tables.drift'; -- single quotes are required for imports

所有可從其他文件訪問的表也將在當前文件及其數據庫中可見includes。如果您想對另一個漂移文件中定義的表聲明查詢,則還需要導入該文件以使這些表可見。請注意,漂移文件中的導入始終具有傳遞性,因此在上面的示例中,您也將擁有所有在可用文件中聲明的導入。漂移文件other.drift沒有機制。export

您也可以將 Dart 文件導入到漂移文件中,這樣,所有通過 Dart 表聲明的表都可以在查詢中使用。我們支持相對導入和package:您熟悉的 Dart 導入。

嵌套結果

許多查詢通常使用 SELECT table.*以下語法來獲取某個表的所有列。當應用于來自連接的多個表時,這種方法可能會變得有點繁瑣,如下例所示:

CREATE TABLE coordinates (id INTEGER NOT NULL PRIMARY KEY,lat REAL NOT NULL,long REAL NOT NULL
);CREATE TABLE saved_routes (id INTEGER NOT NULL PRIMARY KEY,name TEXT NOT NULL,"from" INTEGER NOT NULL REFERENCES coordinates (id),"to" INTEGER NOT NULL REFERENCES coordinates (id)
);routesWithPoints: SELECT r.id, r.name, f.*, t.* FROM saved_routes rINNER JOIN coordinates f ON f.id = r."from"INNER JOIN coordinates t ON t.id = r."to";

為了匹配返回的列名,同時避免 Dart 中的名稱沖突,drift 會生成一個包含、 、id、name和 一個字段的類。當然,這根本沒用——這又是從 還是 來的? 讓我們重寫查詢,這次使用嵌套結果:id1latlonglat1long1lat1fromto

routesWithNestedPoints: SELECT r.id, r.name, f.** AS "from", t.** AS "to" FROM saved_routes rINNER JOIN coordinates f ON f.id = r."from"INNER JOIN coordinates t ON t.id = r."to";

如您所見,我們只需使用特定于漂移的 table.**語法即可嵌套結果。對于此查詢,漂移將生成以下類:

class RoutesWithNestedPointsResult {final int id;final String name;final Point from;final Point to;// ...
}

太棒了!這個類比之前的平面結果類更符合我們的意圖。

這些嵌套結果列 ( **) 只能出現在頂級 select 語句中,復合 select 語句或子查詢尚不支持它們。但是,它們可以引用 SQL 中已連接到 select 語句的任何結果集,包括子查詢和表值函數。

你可能想知道它的內部工作原理,因為它不是有效的 SQL。在構建時,drift 的生成器會將其轉換為引用表的所有列的列表。例如,如果我們有一個foo包含id INT 和bar TEXT列的表。那么,SELECT foo.** FROM foo可能會被解析為 SELECT foo.id AS “nested_0.id”, foo.bar AS “nested_0”.bar FROM foo。

LIST子查詢

從 Drift 版本開始1.4.0,子查詢也可以作為完整列表進行選擇。只需將子查詢放在LIST()函數中,即可將子查詢的所有行包含在結果集中。

重新使用嵌套結果示例中介紹的coordinates和表,我們添加一個存儲沿路線坐標的新表:saved_routes

CREATE TABLE route_points (route INTEGER NOT NULL REFERENCES saved_routes (id),point INTEGER NOT NULL REFERENCES coordinates (id),index_on_route INTEGER,PRIMARY KEY (route, point)
);

現在,假設我們想要查詢一條包含沿途所有點信息的路線。雖然這需要兩條 SQL 語句,但我們可以將其寫成一條漂移查詢,然后自動拆分成兩條語句:

routeWithPoints: SELECTroute.**,LIST(SELECT coordinates.* FROM route_pointsINNER JOIN coordinates ON id = pointWHERE route = route.idORDER BY index_on_route) AS pointsFROM saved_routes route;

這將生成一個結果集,其中包含一個SavedRoute route字段以及 List points沿途所有點的列表。

在內部,Drift 會將此查詢拆分為兩個單獨的查詢:- 外部SELECT route.** FROM saved_routes routeSQL 查詢 -SELECT coordinates.* FROM route_points … ORDER BY index_on_route為外部查詢中的每一行運行一個單獨的查詢。route.id內部查詢中的引用將被替換為一個變量,Drift 會將該變量綁定到外部查詢中的實際值。

雖然LIST()子查詢是一個非常強大的功能,但當外部查詢有很多行時(因為內部查詢針對每個外部行執行),它們的成本可能很高。

Dart 互操作

Drift 文件與 Drift 現有的 dart_api 完美協同工作:

  • 您可以為漂移文件中聲明的表編寫 Dart 查詢:
Future<void> insert(TodosCompanion companion) async {await into(todos).insert(companion);
}
  • 通過將 Dart 文件導入到漂移文件中,您可以為 Dart 中聲明的表編寫 SQL 查詢。
  • 生成的查詢方法可用于事務,它們與自動更新查詢等一起工作。

如果您在生成的 Dart 類中使用fromJson和toJson方法,并且需要更改 json 中列的名稱,則可以使用JSON KEY列約束來執行此操作,因此id INT NOT NULL JSON KEY userId 會在 json 中生成序列化為“userId”的列。

SQL 中的 Dart 組件

你可以使用“Dart 模板”來充分利用 SQL 和 Dart 語言的優勢。Dart 模板是一種 Dart 表達式,可以在運行時內聯到查詢語句中。要使用它們,請在查詢語句中聲明一個 $ 變量:

filterTodos: SELECT * FROM todos WHERE $predicate;
Drift 將生成一個Selectable帶有predicate參數的方法,可用于在運行時構建動態過濾器:

Stream<List<Todo>> watchInCategory(int category) {return filterTodos((todos) => todos.category.equals(category)).watch();
}

這讓你可以編寫單個 SQL 查詢并在運行時動態應用謂詞!此功能適用于

  • 表達式,正如您在上面的示例中看到的那樣
  • 單一排序項:SELECT * FROM todos ORDER BY $term, id ASC
    將生成一個采用的方法OrderingTerm。
  • 整個 order-by 子句:SELECT * FROM todos ORDER BY $order
  • 限制條款:SELECT * FROM todos LIMIT $limit
  • 插入語句的插入項:INSERT INTO todos $row生成一個Insertable row 參數

當用作表達式時,您還可以在查詢中提供默認值:

getTodos ($predicate = TRUE): SELECT * FROM todos WHERE $predicate;

這將使該參數在 Dart 中成為可選參數。如果未明確設置,predicate它將使用默認的 SQL 值(此處為)。TRUE

類型轉換器

您可以在漂移文件中導入并使用用 Dart 編寫的類型轉換器 。導入 Dart 文件需要使用常規import語句。要在列定義上應用類型轉換器,可以使用MAPPED BY列約束:

CREATE TABLE users (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,name TEXT,preferences TEXT MAPPED BY `const PreferenceConverter()`
);

引用帶有類型轉換器的表列的查詢或視圖也將繼承該轉換器。此外,查詢和視圖都可以為特定列指定類型轉換器:

CREATE VIEW my_view AS SELECT 'foo' MAPPED BY `const PreferenceConverter()`SELECTid,json_extract(preferences, '$.settings') MAPPED BY `const PreferenceConverter()`
FROM users;

使用類型轉換器時,我們推薦使用apply_converters_on_variables build 選項。這也會將轉換器從 Dart 應用于 SQL,例如,如果用于變量:SELECT * FROM users WHERE preferences = ?。使用該選項,變量將被推斷為 ,Preferences而不是String。

Drift 文件還對隱式枚舉轉換器有特殊支持:

import 'status.dart';CREATE TABLE tasks (id INTEGER NOT NULL PRIMARY KEY,status ENUM(Status)
);

當然,關于自動枚舉轉換器的警告也適用于漂移文件。

現有的行類

您可以使用自定義行類,而不必讓 Drift 為您生成一個。例如,假設您有一個 Dart 類定義為

class User {final int id;final String name;User(this.id, this.name);
}

然后,您可以指示漂移將該類用作行類,如下所示:

import 'row_class.dart'; --import for where the row class is definedCREATE TABLE users (id INTEGER NOT NULL PRIMARY KEY,name TEXT NOT NULL
) WITH User; -- This tells drift to use the existing Dart class

當使用在其他 Dart 文件中定義的自定義行類時,您還需要將該文件導入到定義數據庫的文件中。有關此功能的更多常規信息,請查看此頁面。

自定義行類可應用于文件SELECT中定義的查詢.drift。要使用自定義行類,WITH可在查詢名稱后添加語法。

例如,假設我們row_class.dart通過添加另一個類來擴展現有的 Dart 代碼:

class UserWithFriends {final User user;final List<User> friends;UserWithFriends(this.user, {this.friends = const []});
}

現在,我們可以使用新類為其行添加相應的查詢:

-- table to demonstrate a more complex select query below.
-- also, remember to add the import for `UserWithFriends` to your drift file.
CREATE TABLE friends (user_a INTEGER NOT NULL REFERENCES users(id),user_b INTEGER NOT NULL REFERENCES users(id),PRIMARY KEY (user_a, user_b)
);allFriendsOf WITH UserWithFriends: SELECT users.** AS user, LIST(SELECT * FROM users a INNER JOIN friends ON user_a = a.id WHERE user_b = users.id OR user_a = users.id
) AS friends FROM users WHERE id = :id;

該WITH UserWithFriends語法將使 Drift 考慮UserWithFriends類。對于構造函數中的每個字段,Drift 都會檢查查詢中的列,并驗證其是否具有兼容類型。然后,Drift 會在內部生成查詢代碼,將行映射到該類的實例 UserWithFriends。

有關使用自定義行類進行查詢的更完整概述,請參閱 查詢部分。

Dart 文檔注釋

漂移文件中列前添加的注釋將作為 Dart 文檔注釋添加到生成的行類中:

CREATE TABLE friends (-- The user original sending the friendship requestuser_a INTEGER NOT NULL REFERENCES users(id),-- The user accepting the friendship request from [userA].user_b INTEGER NOT NULL REFERENCES users(id),PRIMARY KEY (user_a, user_b)
);

漂移生成的類中生成的userA和字段將會有這些注釋作為文檔注釋。userBFriend

結果類名稱

對于大多數查詢,漂移會生成一個新的類來保存結果。該類以查詢名稱加上后綴命名Result,例如,一個myQuery查詢會得到一個MyQueryResult類。

您可以像這樣更改結果類的名稱:

routesWithNestedPoints AS FullRoute: SELECT r.id, -- ...

這樣,多個查詢也可以共享一個結果類。只要它們具有相同的結果集,您就可以為它們分配相同的自定義名稱,并且漂移只會生成一個類。

對于僅選擇表中所有列的查詢,drift 不會生成新的類,而是會重用它生成的數據類。同樣,對于只有一列的查詢,drift 會直接返回該列,而不是將其包裝在結果類中。目前無法覆蓋此行為,因此,如果查詢包含匹配的表或只有一列,則您無法自定義該查詢的結果類名稱。

支持的語句

目前,.drift文件中可以出現以下語句。

  • import ‘other.drift’:將另一個文件中聲明的所有表和查詢導入到當前文件中。
  • DDL 語句:您可以將CREATE TABLE、、CREATE VIEW和CREATE INDEX語句CREATE
    TRIGGER放入漂移文件中。
  • 查詢語句:我們支持INSERT、、SELECT和UPDATE語句DELETE。

所有導入都必須位于 DDL 語句之前,并且這些語句必須位于命名查詢之前。

如果您需要另一個語句的支持,或者如果漂移拒絕您認為有效的查詢,請創建一個問題!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84023.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84023.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84023.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【排坑指南】MySQL初始化后,Nacos與微服務無法連接??

Date&#xff1a;2025/06/18 你好&#xff01; 今天&#xff0c;分享一個工作中遇到的一個 MySQL 問題。在這之前都不知道是 MySQL 的問題&#xff0c;特離譜&#xff01; 昨天和今天大多數時間都用來處理了這一個問題&#xff1a;《MySQL進行了數據庫初始化之后&#xff0c…

springboot獲取工程目錄

在springboot中使用ApplicationHome獲取工程所在目錄的時候&#xff0c;開發環境和生產運行環境輸出的目錄是不同的&#xff0c;開發環境到target/classes目錄&#xff0c;而生產運行則是需要的wzkj-server.jar所在目錄 ApplicationHome home new ApplicationHome(CollectTas…

深入ZGC并發處理的原理

大型Java應用的核心痛點之一&#xff1a;當JVM進行垃圾回收時強制程序暫停&#xff08;STW&#xff09;的代價。在要求低延遲的應用場景——高頻交易系統、實時在線服務或全球性大型平臺——中&#xff0c;這種"時空靜止"的成本可能極高。但JDK從16版本&#xff08;生…

配置DHCP服務(小白的“升級打怪”成長之路)

目錄 項目前準備 一、DHCP服務器配置&#xff08;Rocky8&#xff09; 1&#xff0c;關閉防火墻、安全上下文 2、配置網卡文件 3、安裝hdcp-server 4、配置dhcp服務 5、重啟dhcp服務 二、配置路由器 1、添加兩塊網卡并更改網卡配置文件 2、配置路由功能 3、掛載本地鏡…

云原生安全

云原生 | T Wiki 以下大部分內容參考了這篇文章 什么是云原生 云原生&#xff08;Cloud Native&#xff09; “云原生”可以從字面上拆解為“云”和“原生”兩個部分來理解&#xff1a; “云”&#xff0c;是相對于“本地”而言的。傳統應用部署在本地數據中心或物理服務器…

rapidocr v3.2.0發布

粗略更新日志 rapidocr v3.2.0 發布了。令我感到很開心的是&#xff1a;有 3 個小伙伴提了 PR&#xff0c;他們積極參與了進來。 更新要點如下&#xff1a; 采納了小伙伴qianliyx 的建議&#xff0c;按照行返回單字坐標&#xff1a;同一行的單字坐標是在同一個 tuple 中的。…

Java 操作數類型沖突: varbinary 與 real 不兼容, Java中BigDecimal與SQL Server real類型沖突解決方案

要解決Java中BigDecimal類型與SQL Server中real類型沖突導致的varbinary與real不兼容錯誤&#xff0c;請按以下步驟操作&#xff1a; 錯誤原因分析 類型映射錯誤&#xff1a;JDBC驅動嘗試將BigDecimal轉換為varbinary&#xff08;二進制類型&#xff09;&#xff0c;而非目標字…

25.多子句查詢

MySQL 中包含 GROUP BY、HAVING、ORDER BY、LIMIT 時的查詢語法規則及應用&#xff0c;核心知識總結如下&#xff1a; 1.語法順序規則 當 SELECT 語句同時包含 GROUP BY、HAVING、ORDER BY、LIMIT 時&#xff0c;執行順序為&#xff1a; GROUP BY → HAVING → ORDER BY → L…

Vue3 × DataV:三步上手炫酷數據可視化組件庫

DataV&#xff08;kjgl77/datav-vue3&#xff09;是專為“大屏可視化”場景打造的 Vue3 組件庫&#xff0c;提供邊框、裝飾、等數十個開箱即用的視覺組件。本文聚焦 “在 Vue3 項目中如何正確使用 DataV”&#xff0c;從安裝、全局注冊到常見坑點&#xff0c;帶你迅速玩轉這款酷…

本地KMS服務器激活常用命令

OpenWRT內置了KMS激活的相關服務&#xff0c;配置后需要電腦本地切換到該KMS服務。相關命令如下&#xff1a; 基本功能與定義? slmgr是Windows內置的軟件授權管理工具&#xff0c;全稱為Software License Manager。其核心功能包括產品密鑰安裝/卸載、許可證信息查詢、KMS服務器…

存貨核算:個別計價法、先進先出法、加權平均法、移動加權平均法解讀

存貨作為企業資產的重要組成部分&#xff0c;貫穿于企業運營的各個環節&#xff0c;特別是制造業&#xff0c;企業的所有運營體系都是圍繞存貨來開展的。根據會計準則&#xff0c;存貨是指企業在日常活動中持有以備出售的產成品或商品、處在生產過程中的在半成品&#xff0c;以…

Java異步編程:挑戰、實踐與未來

&#x1f4cc; 摘要 在現代高并發、高性能的系統中&#xff0c;異步編程已經成為構建響應式應用的重要手段。Java 提供了多種異步編程模型&#xff0c;從最基礎的 Future 和線程池&#xff0c;到 CompletableFuture 的鏈式調用&#xff0c;再到反應式框架如 Project Reactor 和…

哈希函數結構:從MD到海綿的進化之路

一、MD結構&#xff1a;哈希函數的經典范式 1. Merkle-Damgrd結構核心原理 #mermaid-svg-BX4ZrTendXiyIVr0 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-BX4ZrTendXiyIVr0 .error-icon{fill:#552222;}#mermaid-s…

零基礎設計模式——行為型模式 - 模板方法模式

第四部分&#xff1a;行為型模式 - 模板方法模式 (Template Method Pattern) 現在我們來學習模板方法模式。這個模式在一個方法中定義一個算法的骨架&#xff0c;而將一些步驟延遲到子類中實現。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。 核…

android通過adb push apk放置目錄/sdcard/Download/下無法安裝

本文通過對源碼進行追蹤,并且調試各種方式,得出android通過adb push apk放置目錄/sdcard/Download/下無法安裝的原因,并從兩個修改點觸發,提出如何能修復此問題的建議。 1. 現象 把apk通過adb push的方式放在/sdcard/Download文件夾下, (1)直接打開File(DocumentUI)…

Spring Boot整合PF4J:構建動態插拔的組件化架構

前言 在當今快速迭代的軟件開發領域,業務需求的頻繁變更對系統架構的靈活性和可擴展性提出了極高要求。傳統的單體應用架構在面對功能的不斷新增和修改時,往往會陷入代碼臃腫、維護困難、擴展性差的困境。組件化開發,為解決這些問題提供了新的思路,通過實現組件的動態插拔…

剃須效率低?電鑄多孔刀網設計如何提升毛發捕捉率

剃須效率低下常源于刀網對毛發的捕捉能力不足——傳統沖壓刀網因孔型單一、邊緣毛刺等問題&#xff0c;導致胡須滑脫或拉扯。而電鑄多孔刀網通過精密工藝革新&#xff0c;將毛發捕捉率提升40%以上。其核心優勢在于三維立體孔型設計與微米級精度控制&#xff0c;以下是技術解析&…

進一步了解git

1、什么是集中式&#xff1f;什么是分布式&#xff1f; SVN&#xff08;集中式&#xff09; 單一中央倉庫&#xff1a;所有代碼和歷史版本集中存儲在中央服務器&#xff0c;用戶本地僅保存當前工作副本。 強依賴網絡&#xff1a;提交、查看歷史等操作需實時連接服務器&#xf…

一、react18+項目初始化

npx create-rect-app 項目名稱配置antd design mobile // 安裝 npm install --save antd-mobile // 在文件中直接引入使用 import { Button } from antd-mobile <Button></Button>更改webpack配置 // 1.安裝必要的包 npm install craco --save-dev // 2.修改pack…

Azure 資源清單

Azure 資源清單 作用前置條件安裝PowerShell 7.0驗證 Azure資源清單安裝配置如果有舊版本&#xff0c;導致新模塊安裝不上&#xff0c;進行強制安裝 PowerShell 登錄到 Azure基本命令輸出詳細信息效果圖展示 作用 官方文檔&#xff1a;https://github.com/microsoft/ARI?tabr…