build();
+
+ @NotNull String getTableName();
+
+ /**
+ * 得到表的设定。
+ * 若未使用 {@link #setTableSettings(String)} 方法则会采用 {@link #defaultTablesSettings()} 。
+ *
+ * @return TableSettings
+ */
+ @NotNull String getTableSettings();
+
+ TableCreateBuilder setTableSettings(@NotNull String settings);
+
+ /**
+ * 设定表的标注,一般用于解释该表的作用。
+ *
+ * @param comment 表标注
+ * @return {@link TableCreateBuilder}
+ */
+ TableCreateBuilder setTableComment(@Nullable String comment);
+
+ /**
+ * 直接设定表的所有列信息
+ *
+ * @param columns 列的相关信息 (包括列设定)
+ * @return {@link TableCreateBuilder}
+ */
+ TableCreateBuilder setColumns(@NotNull String... columns);
+
+ /**
+ * 为该表添加一个列
+ *
+ * @param column 列的相关信息
+ *
如 `uuid` VARCHAR(36) NOT NULL UNIQUE KEY
+ * @return {@link TableCreateBuilder}
+ */
+ TableCreateBuilder addColumn(@NotNull String column);
+
+ /**
+ * 为该表添加一个列
+ *
+ * @param columnName 列名
+ * @param settings 列的设定
+ *
如 VARCHAR(36) NOT NULL UNIQUE KEY
+ * @return {@link TableCreateBuilder}
+ */
+ default TableCreateBuilder addColumn(@NotNull String columnName, @NotNull String settings) {
+ Objects.requireNonNull(columnName, "columnName could not be null");
+ return addColumn(withBackQuote(columnName) + " " + settings);
+ }
+
+ /**
+ * 为该表添加一个列
+ *
+ * @param columnName 列名
+ * @param settings 列的设定
+ *
如 VARCHAR(36) NOT NULL UNIQUE KEY
+ * @param comments 列的注解,用于解释该列数据的作用
+ * @return {@link TableCreateBuilder}
+ */
+ default TableCreateBuilder addColumn(@NotNull String columnName, @NotNull String settings, @NotNull String comments) {
+ return addColumn(columnName, settings + " COMMENT " + withQuote(comments));
+ }
+
+ /**
+ * 为该表添加一个自增列
+ *
自增列强制要求为数字类型,非空,且为UNIQUE。
+ *
注意:一个表只允许有一个自增列!
+ *
+ * @param columnName 列名
+ * @param numberType 数字类型,若省缺则为 {@link NumberType#INT}
+ * @param asPrimaryKey 是否为主键,若为false则设定为唯一键
+ * @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true)
+ * @return {@link TableCreateBuilder}
+ */
+ TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, @Nullable NumberType numberType,
+ boolean asPrimaryKey, boolean unsigned);
+
+ /**
+ * 为该表添加一个INT类型的自增主键列
+ *
自增列强制要求为数字类型,非空,且为UNIQUE。
+ *
注意:一个表只允许有一个自增列!
+ *
+ * @param columnName 列名
+ * @param asPrimaryKey 是否为主键,若为false则设定为唯一键
+ * @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true)
+ * @return {@link TableCreateBuilder}
+ */
+ default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName,
+ boolean asPrimaryKey, boolean unsigned) {
+ return addAutoIncrementColumn(columnName, NumberType.INT, asPrimaryKey, unsigned);
+ }
+
+
+ /**
+ * 为该表添加一个INT类型的自增列
+ *
自增列强制要求为数字类型,非空,且为UNIQUE。
+ *
注意:一个表只允许有一个自增列!
+ *
+ * @param columnName 列名
+ * @param asPrimaryKey 是否为主键,若为false则设定为唯一键
+ * @return {@link TableCreateBuilder}
+ */
+ default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, boolean asPrimaryKey) {
+ return addAutoIncrementColumn(columnName, asPrimaryKey, true);
+ }
+
+ /**
+ * 为该表添加一个INT类型的自增主键列
+ *
自增列强制要求为数字类型,非空,且为UNIQUE。
+ *
注意:一个表只允许有一个自增列!
+ *
+ * @param columnName 列名
+ * @return {@link TableCreateBuilder}
+ */
+ default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName) {
+ return addAutoIncrementColumn(columnName, true);
+ }
+
+ /**
+ * 设定表中的某列为索引或键。
+ *
+ *
创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。
+ *
虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE 和DELETE。
+ *
因此,请合理的设计索引。
+ *
+ * @param type 索引类型
+ * @param columnName 索引包含的列
+ * @return {@link TableCreateBuilder}
+ */
+ default TableCreateBuilder setIndex(@NotNull String columnName,
+ @NotNull IndexType type) {
+ return setIndex(type, null, columnName);
+ }
+
+ /**
+ * 设定表中的某列为索引或键。
+ *
+ *
创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。
+ *
虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE 和DELETE。
+ *
因此,请合理的设计索引。
+ *
+ * @param type 索引类型
+ * @param indexName 索引名称,缺省时将根据第一个索引列赋一个名称
+ * @param columnName 索引包含的列
+ * @param moreColumns 联合索引需要包含的列
+ * @return {@link TableCreateBuilder}
+ */
+ TableCreateBuilder setIndex(@NotNull IndexType type, @Nullable String indexName,
+ @NotNull String columnName, @NotNull String... moreColumns);
+
+
+ /**
+ * 以本表位从表,为表中某列设定自参照外键(即自参照完整性)。
+ *
+ *
外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
+ *
外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
+ *
主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
+ *
+ * @param tableColumn 本表中的列
+ * @param foreignColumn 外键关联表中对应的关联列,必须为目标表的主键,即 {@link IndexType#PRIMARY_KEY}
+ * @return {@link TableCreateBuilder}
+ */
+ default TableCreateBuilder addForeignKey(@NotNull String tableColumn, @NotNull String foreignColumn) {
+ return addForeignKey(tableColumn, getTableName(), foreignColumn);
+ }
+
+ /**
+ * 以本表位从表,为表中某列设定外键。
+ *
+ *
外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
+ *
外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
+ *
主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
+ *
+ * @param tableColumn 本表中的列
+ * @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。
+ * @param foreignColumn 外键关联主表中对应的关联列,须满足
+ *
1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY}
+ *
2. 数据类型必须和所要建立主键的列的数据类型相同。
+ * @return {@link TableCreateBuilder}
+ */
+ default TableCreateBuilder addForeignKey(@NotNull String tableColumn,
+ @NotNull String foreignTable, @NotNull String foreignColumn) {
+ return addForeignKey(tableColumn, null, foreignTable, foreignColumn);
+ }
+
+ /**
+ * 以本表位从表,为表中某列设定外键。
+ *
+ *
外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
+ *
外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
+ *
主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
+ *
+ * @param tableColumn 本表中的列
+ * @param constraintName 约束名,缺省时将使用参数自动生成,如 fk_[tableColumn]_[foreignTable]
+ * @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。
+ * @param foreignColumn 外键关联主表中对应的关联列,须满足
+ *
1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY}
+ *
2. 数据类型必须和所要建立主键的列的数据类型相同。
+ * @return {@link TableCreateBuilder}
+ */
+ default TableCreateBuilder addForeignKey(@NotNull String tableColumn, @Nullable String constraintName,
+ @NotNull String foreignTable, @NotNull String foreignColumn) {
+ return addForeignKey(tableColumn, constraintName, foreignTable, foreignColumn, null, null);
+ }
+
+ /**
+ * 以本表位从表,为表中某列设定外键。
+ *
+ *
外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
+ *
外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
+ *
主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
+ *
+ * @param tableColumn 本表中的列
+ * @param constraintName 约束名,缺省时将使用参数自动生成,如 fk_[tableColumn]_[foreignTable]
+ * @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。
+ * @param foreignColumn 外键关联主表中对应的关联列,须满足
+ *
1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY}
+ *
2. 数据类型必须和所要建立主键的列的数据类型相同。
+ * @param updateRule 在外键被更新时采用的规则,缺省时默认为{@link ForeignKeyRule#RESTRICT}
+ * @param deleteRule 在外键被删除时采用的规则,缺省时默认为{@link ForeignKeyRule#RESTRICT}
+ * @return {@link TableCreateBuilder}
+ */
+ TableCreateBuilder addForeignKey(@NotNull String tableColumn, @Nullable String constraintName,
+ @NotNull String foreignTable, @NotNull String foreignColumn,
+ @Nullable ForeignKeyRule updateRule, @Nullable ForeignKeyRule deleteRule);
+
+ default String defaultTablesSettings() {
+ return "ENGINE=InnoDB DEFAULT CHARSET=utf8";
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/builder/TableMetadataBuilder.java b/src/main/java/com/io/yutian/aulib/sql/api/builder/TableMetadataBuilder.java
new file mode 100644
index 0000000..3aec6c1
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/builder/TableMetadataBuilder.java
@@ -0,0 +1,56 @@
+package com.io.yutian.aulib.sql.api.builder;
+
+import com.io.yutian.aulib.sql.api.SQLBuilder;
+import com.io.yutian.aulib.sql.api.function.SQLFunction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.Unmodifiable;
+
+import java.sql.ResultSet;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+public interface TableMetadataBuilder extends SQLBuilder {
+
+ /**
+ * @return 本表是否存在
+ */
+ CompletableFuture validateExist();
+
+ /**
+ * 对表内的数据列元数据进行读取
+ *
+ * @param columnPattern 列的名称匹配表达式, 为空则匹配所有列
+ * @param reader 读取的方法
+ * @param 结果类型
+ * @return 读取结果
+ */
+ CompletableFuture fetchColumns(@Nullable String columnPattern,
+ @NotNull SQLFunction reader);
+
+ /**
+ * @param columnPattern 需要判断的列名表达式
+ * @return 对应列是否存在
+ */
+ CompletableFuture isColumnExists(@NotNull String columnPattern);
+
+ /**
+ * 列出所有表内的全部列。
+ *
+ * @return 表内全部数据列的列名
+ */
+ default CompletableFuture<@Unmodifiable Set> listColumns() {
+ return listColumns(null);
+ }
+
+ /**
+ * 列出所有满足表达式的列。
+ *
+ * @param columnPattern 列名表达式,为空则列出全部
+ * @return 所有满足表达式的列名
+ */
+ CompletableFuture<@Unmodifiable Set> listColumns(@Nullable String columnPattern);
+
+ // More coming soon.
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/builder/TableQueryBuilder.java b/src/main/java/com/io/yutian/aulib/sql/api/builder/TableQueryBuilder.java
new file mode 100644
index 0000000..6935825
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/builder/TableQueryBuilder.java
@@ -0,0 +1,37 @@
+package com.io.yutian.aulib.sql.api.builder;
+
+import com.io.yutian.aulib.sql.api.action.query.PreparedQueryAction;
+import org.jetbrains.annotations.NotNull;
+
+public interface TableQueryBuilder extends ConditionalBuilder {
+
+ @NotNull String getTableName();
+
+ /**
+ * 选定用于查询的列名
+ *
+ * @param columnNames 列名
+ * @return {@link TableQueryBuilder}
+ */
+ TableQueryBuilder selectColumns(@NotNull String... columnNames);
+
+ /**
+ * 对结果进行排序
+ *
+ * @param columnName 排序使用的列名
+ * @param asc 是否为正序排序 (为false则倒序排序)
+ * @return {@link TableQueryBuilder}
+ */
+ TableQueryBuilder orderBy(@NotNull String columnName, boolean asc);
+
+ /**
+ * 限制查询条数,用于分页查询。
+ *
+ * @param start 开始数
+ * @param end 结束条数
+ * @return {@link TableQueryBuilder}
+ * @since 0.2.6
+ */
+ TableQueryBuilder setPageLimit(int start, int end);
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/builder/UpdateBuilder.java b/src/main/java/com/io/yutian/aulib/sql/api/builder/UpdateBuilder.java
new file mode 100644
index 0000000..ed68991
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/builder/UpdateBuilder.java
@@ -0,0 +1,56 @@
+package com.io.yutian.aulib.sql.api.builder;
+
+import com.io.yutian.aulib.sql.api.SQLAction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.LinkedHashMap;
+
+public interface UpdateBuilder extends ConditionalBuilder> {
+
+ String getTableName();
+
+ /**
+ * 添加一条需要更新的字段名与值
+ *
+ * @param columnName 字段名
+ * @param columnValue 字段名对应的值
+ * @return {@link UpdateBuilder}
+ * @since 0.3.7
+ */
+ UpdateBuilder addColumnValue(@NotNull String columnName, @Nullable Object columnValue);
+
+ /**
+ * 设定更新的全部字段值 (此操作会覆盖之前的设定)
+ * 此操作会覆盖之前的设定
+ *
+ * @param columnData 字段名和值的键值对
+ * @return {@link UpdateBuilder}
+ */
+ UpdateBuilder setColumnValues(LinkedHashMap<@NotNull String, @Nullable Object> columnData);
+
+ /**
+ * 设定更新的全部字段值 (此操作会覆盖之前的设定)
+ *
此操作会覆盖之前的设定
+ *
+ * @param columnNames 字段名
+ * @param columnValues 字段名对应的值
+ * @return {@link UpdateBuilder}
+ */
+ UpdateBuilder setColumnValues(@NotNull String[] columnNames, @Nullable Object[] columnValues);
+
+ /**
+ * 设定更新的全部字段值 (此操作会覆盖之前的设定)
+ *
如需同时更新多条字段,请使用 {@link #setColumnValues(String[], Object[])} 或 {@link #setColumnValues(LinkedHashMap)}
+ *
也可以使用 {@link #addColumnValue(String, Object)} 一条条的添加字段
+ *
+ * @param columnName 字段名
+ * @param columnValue 字段名对应的值
+ * @return {@link UpdateBuilder}
+ */
+ default UpdateBuilder setColumnValues(@NotNull String columnName, @Nullable Object columnValue) {
+ return setColumnValues(new String[]{columnName}, new Object[]{columnValue});
+ }
+
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/builder/UpsertBuilder.java b/src/main/java/com/io/yutian/aulib/sql/api/builder/UpsertBuilder.java
new file mode 100644
index 0000000..b9d64a3
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/builder/UpsertBuilder.java
@@ -0,0 +1,17 @@
+package com.io.yutian.aulib.sql.api.builder;
+
+/**
+ * 存在则更新,不存在则插入。
+ *
+ * @see ReplaceBuilder
+ */
+@Deprecated
+public interface UpsertBuilder {
+
+ String getTableName();
+
+ default UpsertBuilder setColumnNames(String[] columnNames, String updateColumn) {
+ throw new UnsupportedOperationException("Please use REPLACE .");
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/enums/ForeignKeyRule.java b/src/main/java/com/io/yutian/aulib/sql/api/enums/ForeignKeyRule.java
new file mode 100644
index 0000000..8efef25
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/enums/ForeignKeyRule.java
@@ -0,0 +1,41 @@
+package com.io.yutian.aulib.sql.api.enums;
+
+public enum ForeignKeyRule {
+
+ /**
+ * 啥也不做
+ *
注意: 在Mysql中该选项实际上等同于采用默认的 {@link #RESTRICT} 设定!
+ */
+ NO_ACTION("NO ACTION"),
+
+ /**
+ * 拒绝删除要求,直到使用删除键值的辅助表被手工删除,并且没有参照时(这是默认设置,也是最安全的设置)
+ */
+ RESTRICT("RESTRICT"),
+
+ /**
+ * 修改包含与已删除键值有参照关系的所有记录,使用NULL值替换(只能用于已标记为NOT NULL的字段)
+ */
+ SET_NULL("SET NULL"),
+
+ /**
+ * 修改包含与已删除键值有参照关系的所有记录,使用默认值替换(只能用于设定了DEFAULT的字段)
+ */
+ SET_DEFAULT("SET DEFAULT"),
+
+ /**
+ * 级联删除,删除包含与已删除键值有参照关系的所有记录
+ */
+ CASCADE("CASCADE");
+
+ final String ruleName;
+
+ ForeignKeyRule(String ruleName) {
+ this.ruleName = ruleName;
+ }
+
+ public String getRuleName() {
+ return ruleName;
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/enums/IndexType.java b/src/main/java/com/io/yutian/aulib/sql/api/enums/IndexType.java
new file mode 100644
index 0000000..5da665d
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/enums/IndexType.java
@@ -0,0 +1,41 @@
+package com.io.yutian.aulib.sql.api.enums;
+
+public enum IndexType {
+
+
+ /**
+ * 普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。
+ *
因此,应该只为那些最经常出现在查询条件(WHERE column=)或排序条件(ORDER BY column)中的数据列创建索引。
+ *
只要有可能,就应该选择一个数据最整齐、最紧凑的数据列(如一个整数类型的数据列)来创建索引。
+ */
+ INDEX("INDEX"),
+
+
+ /**
+ * 唯一索引 是在表上一个或者多个字段组合建立的索引,这个或者这些字段的值组合起来在表中不可以重复,用于保证数据的唯一性。
+ */
+ UNIQUE_KEY("UNIQUE KEY"),
+
+ /**
+ * 主键索引 是唯一索引的特定类型。表中创建主键时自动创建的索引 。一个表只能建立一个主索引。
+ */
+ PRIMARY_KEY("PRIMARY KEY"),
+
+ /**
+ * 全文索引 主要用来查找文本中的关键字,而不是直接与索引中的值相比较。
+ *
请搭配 MATCH 等语句使用,而不是使用 WHERE - LIKE 。
+ *
全文索引只可用于 CHAR、 VARCHAR 与 TEXT 系列类型。
+ */
+ FULLTEXT_INDEX("FULLTEXT");
+
+
+ final String name;
+
+ IndexType(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/enums/NumberType.java b/src/main/java/com/io/yutian/aulib/sql/api/enums/NumberType.java
new file mode 100644
index 0000000..88e450d
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/enums/NumberType.java
@@ -0,0 +1,11 @@
+package com.io.yutian.aulib.sql.api.enums;
+
+public enum NumberType {
+
+ TINYINT,
+ SMALLINT,
+ MEDIUMINT,
+ INT,
+ BIGINT
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/function/SQLBiFunction.java b/src/main/java/com/io/yutian/aulib/sql/api/function/SQLBiFunction.java
new file mode 100644
index 0000000..48fdb2f
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/function/SQLBiFunction.java
@@ -0,0 +1,24 @@
+package com.io.yutian.aulib.sql.api.function;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.sql.SQLException;
+import java.util.Objects;
+
+@FunctionalInterface
+public interface SQLBiFunction {
+
+ @Nullable
+ R apply(@NotNull T t, @NotNull U u) throws SQLException;
+
+ default SQLBiFunction then(@NotNull SQLFunction super R, ? extends V> after) {
+ Objects.requireNonNull(after);
+ return (T t, U u) -> {
+ R r = apply(t, u);
+ if (r == null) return null;
+ else return after.apply(r);
+ };
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/function/SQLDebugHandler.java b/src/main/java/com/io/yutian/aulib/sql/api/function/SQLDebugHandler.java
new file mode 100644
index 0000000..ef52996
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/function/SQLDebugHandler.java
@@ -0,0 +1,100 @@
+package com.io.yutian.aulib.sql.api.function;
+
+import com.io.yutian.aulib.sql.api.SQLAction;
+import com.io.yutian.aulib.sql.api.SQLQuery;
+import com.io.yutian.aulib.sql.api.action.PreparedSQLUpdateAction;
+import com.io.yutian.aulib.sql.api.action.PreparedSQLUpdateBatchAction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 异常处理器。
+ *
在使用 {@link SQLAction#execute(SQLExceptionHandler)} 等相关方法时,
+ * 如果发生异常,则会调用错误处理器进行错误内容的输出提示。
+ */
+
+public interface SQLDebugHandler {
+ /**
+ * 该方法将在 {@link SQLAction#execute()} 执行前调用。
+ *
+ * @param action {@link SQLAction} 对象
+ * @param params 执行传入的参数列表。
+ * 实际上,仅有 {@link PreparedSQLUpdateAction} 和 {@link PreparedSQLUpdateBatchAction} 才会有传入参数。
+ */
+ void beforeExecute(@NotNull SQLAction> action, @NotNull List<@Nullable Object[]> params);
+
+ /**
+ * 该方法将在 {@link SQLQuery#close()} 执行后调用。
+ *
+ * @param query {@link SQLQuery} 对象
+ * @param executeNanoTime 该次查询开始执行的时间 (单位:纳秒)
+ * @param closeNanoTime 该次查询彻底关闭的时间 (单位:纳秒)
+ */
+ void afterQuery(@NotNull SQLQuery query, long executeNanoTime, long closeNanoTime);
+
+ default String parseParams(@Nullable Object[] params) {
+ if (params == null) return "<#NULL>";
+ else if (params.length == 0) return "<#EMPTY>";
+
+ List paramsString = new ArrayList<>();
+ for (Object param : params) {
+ if (param == null) paramsString.add("NULL");
+ else paramsString.add(param.toString());
+ }
+ return String.join(", ", paramsString);
+ }
+
+ @SuppressWarnings("DuplicatedCode")
+ static SQLDebugHandler defaultHandler(Logger logger) {
+ return new SQLDebugHandler() {
+
+ @Override
+ public void beforeExecute(@NotNull SQLAction> action, @NotNull List<@Nullable Object[]> params) {
+ logger.info("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
+ logger.info("┣# ActionUUID: {}", action.getActionUUID());
+ logger.info("┣# ActionType: {}", action.getClass().getSimpleName());
+ if (action.getSQLContents().size() == 1) {
+ logger.info("┣# SQLContent: {}", action.getSQLContents().get(0));
+ } else {
+ logger.info("┣# SQLContents: ");
+ int i = 0;
+ for (String sqlContent : action.getSQLContents()) {
+ logger.info("┃ - [{}] {}", ++i, sqlContent);
+ }
+ }
+ if (params.size() == 1) {
+ Object[] param = params.get(0);
+ if (param != null) {
+ logger.info("┣# SQLParam: {}", parseParams(param));
+ }
+ } else if (params.size() > 1) {
+ logger.info("┣# SQLParams: ");
+ int i = 0;
+ for (Object[] param : params) {
+ logger.info("┃ - [{}] {}", ++i, parseParams(param));
+ }
+ }
+ logger.info("┣# CreateTime: {}", action.getCreateTime(TimeUnit.MILLISECONDS));
+ logger.info("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
+ }
+
+ @Override
+ public void afterQuery(@NotNull SQLQuery query, long executeNanoTime, long closeNanoTime) {
+ logger.info("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
+ logger.info("┣# ActionUUID: {}", query.getAction().getActionUUID());
+ logger.info("┣# SQLContent: {}", query.getSQLContent());
+ logger.info("┣# CloseTime: {} (cost {} ms)",
+ TimeUnit.NANOSECONDS.toMillis(closeNanoTime),
+ ((double) (closeNanoTime - executeNanoTime) / 1000000)
+ );
+ logger.info("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/function/SQLExceptionHandler.java b/src/main/java/com/io/yutian/aulib/sql/api/function/SQLExceptionHandler.java
new file mode 100644
index 0000000..3c7c733
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/function/SQLExceptionHandler.java
@@ -0,0 +1,46 @@
+package com.io.yutian.aulib.sql.api.function;
+
+import com.io.yutian.aulib.sql.api.SQLAction;
+import org.slf4j.Logger;
+
+import java.sql.SQLException;
+import java.util.function.BiConsumer;
+
+/**
+ * 异常处理器。
+ *
在使用 {@link SQLAction#execute(SQLExceptionHandler)} 等相关方法时,
+ * 如果发生异常,则会调用错误处理器进行错误内容的输出提示。
+ */
+@FunctionalInterface
+public interface SQLExceptionHandler extends BiConsumer> {
+
+ /**
+ * 默认的异常处理器,将详细的输出相关错误与错误来源。
+ *
+ * @param logger 用于输出错误信息的Logger。
+ * @return 输出详细信息的错误处理器。
+ */
+ static SQLExceptionHandler detailed(Logger logger) {
+ return (exception, sqlAction) -> {
+ logger.error("Error occurred while executing SQL: ");
+ int i = 1;
+ for (String content : sqlAction.getSQLContents()) {
+ logger.error(String.format("#%d {%s}", i, content));
+ i++;
+ }
+ exception.printStackTrace();
+ };
+ }
+
+ /**
+ * “安静“ 的错误处理器,发生错误什么都不做。
+ * 强烈不建议把此处理器作为默认处理器使用!
+ *
+ * @return 无输出的处理器。
+ */
+ static SQLExceptionHandler silent() {
+ return (exception, sqlAction) -> {
+ };
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/function/SQLFunction.java b/src/main/java/com/io/yutian/aulib/sql/api/function/SQLFunction.java
new file mode 100644
index 0000000..63910b9
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/function/SQLFunction.java
@@ -0,0 +1,34 @@
+package com.io.yutian.aulib.sql.api.function;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.sql.SQLException;
+import java.util.Objects;
+
+@FunctionalInterface
+public interface SQLFunction {
+
+ @Nullable
+ R apply(@NotNull T t) throws SQLException;
+
+ default SQLFunction compose(@NotNull SQLFunction super V, ? extends T> before) {
+ Objects.requireNonNull(before);
+ return (V v) -> {
+ T t = before.apply(v);
+ if (t == null) return null;
+ else return apply(t);
+ };
+ }
+
+ default SQLFunction then(@NotNull SQLFunction super R, ? extends V> after) {
+ Objects.requireNonNull(after);
+ return (T t) -> {
+ R r = apply(t);
+ if (r == null) return null;
+ else return after.apply(r);
+ };
+ }
+
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/function/SQLHandler.java b/src/main/java/com/io/yutian/aulib/sql/api/function/SQLHandler.java
new file mode 100644
index 0000000..16d2904
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/function/SQLHandler.java
@@ -0,0 +1,23 @@
+package com.io.yutian.aulib.sql.api.function;
+
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+
+import java.sql.SQLException;
+import java.util.Objects;
+
+@FunctionalInterface
+public interface SQLHandler {
+
+ void accept(@NotNull T t) throws SQLException;
+
+ @NotNull
+ @Contract(pure = true)
+ default SQLHandler andThen(@NotNull SQLHandler super T> after) {
+ Objects.requireNonNull(after);
+ return (T t) -> {
+ accept(t);
+ after.accept(t);
+ };
+ }
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/table/NamedSQLTable.java b/src/main/java/com/io/yutian/aulib/sql/api/table/NamedSQLTable.java
new file mode 100644
index 0000000..c14e935
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/table/NamedSQLTable.java
@@ -0,0 +1,50 @@
+package com.io.yutian.aulib.sql.api.table;
+
+import com.io.yutian.aulib.sql.api.SQLManager;
+import com.io.yutian.aulib.sql.api.SQLTable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.sql.SQLException;
+
+
+public abstract class NamedSQLTable implements SQLTable {
+
+ private final @NotNull String tableName;
+
+ protected @Nullable String tablePrefix;
+ protected @Nullable SQLManager manager;
+
+ /**
+ * 请调用 {@link NamedSQLTable} 下的静态方法进行对象的初始化。
+ *
+ * @param tableName 该表的名称
+ */
+ public NamedSQLTable(@NotNull String tableName) {
+ this.tableName = tableName;
+ }
+
+ public @NotNull String getTableName() {
+ return (tablePrefix != null ? tablePrefix : "") + tableName;
+ }
+
+ @Override
+ public @Nullable SQLManager getSQLManager() {
+ return this.manager;
+ }
+
+ /**
+ * 使用指定 SQLManager 进行本示例的初始化。
+ *
+ * @param sqlManager {@link SQLManager}
+ * @param tablePrefix 表名前缀
+ * @return 本表是否为首次创建
+ * @throws SQLException 出现任何错误时抛出
+ */
+ public abstract boolean create(@NotNull SQLManager sqlManager, @Nullable String tablePrefix) throws SQLException;
+
+ public boolean create(@NotNull SQLManager sqlManager) throws SQLException {
+ return create(sqlManager, null);
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/util/TimeDateUtils.java b/src/main/java/com/io/yutian/aulib/sql/api/util/TimeDateUtils.java
new file mode 100644
index 0000000..b70598f
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/util/TimeDateUtils.java
@@ -0,0 +1,108 @@
+package com.io.yutian.aulib.sql.api.util;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class TimeDateUtils {
+ public static final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ public TimeDateUtils() {
+ }
+
+ /**
+ * 得到当前时间文本。
+ *
+ * @return 时间文本 格式{@link TimeDateUtils#getFormat()}
+ */
+ public static String getCurrentTime() {
+ return getTimeString(System.currentTimeMillis());
+ }
+
+ /**
+ * 得到一个时间戳的文本
+ *
+ * @param timeMillis 时间戳
+ * @return 时间文本 格式{@link TimeDateUtils#getFormat()}
+ */
+ public static String getTimeString(long timeMillis) {
+ return getFormat().format(new Date(timeMillis));
+ }
+
+ /**
+ * 得到一个日期时间的文本
+ *
+ * @param time 日期时间
+ * @return 时间文本 格式{@link TimeDateUtils#getFormat()}
+ */
+ public static String getTimeString(Date time) {
+ return getFormat().format(time);
+ }
+
+ /**
+ * 得到一个时间文本的时间戳
+ *
+ * @param timeString 时间文本
+ * @return 时间戳 格式{@link TimeDateUtils#getFormat()}
+ */
+ public static long parseTimeMillis(String timeString) {
+ if (timeString == null) {
+ return -1L;
+ } else {
+ try {
+ return format.parse(timeString).getTime();
+ } catch (ParseException var2) {
+ return -1L;
+ }
+ }
+ }
+
+
+ /**
+ * 得到一个时间文本的对应日期实例
+ *
+ * @param timeString 时间文本
+ * @return 日期实例 格式{@link TimeDateUtils#getFormat()}
+ */
+ public static Date getTimeDate(String timeString) {
+ if (timeString == null) {
+ return null;
+ } else {
+ try {
+ return format.parse(timeString);
+ } catch (ParseException var2) {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * 将秒数转化为 DD:hh:mm:ss 格式
+ *
+ * @param allSeconds 秒数
+ * @return DD:hh:mm:ss格式文本
+ */
+ public static String toDHMSStyle(long allSeconds) {
+ long days = allSeconds / 86400L;
+ long hours = allSeconds % 86400L / 3600L;
+ long minutes = allSeconds % 3600L / 60L;
+ long seconds = allSeconds % 60L;
+ String DateTimes;
+ if (days > 0L) {
+ DateTimes = days + "天" + (hours > 0L ? hours + "小时" : "") + (minutes > 0L ? minutes + "分钟" : "") + (seconds > 0L ? seconds + "秒" : "");
+ } else if (hours > 0L) {
+ DateTimes = hours + "小时" + (minutes > 0L ? minutes + "分钟" : "") + (seconds > 0L ? seconds + "秒" : "");
+ } else if (minutes > 0L) {
+ DateTimes = minutes + "分钟" + (seconds > 0L ? seconds + "秒" : "");
+ } else {
+ DateTimes = seconds + "秒";
+ }
+
+ return DateTimes;
+ }
+
+ public static DateFormat getFormat() {
+ return format;
+ }
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/api/util/UUIDUtil.java b/src/main/java/com/io/yutian/aulib/sql/api/util/UUIDUtil.java
new file mode 100644
index 0000000..eff4c77
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/api/util/UUIDUtil.java
@@ -0,0 +1,28 @@
+package com.io.yutian.aulib.sql.api.util;
+
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class UUIDUtil {
+
+ private static final Pattern COMPILE = Pattern.compile("-", Pattern.LITERAL);
+
+ public static UUID random() {
+ return UUID.randomUUID();
+ }
+
+ public static String toString(UUID uuid, boolean withDash) {
+ if (withDash) return uuid.toString();
+ else return COMPILE.matcher(uuid.toString()).replaceAll(Matcher.quoteReplacement(""));
+ }
+
+ public static UUID toUUID(String s) {
+ if (s.length() == 36) {
+ return UUID.fromString(s);
+ } else {
+ return UUID.fromString(s.substring(0, 8) + '-' + s.substring(8, 12) + '-' + s.substring(12, 16) + '-' + s.substring(16, 20) + '-' + s.substring(20));
+ }
+ }
+
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/builder/AbstractSQLBuilder.java b/src/main/java/com/io/yutian/aulib/sql/builder/AbstractSQLBuilder.java
new file mode 100644
index 0000000..772acad
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/builder/AbstractSQLBuilder.java
@@ -0,0 +1,23 @@
+package com.io.yutian.aulib.sql.builder;
+
+import com.io.yutian.aulib.sql.api.SQLBuilder;
+import com.io.yutian.aulib.sql.manager.SQLManagerImpl;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
+
+public abstract class AbstractSQLBuilder implements SQLBuilder {
+
+ @NotNull
+ final SQLManagerImpl sqlManager;
+
+ public AbstractSQLBuilder(@NotNull SQLManagerImpl manager) {
+ Objects.requireNonNull(manager, "SQLManager must not be null");
+ this.sqlManager = manager;
+ }
+
+ @Override
+ public @NotNull SQLManagerImpl getManager() {
+ return this.sqlManager;
+ }
+}
diff --git a/src/main/java/com/io/yutian/aulib/sql/builder/impl/AbstractConditionalBuilder.java b/src/main/java/com/io/yutian/aulib/sql/builder/impl/AbstractConditionalBuilder.java
new file mode 100644
index 0000000..f331ac2
--- /dev/null
+++ b/src/main/java/com/io/yutian/aulib/sql/builder/impl/AbstractConditionalBuilder.java
@@ -0,0 +1,159 @@
+package com.io.yutian.aulib.sql.builder.impl;
+
+import com.io.yutian.aulib.sql.api.SQLAction;
+import com.io.yutian.aulib.sql.api.builder.ConditionalBuilder;
+import com.io.yutian.aulib.sql.builder.AbstractSQLBuilder;
+import com.io.yutian.aulib.sql.manager.SQLManagerImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.*;
+
+import static com.io.yutian.aulib.sql.api.SQLBuilder.withBackQuote;
+
+public abstract class AbstractConditionalBuilder, T extends SQLAction>>
+ extends AbstractSQLBuilder implements ConditionalBuilder {
+
+ ArrayList conditionSQLs = new ArrayList<>();
+ ArrayList