1
mirror of https://github.com/CarmJos/EasySQL.git synced 2026-06-04 15:28:20 +08:00

[0.3.8] 执行相关优化

- 优化部分调用,替换制表符为空格。
- 补充残缺的 Objects.requireNonNull();
- 对于SQLQuery的auto-close额外判断ResultSet、Statement与Connection是否已关闭,避免重复关闭报错。
This commit is contained in:
2022-02-21 20:38:32 +08:00
parent 2de21a4658
commit 68b5d071ae
64 changed files with 2312 additions and 2294 deletions
@@ -33,180 +33,180 @@ import java.util.logging.Logger;
*/ */
public interface SQLAction<T> { public interface SQLAction<T> {
/** /**
* 得到该Action的UUID * 得到该Action的UUID
* *
* @return UUID * @return UUID
*/ */
@NotNull UUID getActionUUID(); @NotNull UUID getActionUUID();
/** /**
* 得到短八位格式的UUID * 得到短八位格式的UUID
* *
* @return UUID(8) * @return UUID(8)
*/ */
@NotNull String getShortID(); @NotNull String getShortID();
/** /**
* 得到该Action的创建时间 * 得到该Action的创建时间
* *
* @return 创建时间 * @return 创建时间
*/ */
long getCreateTime(); long getCreateTime();
/** /**
* 得到该Action所要执行的源SQL语句 * 得到该Action所要执行的源SQL语句
* *
* @return 源SQL语句 * @return 源SQL语句
*/ */
@NotNull String getSQLContent(); @NotNull String getSQLContent();
/** /**
* 得到承载该Action的对应{@link SQLManager} * 得到承载该Action的对应{@link SQLManager}
* *
* @return {@link SQLManager} * @return {@link SQLManager}
*/ */
@NotNull SQLManager getManager(); @NotNull SQLManager getManager();
/** /**
* 执行该Action对应的SQL语句 * 执行该Action对应的SQL语句
* *
* @return 指定数据类型 * @return 指定数据类型
* @throws SQLException 当SQL操作出现问题时抛出 * @throws SQLException 当SQL操作出现问题时抛出
*/ */
@NotNull T execute() throws SQLException; @NotNull T execute() throws SQLException;
/** /**
* 执行语句并返回值 * 执行语句并返回值
* *
* @param exceptionHandler 异常处理器 默认为 {@link #defaultExceptionHandler()} * @param exceptionHandler 异常处理器 默认为 {@link #defaultExceptionHandler()}
* @return 指定类型数据 * @return 指定类型数据
*/ */
@Nullable @Nullable
default T execute(@Nullable SQLExceptionHandler exceptionHandler) { default T execute(@Nullable SQLExceptionHandler exceptionHandler) {
return execute(t -> t, exceptionHandler); return execute(t -> t, exceptionHandler);
} }
/** /**
* 执行语句并处理返回值 * 执行语句并处理返回值
* *
* @param function 处理方法 * @param function 处理方法
* @param exceptionHandler 异常处理器 默认为 {@link #defaultExceptionHandler()} * @param exceptionHandler 异常处理器 默认为 {@link #defaultExceptionHandler()}
* @param <R> 需要返回的内容 * @param <R> 需要返回的内容
* @return 指定类型数据 * @return 指定类型数据
*/ */
@Nullable @Nullable
default <R> R execute(@NotNull SQLFunction<T, R> function, default <R> R execute(@NotNull SQLFunction<T, R> function,
@Nullable SQLExceptionHandler exceptionHandler) { @Nullable SQLExceptionHandler exceptionHandler) {
return execute(function, null, exceptionHandler); return execute(function, null, exceptionHandler);
} }
/** /**
* 执行语句并处理返回值 * 执行语句并处理返回值
* *
* @param function 处理方法 * @param function 处理方法
* @param defaultResult 默认结果,若处理后的结果为null,则返回该值 * @param defaultResult 默认结果,若处理后的结果为null,则返回该值
* @param exceptionHandler 异常处理器 默认为 {@link #defaultExceptionHandler()} * @param exceptionHandler 异常处理器 默认为 {@link #defaultExceptionHandler()}
* @param <R> 需要返回的内容 * @param <R> 需要返回的内容
* @return 指定类型数据 * @return 指定类型数据
*/ */
@Nullable @Nullable
@Contract("_,!null,_ -> !null") @Contract("_,!null,_ -> !null")
default <R> R execute(@NotNull SQLFunction<T, R> function, default <R> R execute(@NotNull SQLFunction<T, R> function,
@Nullable R defaultResult, @Nullable R defaultResult,
@Nullable SQLExceptionHandler exceptionHandler) { @Nullable SQLExceptionHandler exceptionHandler) {
try { try {
return executeFunction(function, defaultResult); return executeFunction(function, defaultResult);
} catch (SQLException exception) { } catch (SQLException exception) {
handleException(exceptionHandler, exception); handleException(exceptionHandler, exception);
return null; return null;
} }
} }
/** /**
* 执行语句并处理返回值 * 执行语句并处理返回值
* *
* @param function 处理方法 * @param function 处理方法
* @param <R> 需要返回的内容 * @param <R> 需要返回的内容
* @return 指定类型数据 * @return 指定类型数据
* @throws SQLException 当SQL操作出现问题时抛出 * @throws SQLException 当SQL操作出现问题时抛出
*/ */
@Nullable @Nullable
default <R> R executeFunction(@NotNull SQLFunction<@NotNull T, R> function) throws SQLException { default <R> R executeFunction(@NotNull SQLFunction<@NotNull T, R> function) throws SQLException {
return executeFunction(function, null); return executeFunction(function, null);
} }
/** /**
* 执行语句并处理返回值 * 执行语句并处理返回值
* *
* @param function 处理方法 * @param function 处理方法
* @param defaultResult 默认结果,若处理后的结果为null,则返回该值 * @param defaultResult 默认结果,若处理后的结果为null,则返回该值
* @param <R> 需要返回的内容 * @param <R> 需要返回的内容
* @return 指定类型数据 * @return 指定类型数据
* @throws SQLException 当SQL操作出现问题时抛出 * @throws SQLException 当SQL操作出现问题时抛出
*/ */
@Nullable @Nullable
@Contract("_,!null -> !null") @Contract("_,!null -> !null")
default <R> R executeFunction(@NotNull SQLFunction<@NotNull T, R> function, default <R> R executeFunction(@NotNull SQLFunction<@NotNull T, R> function,
@Nullable R defaultResult) throws SQLException { @Nullable R defaultResult) throws SQLException {
try { try {
R result = function.apply(execute()); R result = function.apply(execute());
return result == null ? defaultResult : result; return result == null ? defaultResult : result;
} catch (SQLException exception) { } catch (SQLException exception) {
throw new SQLException(exception); throw new SQLException(exception);
} }
} }
/** /**
* 异步执行SQL语句,采用默认异常处理,无需返回值。 * 异步执行SQL语句,采用默认异常处理,无需返回值。
*/ */
default void executeAsync() { default void executeAsync() {
executeAsync(null); executeAsync(null);
} }
/** /**
* 异步执行SQL语句 * 异步执行SQL语句
* *
* @param success 成功时的操作 * @param success 成功时的操作
*/ */
default void executeAsync(@Nullable SQLHandler<T> success) { default void executeAsync(@Nullable SQLHandler<T> success) {
executeAsync(success, null); executeAsync(success, null);
} }
/** /**
* 异步执行SQL语句 * 异步执行SQL语句
* *
* @param success 成功时的操作 * @param success 成功时的操作
* @param failure 异常处理器 默认为 {@link SQLAction#defaultExceptionHandler()} * @param failure 异常处理器 默认为 {@link SQLAction#defaultExceptionHandler()}
*/ */
void executeAsync(@Nullable SQLHandler<T> success, void executeAsync(@Nullable SQLHandler<T> success,
@Nullable SQLExceptionHandler failure); @Nullable SQLExceptionHandler failure);
default void handleException(@Nullable SQLExceptionHandler handler, SQLException exception) { default void handleException(@Nullable SQLExceptionHandler handler, SQLException exception) {
if (handler == null) handler = defaultExceptionHandler(); if (handler == null) handler = defaultExceptionHandler();
handler.accept(exception, this); handler.accept(exception, this);
} }
/** /**
* 默认的异常处理器 * 默认的异常处理器
* *
* @return {@link DefaultSQLExceptionHandler#get(Logger)} * @return {@link DefaultSQLExceptionHandler#get(Logger)}
* @see DefaultSQLExceptionHandler * @see DefaultSQLExceptionHandler
*/ */
default SQLExceptionHandler defaultExceptionHandler() { default SQLExceptionHandler defaultExceptionHandler() {
return DefaultSQLExceptionHandler.get(getManager().getLogger()); return DefaultSQLExceptionHandler.get(getManager().getLogger());
} }
/** /**
* 设定通用的异常处理器。 * 设定通用的异常处理器。
* <br> 在使用 {@link #execute(SQLExceptionHandler)} 等相关方法时,若传入的处理器为null,则会采用此处理器。 * <br> 在使用 {@link #execute(SQLExceptionHandler)} 等相关方法时,若传入的处理器为null,则会采用此处理器。
* <br> 若该方法传入参数为 null,则会使用 {@link #defaultExceptionHandler()} 。 * <br> 若该方法传入参数为 null,则会使用 {@link #defaultExceptionHandler()} 。
* *
* @param handler 异常处理器 * @param handler 异常处理器
*/ */
default void setExceptionHandler(@Nullable SQLExceptionHandler handler) { default void setExceptionHandler(@Nullable SQLExceptionHandler handler) {
DefaultSQLExceptionHandler.setCustomHandler(handler); DefaultSQLExceptionHandler.setCustomHandler(handler);
} }
} }
@@ -11,22 +11,21 @@ import org.jetbrains.annotations.NotNull;
*/ */
public interface SQLBuilder { public interface SQLBuilder {
/** static @NotNull String withBackQuote(@NotNull String str) {
* 得到承载该Builder的对应{@link SQLManager} str = str.trim();
* return !str.isEmpty() && str.charAt(0) == '`' && str.charAt(str.length() - 1) == '`' ? str : "`" + str + "`";
* @return {@link SQLManager} }
*/
@NotNull SQLManager getManager();
static @NotNull String withQuote(@NotNull String str) {
str = str.trim();
return !str.isEmpty() && str.charAt(0) == '\'' && str.charAt(str.length() - 1) == '\'' ? str : "'" + str + "'";
}
static @NotNull String withBackQuote(@NotNull String str) { /**
str = str.trim(); * 得到承载该Builder的对应{@link SQLManager}
return str.startsWith("`") && str.endsWith("`") ? str : "`" + str + "`"; *
} * @return {@link SQLManager}
*/
static @NotNull String withQuote(@NotNull String str) { @NotNull SQLManager getManager();
str = str.trim();
return str.startsWith("'") && str.endsWith("'") ? str : "'" + str + "'";
}
} }
@@ -19,157 +19,157 @@ import java.util.logging.Logger;
public interface SQLManager { public interface SQLManager {
Logger getLogger(); Logger getLogger();
boolean isDebugMode(); boolean isDebugMode();
void setDebugMode(@NotNull Supplier<@NotNull Boolean> debugMode); void setDebugMode(@NotNull Supplier<@NotNull Boolean> debugMode);
default void setDebugMode(boolean enable) { default void setDebugMode(boolean enable) {
setDebugMode(() -> enable); setDebugMode(() -> enable);
} }
/** /**
* 得到连接池源 * 得到连接池源
* *
* @return DataSource * @return DataSource
*/ */
@NotNull DataSource getDataSource(); @NotNull DataSource getDataSource();
/** /**
* 得到一个数据库连接实例 * 得到一个数据库连接实例
* *
* @return Connection * @return Connection
* @throws SQLException 见 {@link DataSource#getConnection()} * @throws SQLException 见 {@link DataSource#getConnection()}
*/ */
@NotNull Connection getConnection() throws SQLException; @NotNull Connection getConnection() throws SQLException;
/** /**
* 得到正使用的查询。 * 得到正使用的查询。
* *
* @return 查询列表 * @return 查询列表
*/ */
@NotNull Map<UUID, SQLQuery> getActiveQuery(); @NotNull Map<UUID, SQLQuery> getActiveQuery();
/** /**
* 执行一条不需要返回结果的SQL语句(多用于UPDATE、REPLACE、DELETE方法) * 执行一条不需要返回结果的SQL语句(多用于UPDATE、REPLACE、DELETE方法)
* 该方法使用 Statement 实现,请注意SQL注入风险! * 该方法使用 Statement 实现,请注意SQL注入风险!
* *
* @param sql SQL语句内容 * @param sql SQL语句内容
* @return 更新的行数 * @return 更新的行数
* @see SQLUpdateAction * @see SQLUpdateAction
*/ */
@Nullable Integer executeSQL(String sql); @Nullable Integer executeSQL(String sql);
/** /**
* 执行一条不需要返回结果的预处理SQL更改(UPDATE、REPLACE、DELETE) * 执行一条不需要返回结果的预处理SQL更改(UPDATE、REPLACE、DELETE)
* *
* @param sql SQL语句内容 * @param sql SQL语句内容
* @param params SQL语句中 ? 的对应参数 * @param params SQL语句中 ? 的对应参数
* @return 更新的行数 * @return 更新的行数
* @see PreparedSQLUpdateAction * @see PreparedSQLUpdateAction
*/ */
@Nullable Integer executeSQL(String sql, Object[] params); @Nullable Integer executeSQL(String sql, Object[] params);
/** /**
* 执行多条不需要返回结果的SQL更改(UPDATE、REPLACE、DELETE) * 执行多条不需要返回结果的SQL更改(UPDATE、REPLACE、DELETE)
* *
* @param sql SQL语句内容 * @param sql SQL语句内容
* @param paramsBatch SQL语句中对应?的参数组 * @param paramsBatch SQL语句中对应?的参数组
* @return 对应参数返回的行数 * @return 对应参数返回的行数
* @see PreparedSQLUpdateBatchAction * @see PreparedSQLUpdateBatchAction
*/ */
@Nullable List<Integer> executeSQLBatch(String sql, Iterable<Object[]> paramsBatch); @Nullable List<Integer> executeSQLBatch(String sql, Iterable<Object[]> paramsBatch);
/** /**
* 执行多条不需要返回结果的SQL。 * 执行多条不需要返回结果的SQL。
* 该方法使用 Statement 实现,请注意SQL注入风险! * 该方法使用 Statement 实现,请注意SQL注入风险!
* *
* @param sql SQL语句内容 * @param sql SQL语句内容
* @param moreSQL 更多SQL语句内容 * @param moreSQL 更多SQL语句内容
* @return 对应参数返回的行数 * @return 对应参数返回的行数
* @see SQLUpdateBatchAction * @see SQLUpdateBatchAction
*/ */
@Nullable List<Integer> executeSQLBatch(@NotNull String sql, String... moreSQL); @Nullable List<Integer> executeSQLBatch(@NotNull String sql, String... moreSQL);
/** /**
* 执行多条不需要返回结果的SQL。 * 执行多条不需要返回结果的SQL。
* *
* @param sqlBatch SQL语句内容 * @param sqlBatch SQL语句内容
* @return 对应参数返回的行数 * @return 对应参数返回的行数
*/ */
@Nullable List<Integer> executeSQLBatch(@NotNull Iterable<String> sqlBatch); @Nullable List<Integer> executeSQLBatch(@NotNull Iterable<String> sqlBatch);
/** /**
* 在库中创建一个表 * 在库中创建一个表
* *
* @param tableName 表名 * @param tableName 表名
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
TableCreateBuilder createTable(@NotNull String tableName); TableCreateBuilder createTable(@NotNull String tableName);
/** /**
* 对库中的某个表执行更改 * 对库中的某个表执行更改
* *
* @param tableName 表名 * @param tableName 表名
* @return {@link TableAlterBuilder} * @return {@link TableAlterBuilder}
*/ */
TableAlterBuilder alterTable(@NotNull String tableName); TableAlterBuilder alterTable(@NotNull String tableName);
/** /**
* 新建一个查询 * 新建一个查询
* *
* @return {@link QueryBuilder} * @return {@link QueryBuilder}
*/ */
QueryBuilder createQuery(); QueryBuilder createQuery();
/** /**
* 创建一条插入操作 * 创建一条插入操作
* *
* @param tableName 目标表名 * @param tableName 目标表名
* @return {@link InsertBuilder} * @return {@link InsertBuilder}
*/ */
InsertBuilder<PreparedSQLUpdateAction> createInsert(@NotNull String tableName); InsertBuilder<PreparedSQLUpdateAction> createInsert(@NotNull String tableName);
/** /**
* 创建支持多组数据的插入操作 * 创建支持多组数据的插入操作
* *
* @param tableName 目标表名 * @param tableName 目标表名
* @return {@link InsertBuilder} * @return {@link InsertBuilder}
*/ */
InsertBuilder<PreparedSQLUpdateBatchAction> createInsertBatch(@NotNull String tableName); InsertBuilder<PreparedSQLUpdateBatchAction> createInsertBatch(@NotNull String tableName);
/** /**
* 创建一条替换操作 * 创建一条替换操作
* *
* @param tableName 目标表名 * @param tableName 目标表名
* @return {@link ReplaceBuilder} * @return {@link ReplaceBuilder}
*/ */
ReplaceBuilder<PreparedSQLUpdateAction> createReplace(@NotNull String tableName); ReplaceBuilder<PreparedSQLUpdateAction> createReplace(@NotNull String tableName);
/** /**
* 创建支持多组数据的替换操作 * 创建支持多组数据的替换操作
* *
* @param tableName 目标表名 * @param tableName 目标表名
* @return {@link ReplaceBuilder} * @return {@link ReplaceBuilder}
*/ */
ReplaceBuilder<PreparedSQLUpdateBatchAction> createReplaceBatch(@NotNull String tableName); ReplaceBuilder<PreparedSQLUpdateBatchAction> createReplaceBatch(@NotNull String tableName);
/** /**
* 创建更新操作 * 创建更新操作
* *
* @param tableName 目标表名 * @param tableName 目标表名
* @return {@link UpdateBuilder} * @return {@link UpdateBuilder}
*/ */
UpdateBuilder createUpdate(@NotNull String tableName); UpdateBuilder createUpdate(@NotNull String tableName);
/** /**
* 创建删除操作 * 创建删除操作
* *
* @param tableName 目标表名 * @param tableName 目标表名
* @return {@link DeleteBuilder} * @return {@link DeleteBuilder}
*/ */
DeleteBuilder createDelete(@NotNull String tableName); DeleteBuilder createDelete(@NotNull String tableName);
} }
@@ -9,44 +9,44 @@ import java.sql.Statement;
public interface SQLQuery extends AutoCloseable { public interface SQLQuery extends AutoCloseable {
/** /**
* 获取该查询创建的时间 * 获取该查询创建的时间
* *
* @return 创建时间 * @return 创建时间
*/ */
long getExecuteTime(); long getExecuteTime();
/** /**
* 得到承载该SQLQuery的对应{@link SQLManager} * 得到承载该SQLQuery的对应{@link SQLManager}
* *
* @return {@link SQLManager} * @return {@link SQLManager}
*/ */
SQLManager getManager(); SQLManager getManager();
/** /**
* 得到承载该SQLQuery的对应{@link QueryAction} * 得到承载该SQLQuery的对应{@link QueryAction}
* *
* @return {@link QueryAction} 或 {@link PreparedQueryAction} * @return {@link QueryAction} 或 {@link PreparedQueryAction}
*/ */
QueryAction getAction(); QueryAction getAction();
ResultSet getResultSet(); ResultSet getResultSet();
/** /**
* 得到设定的SQL语句 * 得到设定的SQL语句
* *
* @return SQL语句 * @return SQL语句
*/ */
String getSQLContent(); String getSQLContent();
/** /**
* 关闭所有内容 * 关闭所有内容
*/ */
@Override @Override
void close(); void close();
Statement getStatement(); Statement getStatement();
Connection getConnection(); Connection getConnection();
} }
@@ -6,51 +6,51 @@ import java.util.List;
public interface PreparedSQLUpdateBatchAction extends SQLAction<List<Integer>> { public interface PreparedSQLUpdateBatchAction extends SQLAction<List<Integer>> {
/** /**
* 设定多组SQL语句中所有 ? 对应的参数 * 设定多组SQL语句中所有 ? 对应的参数
* *
* @param allParams 所有参数内容 * @param allParams 所有参数内容
* @return {@link PreparedSQLUpdateBatchAction} * @return {@link PreparedSQLUpdateBatchAction}
*/ */
PreparedSQLUpdateBatchAction setAllParams(Iterable<Object[]> allParams); PreparedSQLUpdateBatchAction setAllParams(Iterable<Object[]> allParams);
/** /**
* 添加一组SQL语句中所有 ? 对应的参数 * 添加一组SQL语句中所有 ? 对应的参数
* *
* @param params 参数内容 * @param params 参数内容
* @return {@link PreparedSQLUpdateBatchAction} * @return {@link PreparedSQLUpdateBatchAction}
*/ */
PreparedSQLUpdateBatchAction addParamsBatch(Object... params); PreparedSQLUpdateBatchAction addParamsBatch(Object... params);
/** /**
* 设定自增主键的序列 * 设定自增主键的序列
* *
* @param keyColumnIndex 自增主键的序列 * @param keyColumnIndex 自增主键的序列
* <br>若该值 0,则 {@link #execute()} 返回自增主键数值 * <br>若该值 0,则 {@link #execute()} 返回自增主键数值
* <br>若该值 ≤ 0,则 {@link #execute()} 返回变更的行数 * <br>若该值 ≤ 0,则 {@link #execute()} 返回变更的行数
* @return {@link PreparedSQLUpdateBatchAction} * @return {@link PreparedSQLUpdateBatchAction}
* @see #setReturnGeneratedKeys(boolean) * @see #setReturnGeneratedKeys(boolean)
*/ */
@Deprecated @Deprecated
default PreparedSQLUpdateBatchAction setKeyIndex(int keyColumnIndex) { default PreparedSQLUpdateBatchAction setKeyIndex(int keyColumnIndex) {
return setReturnGeneratedKeys(keyColumnIndex > 0); return setReturnGeneratedKeys(keyColumnIndex > 0);
} }
/** /**
* 设定该操作返回自增键序列。 * 设定该操作返回自增键序列。
* *
* @return {@link PreparedSQLUpdateBatchAction} * @return {@link PreparedSQLUpdateBatchAction}
*/ */
default PreparedSQLUpdateBatchAction returnGeneratedKeys() { default PreparedSQLUpdateBatchAction returnGeneratedKeys() {
return setReturnGeneratedKeys(true); return setReturnGeneratedKeys(true);
} }
/** /**
* 设定该操作是否返回自增键序列。 * 设定该操作是否返回自增键序列。
* *
* @param returnGeneratedKey 是否返回自增键序列 * @param returnGeneratedKey 是否返回自增键序列
* @return {@link PreparedSQLUpdateBatchAction} * @return {@link PreparedSQLUpdateBatchAction}
*/ */
PreparedSQLUpdateBatchAction setReturnGeneratedKeys(boolean returnGeneratedKey); PreparedSQLUpdateBatchAction setReturnGeneratedKeys(boolean returnGeneratedKey);
} }
@@ -29,7 +29,7 @@ public interface SQLUpdateAction extends SQLAction<Integer> {
/** /**
* 设定该操作是否返回自增键序列。 * 设定该操作是否返回自增键序列。
*
* @param returnGeneratedKey 是否返回自增键序列 * @param returnGeneratedKey 是否返回自增键序列
* @return {@link SQLUpdateAction} * @return {@link SQLUpdateAction}
*/ */
@@ -5,21 +5,22 @@ import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
@SuppressWarnings("UnusedReturnValue")
public interface SQLUpdateBatchAction extends SQLAction<List<Integer>> { public interface SQLUpdateBatchAction extends SQLAction<List<Integer>> {
/** /**
* 添加一条批量执行的SQL语句 * 添加一条批量执行的SQL语句
* *
* @param sql SQL语句 * @param sql SQL语句
* @return {@link SQLUpdateBatchAction} * @return {@link SQLUpdateBatchAction}
*/ */
SQLUpdateBatchAction addBatch(@NotNull String sql); SQLUpdateBatchAction addBatch(@NotNull String sql);
@Override @Override
default @NotNull String getSQLContent() { default @NotNull String getSQLContent() {
return getSQLContents().get(0); return getSQLContents().get(0);
} }
List<String> getSQLContents(); List<String> getSQLContents();
} }
@@ -32,16 +32,16 @@ import java.sql.SQLException;
*/ */
public interface QueryAction extends SQLAction<SQLQuery> { public interface QueryAction extends SQLAction<SQLQuery> {
@Override @Override
@Contract("_,!null -> !null") @Contract("_,!null -> !null")
default <R> @Nullable R executeFunction(@NotNull SQLFunction<@NotNull SQLQuery, R> function, default <R> @Nullable R executeFunction(@NotNull SQLFunction<@NotNull SQLQuery, R> function,
@Nullable R defaultResult) throws SQLException { @Nullable R defaultResult) throws SQLException {
try (SQLQuery value = execute()) { try (SQLQuery value = execute()) {
R result = function.apply(value); R result = function.apply(value);
return result == null ? defaultResult : result; return result == null ? defaultResult : result;
} catch (SQLException exception) { } catch (SQLException exception) {
throw new SQLException(exception); throw new SQLException(exception);
} }
} }
} }
@@ -4,6 +4,6 @@ import cc.carm.lib.easysql.api.SQLAction;
public interface DeleteBuilder extends ConditionalBuilder<DeleteBuilder, SQLAction<Integer>> { public interface DeleteBuilder extends ConditionalBuilder<DeleteBuilder, SQLAction<Integer>> {
String getTableName(); String getTableName();
} }
@@ -14,12 +14,12 @@ import java.util.List;
*/ */
public interface ReplaceBuilder<T extends SQLAction<?>> { public interface ReplaceBuilder<T extends SQLAction<?>> {
String getTableName(); String getTableName();
T setColumnNames(List<String> columnNames); T setColumnNames(List<String> columnNames);
default T setColumnNames(String... columnNames) { default T setColumnNames(String... columnNames) {
return setColumnNames(columnNames == null ? null : Arrays.asList(columnNames)); return setColumnNames(columnNames == null ? null : Arrays.asList(columnNames));
} }
} }
@@ -10,120 +10,120 @@ import org.jetbrains.annotations.Nullable;
public interface TableAlterBuilder extends SQLBuilder { public interface TableAlterBuilder extends SQLBuilder {
SQLAction<Integer> renameTo(@NotNull String newTableName); SQLAction<Integer> renameTo(@NotNull String newTableName);
SQLAction<Integer> changeComment(@NotNull String newTableComment); SQLAction<Integer> changeComment(@NotNull String newTableComment);
SQLAction<Integer> setAutoIncrementIndex(int index); SQLAction<Integer> setAutoIncrementIndex(int index);
SQLAction<Integer> addIndex(@NotNull IndexType indexType, @NotNull String indexName, SQLAction<Integer> addIndex(@NotNull IndexType indexType, @Nullable String indexName,
@NotNull String columnName, @NotNull String... moreColumns); @NotNull String columnName, @NotNull String... moreColumns);
/** /**
* 为该表移除一个索引 * 为该表移除一个索引
* *
* @param indexName 索引名 * @param indexName 索引名
* @return {@link SQLUpdateAction} * @return {@link SQLUpdateAction}
*/ */
SQLAction<Integer> dropIndex(@NotNull String indexName); SQLAction<Integer> dropIndex(@NotNull String indexName);
/** /**
* 为该表移除一个外键 * 为该表移除一个外键
* *
* @param keySymbol 外键名 * @param keySymbol 外键名
* @return {@link SQLUpdateAction} * @return {@link SQLUpdateAction}
*/ */
SQLAction<Integer> dropForeignKey(@NotNull String keySymbol); SQLAction<Integer> dropForeignKey(@NotNull String keySymbol);
/** /**
* 为该表移除主键(须添加新主键) * 为该表移除主键(须添加新主键)
* *
* @return {@link SQLUpdateAction} * @return {@link SQLUpdateAction}
*/ */
SQLAction<Integer> dropPrimaryKey(); SQLAction<Integer> dropPrimaryKey();
/** /**
* 为表添加一列 * 为表添加一列
* *
* @param columnName 列名 * @param columnName 列名
* @param settings 列的相关设定 * @param settings 列的相关设定
* @return {@link SQLUpdateAction} * @return {@link SQLUpdateAction}
*/ */
default SQLAction<Integer> addColumn(@NotNull String columnName, @NotNull String settings) { default SQLAction<Integer> addColumn(@NotNull String columnName, @NotNull String settings) {
return addColumn(columnName, settings, null); return addColumn(columnName, settings, null);
} }
/** /**
* 为表添加一列 * 为表添加一列
* *
* @param columnName 列名 * @param columnName 列名
* @param settings 列的相关设定 * @param settings 列的相关设定
* @param afterColumn 该列增添到哪个列的后面, * @param afterColumn 该列增添到哪个列的后面,
* <p> 该参数若省缺则放于最后一行 * <p> 该参数若省缺则放于最后一行
* <p> 若为 "" 则置于首行。 * <p> 若为 "" 则置于首行。
* @return {@link SQLUpdateAction} * @return {@link SQLUpdateAction}
*/ */
SQLAction<Integer> addColumn(@NotNull String columnName, @NotNull String settings, @Nullable String afterColumn); SQLAction<Integer> addColumn(@NotNull String columnName, @NotNull String settings, @Nullable String afterColumn);
SQLAction<Integer> renameColumn(@NotNull String columnName, @NotNull String newName); SQLAction<Integer> renameColumn(@NotNull String columnName, @NotNull String newName);
SQLAction<Integer> modifyColumn(@NotNull String columnName, @NotNull String settings); SQLAction<Integer> modifyColumn(@NotNull String columnName, @NotNull String settings);
default SQLAction<Integer> modifyColumn(@NotNull String columnName, @NotNull String columnSettings, @NotNull String afterColumn) { default SQLAction<Integer> modifyColumn(@NotNull String columnName, @NotNull String columnSettings, @NotNull String afterColumn) {
return modifyColumn(columnName, columnSettings + " AFTER `" + afterColumn + "`"); return modifyColumn(columnName, columnSettings + " AFTER `" + afterColumn + "`");
} }
SQLAction<Integer> removeColumn(@NotNull String columnName); SQLAction<Integer> removeColumn(@NotNull String columnName);
SQLAction<Integer> setColumnDefault(@NotNull String columnName, @NotNull String defaultValue); SQLAction<Integer> setColumnDefault(@NotNull String columnName, @NotNull String defaultValue);
SQLAction<Integer> removeColumnDefault(@NotNull String columnName); SQLAction<Integer> removeColumnDefault(@NotNull String columnName);
/** /**
* 为该表添加一个自增列 * 为该表添加一个自增列
* <p> 自增列强制要求为数字类型,非空,且为UNIQUE。 * <p> 自增列强制要求为数字类型,非空,且为UNIQUE。
* <p> 注意:一个表只允许有一个自增列! * <p> 注意:一个表只允许有一个自增列!
* *
* @param columnName 列名 * @param columnName 列名
* @param numberType 数字类型,若省缺则为 {@link NumberType#INT} * @param numberType 数字类型,若省缺则为 {@link NumberType#INT}
* @param primary 是否为主键,若否则只为唯一键 * @param primary 是否为主键,若否则只为唯一键
* @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true) * @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true)
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
default SQLAction<Integer> addAutoIncrementColumn(@NotNull String columnName, @Nullable NumberType numberType, default SQLAction<Integer> addAutoIncrementColumn(@NotNull String columnName, @Nullable NumberType numberType,
boolean primary, boolean unsigned) { boolean primary, boolean unsigned) {
return addColumn(columnName, return addColumn(columnName,
(numberType == null ? NumberType.INT : numberType).name() (numberType == null ? NumberType.INT : numberType).name()
+ (unsigned ? " UNSIGNED " : " ") + (unsigned ? " UNSIGNED " : " ")
+ "NOT NULL AUTO_INCREMENT " + (primary ? "PRIMARY KEY" : "UNIQUE KEY"), + "NOT NULL AUTO_INCREMENT " + (primary ? "PRIMARY KEY" : "UNIQUE KEY"),
"" ""
); );
} }
/** /**
* 为该表添加一个自增列 * 为该表添加一个自增列
* <br> 自增列强制要求为数字类型,非空,且为UNIQUE。 * <br> 自增列强制要求为数字类型,非空,且为UNIQUE。
* <p> 注意:一个表只允许有一个自增列! * <p> 注意:一个表只允许有一个自增列!
* *
* @param columnName 列名 * @param columnName 列名
* @param numberType 数字类型,若省缺则为 {@link NumberType#INT} * @param numberType 数字类型,若省缺则为 {@link NumberType#INT}
* @return {@link TableAlterBuilder} * @return {@link TableAlterBuilder}
*/ */
default SQLAction<Integer> addAutoIncrementColumn(@NotNull String columnName, @NotNull NumberType numberType) { default SQLAction<Integer> addAutoIncrementColumn(@NotNull String columnName, @NotNull NumberType numberType) {
return addAutoIncrementColumn(columnName, numberType, false, true); return addAutoIncrementColumn(columnName, numberType, false, true);
} }
/** /**
* 为该表添加一个自增列 * 为该表添加一个自增列
* <br> 自增列强制要求为数字类型,非空,且为UNIQUE。 * <br> 自增列强制要求为数字类型,非空,且为UNIQUE。
* <p> 注意:一个表只允许有一个自增列! * <p> 注意:一个表只允许有一个自增列!
* *
* @param columnName 列名 * @param columnName 列名
* @return {@link TableAlterBuilder} * @return {@link TableAlterBuilder}
*/ */
default SQLAction<Integer> addAutoIncrementColumn(@NotNull String columnName) { default SQLAction<Integer> addAutoIncrementColumn(@NotNull String columnName) {
return addAutoIncrementColumn(columnName, NumberType.INT); return addAutoIncrementColumn(columnName, NumberType.INT);
} }
} }
@@ -16,241 +16,241 @@ import static cc.carm.lib.easysql.api.SQLBuilder.withQuote;
public interface TableCreateBuilder extends SQLBuilder { public interface TableCreateBuilder extends SQLBuilder {
/** /**
* 将现有条件构建完整的SQL语句用于执行。 * 将现有条件构建完整的SQL语句用于执行。
* *
* @return {@link SQLUpdateAction} * @return {@link SQLUpdateAction}
*/ */
SQLUpdateAction build(); SQLUpdateAction build();
@NotNull String getTableName(); @NotNull String getTableName();
/** /**
* 得到表的设定。 * 得到表的设定。
* <p> 若未使用 {@link #setTableSettings(String)} 方法则会采用 {@link #defaultTablesSettings()} 。 * <p> 若未使用 {@link #setTableSettings(String)} 方法则会采用 {@link #defaultTablesSettings()} 。
* *
* @return TableSettings * @return TableSettings
*/ */
@NotNull String getTableSettings(); @NotNull String getTableSettings();
TableCreateBuilder setTableSettings(@NotNull String settings); TableCreateBuilder setTableSettings(@NotNull String settings);
/** /**
* 设定表的标注,一般用于解释该表的作用。 * 设定表的标注,一般用于解释该表的作用。
* *
* @param comment 表标注 * @param comment 表标注
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
TableCreateBuilder setTableComment(@Nullable String comment); TableCreateBuilder setTableComment(@Nullable String comment);
/** /**
* 直接设定表的所有列信息 * 直接设定表的所有列信息
* *
* @param columns 列的相关信息 (包括列设定) * @param columns 列的相关信息 (包括列设定)
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
TableCreateBuilder setColumns(@NotNull String... columns); TableCreateBuilder setColumns(@NotNull String... columns);
/** /**
* 为该表添加一个列 * 为该表添加一个列
* *
* @param column 列的相关信息 * @param column 列的相关信息
* <br>如 `uuid` VARCHAR(36) NOT NULL UNIQUE KEY * <br>如 `uuid` VARCHAR(36) NOT NULL UNIQUE KEY
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
TableCreateBuilder addColumn(@NotNull String column); TableCreateBuilder addColumn(@NotNull String column);
/** /**
* 为该表添加一个列 * 为该表添加一个列
* *
* @param columnName 列名 * @param columnName 列名
* @param settings 列的设定 * @param settings 列的设定
* <br>如 VARCHAR(36) NOT NULL UNIQUE KEY * <br>如 VARCHAR(36) NOT NULL UNIQUE KEY
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
default TableCreateBuilder addColumn(@NotNull String columnName, @NotNull String settings) { default TableCreateBuilder addColumn(@NotNull String columnName, @NotNull String settings) {
Objects.requireNonNull(columnName, "columnName could not be null"); Objects.requireNonNull(columnName, "columnName could not be null");
return addColumn(withBackQuote(columnName) + " " + settings); return addColumn(withBackQuote(columnName) + " " + settings);
} }
/** /**
* 为该表添加一个列 * 为该表添加一个列
* *
* @param columnName 列名 * @param columnName 列名
* @param settings 列的设定 * @param settings 列的设定
* <br>如 VARCHAR(36) NOT NULL UNIQUE KEY * <br>如 VARCHAR(36) NOT NULL UNIQUE KEY
* @param comments 列的注解,用于解释该列数据的作用 * @param comments 列的注解,用于解释该列数据的作用
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
default TableCreateBuilder addColumn(@NotNull String columnName, @NotNull String settings, @NotNull String comments) { default TableCreateBuilder addColumn(@NotNull String columnName, @NotNull String settings, @NotNull String comments) {
return addColumn(columnName, settings + " COMMENT " + withQuote(comments)); return addColumn(columnName, settings + " COMMENT " + withQuote(comments));
} }
/** /**
* 为该表添加一个自增列 * 为该表添加一个自增列
* <p> 自增列强制要求为数字类型,非空,且为UNIQUE。 * <p> 自增列强制要求为数字类型,非空,且为UNIQUE。
* <p> 注意:一个表只允许有一个自增列! * <p> 注意:一个表只允许有一个自增列!
* *
* @param columnName 列名 * @param columnName 列名
* @param numberType 数字类型,若省缺则为 {@link NumberType#INT} * @param numberType 数字类型,若省缺则为 {@link NumberType#INT}
* @param asPrimaryKey 是否为主键,若为false则设定为唯一键 * @param asPrimaryKey 是否为主键,若为false则设定为唯一键
* @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true) * @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true)
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, @Nullable NumberType numberType, TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, @Nullable NumberType numberType,
boolean asPrimaryKey, boolean unsigned); boolean asPrimaryKey, boolean unsigned);
/** /**
* 为该表添加一个INT类型的自增主键列 * 为该表添加一个INT类型的自增主键列
* <p> 自增列强制要求为数字类型,非空,且为UNIQUE。 * <p> 自增列强制要求为数字类型,非空,且为UNIQUE。
* <p> 注意:一个表只允许有一个自增列! * <p> 注意:一个表只允许有一个自增列!
* *
* @param columnName 列名 * @param columnName 列名
* @param asPrimaryKey 是否为主键,若为false则设定为唯一键 * @param asPrimaryKey 是否为主键,若为false则设定为唯一键
* @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true) * @param unsigned 是否采用 UNSIGNED (即无负数,可以增加自增键的最高数,建议为true)
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName,
boolean asPrimaryKey, boolean unsigned) { boolean asPrimaryKey, boolean unsigned) {
return addAutoIncrementColumn(columnName, NumberType.INT, asPrimaryKey, unsigned); return addAutoIncrementColumn(columnName, NumberType.INT, asPrimaryKey, unsigned);
} }
/** /**
* 为该表添加一个INT类型的自增列 * 为该表添加一个INT类型的自增列
* <p> 自增列强制要求为数字类型,非空,且为UNIQUE。 * <p> 自增列强制要求为数字类型,非空,且为UNIQUE。
* <p> 注意:一个表只允许有一个自增列! * <p> 注意:一个表只允许有一个自增列!
* *
* @param columnName 列名 * @param columnName 列名
* @param asPrimaryKey 是否为主键,若为false则设定为唯一键 * @param asPrimaryKey 是否为主键,若为false则设定为唯一键
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, boolean asPrimaryKey) { default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, boolean asPrimaryKey) {
return addAutoIncrementColumn(columnName, asPrimaryKey, true); return addAutoIncrementColumn(columnName, asPrimaryKey, true);
} }
/** /**
* 为该表添加一个INT类型的自增主键列 * 为该表添加一个INT类型的自增主键列
* <p> 自增列强制要求为数字类型,非空,且为UNIQUE。 * <p> 自增列强制要求为数字类型,非空,且为UNIQUE。
* <p> 注意:一个表只允许有一个自增列! * <p> 注意:一个表只允许有一个自增列!
* *
* @param columnName 列名 * @param columnName 列名
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName) { default TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName) {
return addAutoIncrementColumn(columnName, true); return addAutoIncrementColumn(columnName, true);
} }
/** /**
* 设定表中的某列为索引或键。 * 设定表中的某列为索引或键。
* *
* <p>创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。 * <p>创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。
* <br>虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE 和DELETE。 * <br>虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE 和DELETE。
* <br>因此,请合理的设计索引。 * <br>因此,请合理的设计索引。
* *
* @param type 索引类型 * @param type 索引类型
* @param columnName 索引包含的列 * @param columnName 索引包含的列
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
default TableCreateBuilder setIndex(@NotNull String columnName, default TableCreateBuilder setIndex(@NotNull String columnName,
@NotNull IndexType type) { @NotNull IndexType type) {
return setIndex(type, null, columnName); return setIndex(type, null, columnName);
} }
/** /**
* 设定表中的某列为索引或键。 * 设定表中的某列为索引或键。
* *
* <p>创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。 * <p>创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。
* <br>虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE 和DELETE。 * <br>虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE 和DELETE。
* <br>因此,请合理的设计索引。 * <br>因此,请合理的设计索引。
* *
* @param type 索引类型 * @param type 索引类型
* @param indexName 索引名称,缺省时将根据第一个索引列赋一个名称 * @param indexName 索引名称,缺省时将根据第一个索引列赋一个名称
* @param columnName 索引包含的列 * @param columnName 索引包含的列
* @param moreColumns 联合索引需要包含的列 * @param moreColumns 联合索引需要包含的列
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
TableCreateBuilder setIndex(@NotNull IndexType type, @Nullable String indexName, TableCreateBuilder setIndex(@NotNull IndexType type, @Nullable String indexName,
@NotNull String columnName, @NotNull String... moreColumns); @NotNull String columnName, @NotNull String... moreColumns);
/** /**
* 以本表位从表,为表中某列设定自参照外键(即自参照完整性)。 * 以本表位从表,为表中某列设定自参照外键(即自参照完整性)。
* *
* <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。 * <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
* <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。 * <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
* <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。 * <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
* *
* @param tableColumn 本表中的列 * @param tableColumn 本表中的列
* @param foreignColumn 外键关联表中对应的关联列,必须为目标表的主键,即 {@link IndexType#PRIMARY_KEY} * @param foreignColumn 外键关联表中对应的关联列,必须为目标表的主键,即 {@link IndexType#PRIMARY_KEY}
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
default TableCreateBuilder addForeignKey(@NotNull String tableColumn, @NotNull String foreignColumn) { default TableCreateBuilder addForeignKey(@NotNull String tableColumn, @NotNull String foreignColumn) {
return addForeignKey(tableColumn, getTableName(), foreignColumn); return addForeignKey(tableColumn, getTableName(), foreignColumn);
} }
/** /**
* 以本表位从表,为表中某列设定外键。 * 以本表位从表,为表中某列设定外键。
* *
* <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。 * <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
* <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。 * <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
* <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。 * <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
* *
* @param tableColumn 本表中的列 * @param tableColumn 本表中的列
* @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。 * @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。
* @param foreignColumn 外键关联主表中对应的关联列,须满足 * @param foreignColumn 外键关联主表中对应的关联列,须满足
* <p> 1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY} * <p> 1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY}
* <p> 2. 数据类型必须和所要建立主键的列的数据类型相同。 * <p> 2. 数据类型必须和所要建立主键的列的数据类型相同。
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
default TableCreateBuilder addForeignKey(@NotNull String tableColumn, default TableCreateBuilder addForeignKey(@NotNull String tableColumn,
@NotNull String foreignTable, @NotNull String foreignColumn) { @NotNull String foreignTable, @NotNull String foreignColumn) {
return addForeignKey(tableColumn, null, foreignTable, foreignColumn); return addForeignKey(tableColumn, null, foreignTable, foreignColumn);
} }
/** /**
* 以本表位从表,为表中某列设定外键。 * 以本表位从表,为表中某列设定外键。
* *
* <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。 * <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
* <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。 * <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
* <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。 * <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
* *
* @param tableColumn 本表中的列 * @param tableColumn 本表中的列
* @param constraintName 约束名,缺省时将使用参数自动生成,如 <i>fk_[tableColumn]_[foreignTable]</i> * @param constraintName 约束名,缺省时将使用参数自动生成,如 <i>fk_[tableColumn]_[foreignTable]</i>
* @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。 * @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。
* @param foreignColumn 外键关联主表中对应的关联列,须满足 * @param foreignColumn 外键关联主表中对应的关联列,须满足
* <p> 1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY} * <p> 1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY}
* <p> 2. 数据类型必须和所要建立主键的列的数据类型相同。 * <p> 2. 数据类型必须和所要建立主键的列的数据类型相同。
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
default TableCreateBuilder addForeignKey(@NotNull String tableColumn, @Nullable String constraintName, default TableCreateBuilder addForeignKey(@NotNull String tableColumn, @Nullable String constraintName,
@NotNull String foreignTable, @NotNull String foreignColumn) { @NotNull String foreignTable, @NotNull String foreignColumn) {
return addForeignKey(tableColumn, constraintName, foreignTable, foreignColumn, null, null); return addForeignKey(tableColumn, constraintName, foreignTable, foreignColumn, null, null);
} }
/** /**
* 以本表位从表,为表中某列设定外键。 * 以本表位从表,为表中某列设定外键。
* *
* <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。 * <p>外键约束(FOREIGN KEY)是表的一个特殊字段,经常与主键约束一起使用。
* <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。 * <br>外键用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。
* <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。 * <br>主表删除某条记录时,从表中与之对应的记录也必须有相应的改变。
* *
* @param tableColumn 本表中的列 * @param tableColumn 本表中的列
* @param constraintName 约束名,缺省时将使用参数自动生成,如 <i>fk_[tableColumn]_[foreignTable]</i> * @param constraintName 约束名,缺省时将使用参数自动生成,如 <i>fk_[tableColumn]_[foreignTable]</i>
* @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。 * @param foreignTable 外键关联主表,必须为已存在的表或本表,且必须有主键。
* @param foreignColumn 外键关联主表中对应的关联列,须满足 * @param foreignColumn 外键关联主表中对应的关联列,须满足
* <p> 1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY} * <p> 1. 为主表的主键,即 {@link IndexType#PRIMARY_KEY}
* <p> 2. 数据类型必须和所要建立主键的列的数据类型相同。 * <p> 2. 数据类型必须和所要建立主键的列的数据类型相同。
* @param updateRule 在外键被更新时采用的规则,缺省时默认为{@link ForeignKeyRule#RESTRICT} * @param updateRule 在外键被更新时采用的规则,缺省时默认为{@link ForeignKeyRule#RESTRICT}
* @param deleteRule 在外键被删除时采用的规则,缺省时默认为{@link ForeignKeyRule#RESTRICT} * @param deleteRule 在外键被删除时采用的规则,缺省时默认为{@link ForeignKeyRule#RESTRICT}
* @return {@link TableCreateBuilder} * @return {@link TableCreateBuilder}
*/ */
TableCreateBuilder addForeignKey(@NotNull String tableColumn, @Nullable String constraintName, TableCreateBuilder addForeignKey(@NotNull String tableColumn, @Nullable String constraintName,
@NotNull String foreignTable, @NotNull String foreignColumn, @NotNull String foreignTable, @NotNull String foreignColumn,
@Nullable ForeignKeyRule updateRule, @Nullable ForeignKeyRule deleteRule); @Nullable ForeignKeyRule updateRule, @Nullable ForeignKeyRule deleteRule);
default String defaultTablesSettings() { default String defaultTablesSettings() {
return "ENGINE=InnoDB DEFAULT CHARSET=utf8"; return "ENGINE=InnoDB DEFAULT CHARSET=utf8";
} }
} }
@@ -2,40 +2,40 @@ package cc.carm.lib.easysql.api.enums;
public enum ForeignKeyRule { public enum ForeignKeyRule {
/** /**
* 啥也不做 * 啥也不做
* <p>注意: 在Mysql中该选项实际上等同于采用默认的 {@link #RESTRICT} 设定! * <p>注意: 在Mysql中该选项实际上等同于采用默认的 {@link #RESTRICT} 设定!
*/ */
NO_ACTION("NO ACTION"), NO_ACTION("NO ACTION"),
/** /**
* 拒绝删除要求,直到使用删除键值的辅助表被手工删除,并且没有参照时(这是默认设置,也是最安全的设置) * 拒绝删除要求,直到使用删除键值的辅助表被手工删除,并且没有参照时(这是默认设置,也是最安全的设置)
*/ */
RESTRICT("RESTRICT"), RESTRICT("RESTRICT"),
/** /**
* 修改包含与已删除键值有参照关系的所有记录,使用NULL值替换(只能用于已标记为NOT NULL的字段) * 修改包含与已删除键值有参照关系的所有记录,使用NULL值替换(只能用于已标记为NOT NULL的字段)
*/ */
SET_NULL("SET NULL"), SET_NULL("SET NULL"),
/** /**
* 修改包含与已删除键值有参照关系的所有记录,使用默认值替换(只能用于设定了DEFAULT的字段) * 修改包含与已删除键值有参照关系的所有记录,使用默认值替换(只能用于设定了DEFAULT的字段)
*/ */
SET_DEFAULT("SET DEFAULT"), SET_DEFAULT("SET DEFAULT"),
/** /**
* <b>级联删除</b>,删除包含与已删除键值有参照关系的所有记录 * <b>级联删除</b>,删除包含与已删除键值有参照关系的所有记录
*/ */
CASCADE("CASCADE"); CASCADE("CASCADE");
final String ruleName; final String ruleName;
ForeignKeyRule(String ruleName) { ForeignKeyRule(String ruleName) {
this.ruleName = ruleName; this.ruleName = ruleName;
} }
public String getRuleName() { public String getRuleName() {
return ruleName; return ruleName;
} }
} }
@@ -3,39 +3,39 @@ package cc.carm.lib.easysql.api.enums;
public enum IndexType { public enum IndexType {
/** /**
* <b>普通索引</b>(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。 * <b>普通索引</b>(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。
* <br> 因此,应该只为那些最经常出现在查询条件(WHERE column=)或排序条件(ORDER BY column)中的数据列创建索引。 * <br> 因此,应该只为那些最经常出现在查询条件(WHERE column=)或排序条件(ORDER BY column)中的数据列创建索引。
* <br> 只要有可能,就应该选择一个数据最整齐、最紧凑的数据列(如一个整数类型的数据列)来创建索引。 * <br> 只要有可能,就应该选择一个数据最整齐、最紧凑的数据列(如一个整数类型的数据列)来创建索引。
*/ */
INDEX("INDEX"), INDEX("INDEX"),
/** /**
* <b>唯一索引</b> 是在表上一个或者多个字段组合建立的索引,这个或者这些字段的值组合起来在表中不可以重复,用于保证数据的唯一性。 * <b>唯一索引</b> 是在表上一个或者多个字段组合建立的索引,这个或者这些字段的值组合起来在表中不可以重复,用于保证数据的唯一性。
*/ */
UNIQUE_KEY("UNIQUE KEY"), UNIQUE_KEY("UNIQUE KEY"),
/** /**
* <b>主键索引</b> 是唯一索引的特定类型。表中创建主键时自动创建的索引 。一个表只能建立一个主索引。 * <b>主键索引</b> 是唯一索引的特定类型。表中创建主键时自动创建的索引 。一个表只能建立一个主索引。
*/ */
PRIMARY_KEY("PRIMARY KEY"), PRIMARY_KEY("PRIMARY KEY"),
/** /**
* <b>全文索引</b> 主要用来查找文本中的关键字,而不是直接与索引中的值相比较。 * <b>全文索引</b> 主要用来查找文本中的关键字,而不是直接与索引中的值相比较。
* <br> 请搭配 MATCH 等语句使用,而不是使用 WHERE - LIKE 。 * <br> 请搭配 MATCH 等语句使用,而不是使用 WHERE - LIKE 。
* <br> 全文索引只可用于 CHAR、 VARCHAR 与 TEXT 系列类型。 * <br> 全文索引只可用于 CHAR、 VARCHAR 与 TEXT 系列类型。
*/ */
FULLTEXT_INDEX("FULLTEXT"); FULLTEXT_INDEX("FULLTEXT");
final String name; final String name;
IndexType(String name) { IndexType(String name) {
this.name = name; this.name = name;
} }
public String getName() { public String getName() {
return name; return name;
} }
} }
@@ -2,10 +2,10 @@ package cc.carm.lib.easysql.api.enums;
public enum NumberType { public enum NumberType {
TINYINT, TINYINT,
SMALLINT, SMALLINT,
MEDIUMINT, MEDIUMINT,
INT, INT,
BIGINT BIGINT
} }
@@ -7,6 +7,6 @@ import java.util.function.BiConsumer;
@FunctionalInterface @FunctionalInterface
public interface SQLExceptionHandler extends BiConsumer<SQLException, SQLAction<?>> { public interface SQLExceptionHandler extends BiConsumer<SQLException, SQLAction<?>> {
} }
@@ -8,7 +8,7 @@ import java.sql.SQLException;
@FunctionalInterface @FunctionalInterface
public interface SQLFunction<T, R> { public interface SQLFunction<T, R> {
@Nullable @Nullable
R apply(@NotNull T t) throws SQLException; R apply(@NotNull T t) throws SQLException;
} }
@@ -9,15 +9,15 @@ import java.util.Objects;
@FunctionalInterface @FunctionalInterface
public interface SQLHandler<T> { public interface SQLHandler<T> {
void accept(@NotNull T t) throws SQLException; void accept(@NotNull T t) throws SQLException;
@NotNull @NotNull
@Contract(pure = true) @Contract(pure = true)
default SQLHandler<T> andThen(@NotNull SQLHandler<? super T> after) { default SQLHandler<T> andThen(@NotNull SQLHandler<? super T> after) {
Objects.requireNonNull(after); Objects.requireNonNull(after);
return (T t) -> { return (T t) -> {
accept(t); accept(t);
after.accept(t); after.accept(t);
}; };
} }
} }
@@ -11,47 +11,46 @@ import java.util.logging.Logger;
public class DefaultSQLExceptionHandler implements SQLExceptionHandler { public class DefaultSQLExceptionHandler implements SQLExceptionHandler {
private static @Nullable SQLExceptionHandler customDefaultHandler = null; private static @Nullable SQLExceptionHandler customDefaultHandler = null;
private final Logger logger;
public static void setCustomHandler(@Nullable SQLExceptionHandler handler) { public DefaultSQLExceptionHandler(Logger logger) {
DefaultSQLExceptionHandler.customDefaultHandler = handler; this.logger = logger;
} }
public static @Nullable SQLExceptionHandler getCustomHandler() { public static @Nullable SQLExceptionHandler getCustomHandler() {
return customDefaultHandler; return customDefaultHandler;
} }
public static @NotNull SQLExceptionHandler get(Logger logger) { public static void setCustomHandler(@Nullable SQLExceptionHandler handler) {
if (getCustomHandler() != null) return getCustomHandler(); DefaultSQLExceptionHandler.customDefaultHandler = handler;
else return new DefaultSQLExceptionHandler(logger); }
}
private final Logger logger; public static @NotNull SQLExceptionHandler get(Logger logger) {
if (getCustomHandler() != null) return getCustomHandler();
else return new DefaultSQLExceptionHandler(logger);
}
public DefaultSQLExceptionHandler(Logger logger) { protected Logger getLogger() {
this.logger = logger; return logger;
} }
protected Logger getLogger() { @Override
return logger; public void accept(SQLException exception, SQLAction<?> sqlAction) {
} if (sqlAction instanceof SQLUpdateBatchAction) {
@Override getLogger().severe("Error when execute SQLs : ");
public void accept(SQLException exception, SQLAction<?> sqlAction) { int i = 1;
if (sqlAction instanceof SQLUpdateBatchAction) { for (String content : ((SQLUpdateBatchAction) sqlAction).getSQLContents()) {
getLogger().severe(String.format("#%d {%s}", i, content));
i++;
}
getLogger().severe("Error when execute SQLs : "); } else {
int i = 1; getLogger().severe("Error when execute { " + sqlAction.getSQLContent() + " }");
for (String content : ((SQLUpdateBatchAction) sqlAction).getSQLContents()) { }
getLogger().severe("#" + i + " {" + content + "}"); exception.printStackTrace();
i++; }
}
} else {
getLogger().severe("Error when execute { " + sqlAction.getSQLContent() + " }");
}
exception.printStackTrace();
}
} }
@@ -6,7 +6,7 @@ import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
public class TimeDateUtils { public class TimeDateUtils {
public static DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public TimeDateUtils() { public TimeDateUtils() {
} }
@@ -7,78 +7,80 @@ import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
public abstract class AbstractSQLAction<T> implements SQLAction<T> { public abstract class AbstractSQLAction<T> implements SQLAction<T> {
private final @NotNull SQLManagerImpl sqlManager; protected final @NotNull String sqlContent;
private final @NotNull SQLManagerImpl sqlManager;
private final @NotNull UUID uuid;
private final long createTime;
private final @NotNull UUID uuid; public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql) {
private final long createTime; this(manager, sql, System.currentTimeMillis());
}
protected @NotNull String sqlContent; public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql, @NotNull UUID uuid) {
this(manager, sql, uuid, System.currentTimeMillis());
}
public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql) { public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql, long createTime) {
this(manager, sql, System.currentTimeMillis()); this(manager, sql, UUID.randomUUID(), createTime);
} }
public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql, @NotNull UUID uuid) { public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql,
this(manager, sql, uuid, System.currentTimeMillis()); @NotNull UUID uuid, long createTime) {
} Objects.requireNonNull(manager);
Objects.requireNonNull(sql);
public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql, long createTime) { Objects.requireNonNull(uuid);
this(manager, sql, UUID.randomUUID(), createTime); this.sqlManager = manager;
} this.sqlContent = sql;
this.uuid = uuid;
public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql, this.createTime = createTime;
@NotNull UUID uuid, long createTime) { }
this.sqlManager = manager;
this.sqlContent = sql;
this.uuid = uuid;
this.createTime = createTime;
}
@Override @Override
public @NotNull UUID getActionUUID() { public @NotNull UUID getActionUUID() {
return this.uuid; return this.uuid;
} }
@Override @Override
public @NotNull String getShortID() { public @NotNull String getShortID() {
return getActionUUID().toString().substring(0, 8); return getActionUUID().toString().substring(0, 8);
} }
@Override @Override
public long getCreateTime() { public long getCreateTime() {
return this.createTime; return this.createTime;
} }
@Override @Override
public @NotNull String getSQLContent() { public @NotNull String getSQLContent() {
return this.sqlContent.trim(); return this.sqlContent.trim();
} }
@Override @Override
public @NotNull SQLManagerImpl getManager() { public @NotNull SQLManagerImpl getManager() {
return this.sqlManager; return this.sqlManager;
} }
protected void outputDebugMessage() { protected void outputDebugMessage() {
getManager().debug("# " + getShortID() + " -> { " + getSQLContent() + " }"); getManager().debug("# " + getShortID() + " -> { " + getSQLContent() + " }");
} }
@Override @Override
@SuppressWarnings("FutureReturnValueIgnored") @SuppressWarnings("FutureReturnValueIgnored")
public void executeAsync(SQLHandler<T> success, SQLExceptionHandler failure) { public void executeAsync(SQLHandler<T> success, SQLExceptionHandler failure) {
getManager().getExecutorPool().submit(() -> { getManager().getExecutorPool().submit(() -> {
try { try {
T returnedValue = execute(); T returnedValue = execute();
if (success != null) success.accept(returnedValue); if (success != null) success.accept(returnedValue);
} catch (SQLException e) { } catch (SQLException e) {
handleException(failure, e); handleException(failure, e);
} }
}); });
} }
} }
@@ -15,60 +15,60 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class PreparedSQLBatchUpdateActionImpl public class PreparedSQLBatchUpdateActionImpl
extends AbstractSQLAction<List<Integer>> extends AbstractSQLAction<List<Integer>>
implements PreparedSQLUpdateBatchAction { implements PreparedSQLUpdateBatchAction {
boolean returnKeys = false; boolean returnKeys = false;
List<Object[]> allParams; List<Object[]> allParams;
public PreparedSQLBatchUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) { public PreparedSQLBatchUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
super(manager, sql); super(manager, sql);
this.allParams = new ArrayList<>(); this.allParams = new ArrayList<>();
} }
@Override @Override
public PreparedSQLUpdateBatchAction setAllParams(Iterable<Object[]> allParams) { public PreparedSQLUpdateBatchAction setAllParams(Iterable<Object[]> allParams) {
List<Object[]> paramsList = new ArrayList<>(); List<Object[]> paramsList = new ArrayList<>();
allParams.forEach(paramsList::add); allParams.forEach(paramsList::add);
this.allParams = paramsList; this.allParams = paramsList;
return this; return this;
} }
@Override @Override
public PreparedSQLUpdateBatchAction addParamsBatch(Object... params) { public PreparedSQLUpdateBatchAction addParamsBatch(Object... params) {
this.allParams.add(params); this.allParams.add(params);
return this; return this;
} }
@Override @Override
public PreparedSQLUpdateBatchAction setReturnGeneratedKeys(boolean returnGeneratedKey) { public PreparedSQLUpdateBatchAction setReturnGeneratedKeys(boolean returnGeneratedKey) {
this.returnKeys = returnGeneratedKey; this.returnKeys = returnGeneratedKey;
return this; return this;
} }
@Override @Override
public @NotNull List<Integer> execute() throws SQLException { public @NotNull List<Integer> execute() throws SQLException {
try (Connection connection = getManager().getConnection()) { try (Connection connection = getManager().getConnection()) {
try (PreparedStatement statement = StatementUtil.createPrepareStatementBatch( try (PreparedStatement statement = StatementUtil.createPrepareStatementBatch(
connection, getSQLContent(), allParams, returnKeys connection, getSQLContent(), allParams, returnKeys
)) { )) {
outputDebugMessage(); outputDebugMessage();
int[] executed = statement.executeBatch(); int[] executed = statement.executeBatch();
if (!returnKeys) return Arrays.stream(executed).boxed().collect(Collectors.toList()); if (!returnKeys) return Arrays.stream(executed).boxed().collect(Collectors.toList());
else { else {
try (ResultSet resultSet = statement.getGeneratedKeys()) { try (ResultSet resultSet = statement.getGeneratedKeys()) {
List<Integer> generatedKeys = new ArrayList<>(); List<Integer> generatedKeys = new ArrayList<>();
while (resultSet.next()) { while (resultSet.next()) {
generatedKeys.add(resultSet.getInt(1)); generatedKeys.add(resultSet.getInt(1));
} }
return generatedKeys; return generatedKeys;
} }
} }
} }
} }
} }
} }
@@ -14,64 +14,64 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class PreparedSQLUpdateActionImpl public class PreparedSQLUpdateActionImpl
extends SQLUpdateActionImpl extends SQLUpdateActionImpl
implements PreparedSQLUpdateAction { implements PreparedSQLUpdateAction {
Object[] params; Object[] params;
public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) { public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
this(manager, sql, (Object[]) null); this(manager, sql, (Object[]) null);
} }
public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql, public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql,
@Nullable List<Object> params) { @Nullable List<Object> params) {
this(manager, sql, params == null ? null : params.toArray()); this(manager, sql, params == null ? null : params.toArray());
} }
public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql, public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql,
@Nullable Object[] params) { @Nullable Object[] params) {
super(manager, sql); super(manager, sql);
this.params = params; this.params = params;
} }
@Override @Override
public PreparedSQLUpdateActionImpl setParams(Object... params) { public PreparedSQLUpdateActionImpl setParams(Object... params) {
this.params = params; this.params = params;
return this; return this;
} }
@Override @Override
public PreparedSQLUpdateAction setParams(@Nullable Iterable<Object> params) { public PreparedSQLUpdateAction setParams(@Nullable Iterable<Object> params) {
if (params == null) { if (params == null) {
return setParams((Object[]) null); return setParams((Object[]) null);
} else { } else {
List<Object> paramsList = new ArrayList<>(); List<Object> paramsList = new ArrayList<>();
params.forEach(paramsList::add); params.forEach(paramsList::add);
return setParams(paramsList.toArray()); return setParams(paramsList.toArray());
} }
} }
@Override @Override
public @NotNull Integer execute() throws SQLException { public @NotNull Integer execute() throws SQLException {
try (Connection connection = getManager().getConnection()) { try (Connection connection = getManager().getConnection()) {
try (PreparedStatement statement = StatementUtil.createPrepareStatement( try (PreparedStatement statement = StatementUtil.createPrepareStatement(
connection, getSQLContent(), params, returnGeneratedKeys connection, getSQLContent(), params, returnGeneratedKeys
)) { )) {
outputDebugMessage(); outputDebugMessage();
int changes = statement.executeUpdate(); int changes = statement.executeUpdate();
if (!returnGeneratedKeys) return changes; if (!returnGeneratedKeys) return changes;
else { else {
try (ResultSet resultSet = statement.getGeneratedKeys()) { try (ResultSet resultSet = statement.getGeneratedKeys()) {
return resultSet.next() ? resultSet.getInt(1) : -1; return resultSet.next() ? resultSet.getInt(1) : -1;
} }
} }
} }
} }
} }
} }
@@ -10,39 +10,39 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
public class SQLUpdateActionImpl public class SQLUpdateActionImpl
extends AbstractSQLAction<Integer> extends AbstractSQLAction<Integer>
implements SQLUpdateAction { implements SQLUpdateAction {
boolean returnGeneratedKeys = false; boolean returnGeneratedKeys = false;
public SQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) { public SQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
super(manager, sql); super(manager, sql);
} }
@Override @Override
public @NotNull Integer execute() throws SQLException { public @NotNull Integer execute() throws SQLException {
try (Connection connection = getManager().getConnection()) { try (Connection connection = getManager().getConnection()) {
try (Statement statement = connection.createStatement()) { try (Statement statement = connection.createStatement()) {
outputDebugMessage(); outputDebugMessage();
if (!returnGeneratedKeys) { if (!returnGeneratedKeys) {
return statement.executeUpdate(getSQLContent()); return statement.executeUpdate(getSQLContent());
} else { } else {
statement.executeUpdate(getSQLContent(), Statement.RETURN_GENERATED_KEYS); statement.executeUpdate(getSQLContent(), Statement.RETURN_GENERATED_KEYS);
try (ResultSet resultSet = statement.getGeneratedKeys()) { try (ResultSet resultSet = statement.getGeneratedKeys()) {
return resultSet.next() ? resultSet.getInt(1) : -1; return resultSet.next() ? resultSet.getInt(1) : -1;
} }
} }
} }
} }
} }
@Override @Override
public SQLUpdateAction setReturnGeneratedKey(boolean returnGeneratedKey) { public SQLUpdateAction setReturnGeneratedKey(boolean returnGeneratedKey) {
this.returnGeneratedKeys = returnGeneratedKey; this.returnGeneratedKeys = returnGeneratedKey;
return this; return this;
} }
} }
@@ -14,53 +14,53 @@ import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class SQLUpdateBatchActionImpl public class SQLUpdateBatchActionImpl
extends AbstractSQLAction<List<Integer>> extends AbstractSQLAction<List<Integer>>
implements SQLUpdateBatchAction { implements SQLUpdateBatchAction {
List<String> sqlContents = new ArrayList<>(); protected final List<String> sqlContents = new ArrayList<>();
public SQLUpdateBatchActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) { public SQLUpdateBatchActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
super(manager, sql); super(manager, sql);
this.sqlContents.add(sql); this.sqlContents.add(sql);
} }
@Override @Override
public @NotNull List<String> getSQLContents() { public @NotNull List<String> getSQLContents() {
return this.sqlContents; return this.sqlContents;
} }
@Override @Override
public SQLUpdateBatchAction addBatch(@NotNull String sql) { public SQLUpdateBatchAction addBatch(@NotNull String sql) {
Objects.requireNonNull(sql, "sql could not be null"); Objects.requireNonNull(sql, "sql could not be null");
this.sqlContents.add(sql); this.sqlContents.add(sql);
return this; return this;
} }
@Override @Override
public @NotNull List<Integer> execute() throws SQLException { public @NotNull List<Integer> execute() throws SQLException {
try (Connection connection = getManager().getConnection()) { try (Connection connection = getManager().getConnection()) {
try (Statement statement = connection.createStatement()) { try (Statement statement = connection.createStatement()) {
outputDebugMessage(); outputDebugMessage();
for (String content : this.sqlContents) { for (String content : this.sqlContents) {
statement.addBatch(content); statement.addBatch(content);
} }
int[] executed = statement.executeBatch(); int[] executed = statement.executeBatch();
return Arrays.stream(executed).boxed().collect(Collectors.toList()); return Arrays.stream(executed).boxed().collect(Collectors.toList());
} }
} }
} }
@Override @Override
protected void outputDebugMessage() { protected void outputDebugMessage() {
getManager().debug("# " + getShortID() + " -> ["); getManager().debug("# " + getShortID() + " -> [");
for (String content : getSQLContents()) getManager().debug(" { " + content + " }"); for (String content : getSQLContents()) getManager().debug(String.format(" { %s }", content));
getManager().debug("]"); getManager().debug("]");
} }
} }
@@ -16,71 +16,71 @@ import java.util.function.Consumer;
public class PreparedQueryActionImpl extends QueryActionImpl implements PreparedQueryAction { public class PreparedQueryActionImpl extends QueryActionImpl implements PreparedQueryAction {
Consumer<PreparedStatement> handler; Consumer<PreparedStatement> handler;
Object[] params; Object[] params;
public PreparedQueryActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) { public PreparedQueryActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
super(manager, sql); super(manager, sql);
} }
@Override @Override
public PreparedQueryActionImpl setParams(@Nullable Object... params) { public PreparedQueryActionImpl setParams(@Nullable Object... params) {
this.params = params; this.params = params;
return this; return this;
} }
@Override @Override
public PreparedQueryActionImpl setParams(@Nullable Iterable<Object> params) { public PreparedQueryActionImpl setParams(@Nullable Iterable<Object> params) {
if (params == null) { if (params == null) {
return setParams((Object[]) null); return setParams((Object[]) null);
} else { } else {
List<Object> paramsList = new ArrayList<>(); List<Object> paramsList = new ArrayList<>();
params.forEach(paramsList::add); params.forEach(paramsList::add);
return setParams(paramsList.toArray()); return setParams(paramsList.toArray());
} }
} }
@Override @Override
public PreparedQueryActionImpl handleStatement(@Nullable Consumer<PreparedStatement> statement) { public PreparedQueryActionImpl handleStatement(@Nullable Consumer<PreparedStatement> statement) {
this.handler = statement; this.handler = statement;
return this; return this;
} }
@Override @Override
public @NotNull SQLQueryImpl execute() throws SQLException { public @NotNull SQLQueryImpl execute() throws SQLException {
outputDebugMessage(); outputDebugMessage();
Connection connection = getManager().getConnection(); Connection connection = getManager().getConnection();
PreparedStatement preparedStatement; PreparedStatement preparedStatement;
try { try {
if (handler == null) { if (handler == null) {
preparedStatement = StatementUtil.createPrepareStatement(connection, getSQLContent(), this.params); preparedStatement = StatementUtil.createPrepareStatement(connection, getSQLContent(), this.params);
} else { } else {
preparedStatement = connection.prepareStatement(getSQLContent()); preparedStatement = connection.prepareStatement(getSQLContent());
handler.accept(preparedStatement); handler.accept(preparedStatement);
} }
} catch (SQLException exception) { } catch (SQLException exception) {
connection.close(); connection.close();
throw exception; throw exception;
} }
try { try {
long executeTime = System.currentTimeMillis(); long executeTime = System.currentTimeMillis();
SQLQueryImpl query = new SQLQueryImpl( SQLQueryImpl query = new SQLQueryImpl(
getManager(), this, getManager(), this,
connection, preparedStatement, connection, preparedStatement,
preparedStatement.executeQuery(), preparedStatement.executeQuery(),
executeTime executeTime
); );
getManager().getActiveQuery().put(getActionUUID(), query); getManager().getActiveQuery().put(getActionUUID(), query);
return query; return query;
} catch (SQLException exception) { } catch (SQLException exception) {
preparedStatement.close(); preparedStatement.close();
connection.close(); connection.close();
throw exception; throw exception;
} }
} }
} }
@@ -15,49 +15,49 @@ import java.sql.Statement;
public class QueryActionImpl extends AbstractSQLAction<SQLQuery> implements QueryAction { public class QueryActionImpl extends AbstractSQLAction<SQLQuery> implements QueryAction {
public QueryActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) { public QueryActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
super(manager, sql); super(manager, sql);
} }
@Override @Override
public @NotNull SQLQueryImpl execute() throws SQLException { public @NotNull SQLQueryImpl execute() throws SQLException {
Connection connection = getManager().getConnection(); Connection connection = getManager().getConnection();
Statement statement; Statement statement;
try { try {
statement = connection.createStatement(); statement = connection.createStatement();
} catch (SQLException ex) { } catch (SQLException ex) {
connection.close(); connection.close();
throw ex; throw ex;
} }
outputDebugMessage();
try {
long executeTime = System.currentTimeMillis();
SQLQueryImpl query = new SQLQueryImpl(
getManager(), this,
connection, statement,
statement.executeQuery(getSQLContent()),
executeTime
);
getManager().getActiveQuery().put(getActionUUID(), query);
return query; outputDebugMessage();
} catch (SQLException exception) { try {
statement.close(); long executeTime = System.currentTimeMillis();
connection.close(); SQLQueryImpl query = new SQLQueryImpl(
throw exception; getManager(), this,
} connection, statement,
} statement.executeQuery(getSQLContent()),
executeTime
);
getManager().getActiveQuery().put(getActionUUID(), query);
return query;
} catch (SQLException exception) {
statement.close();
connection.close();
throw exception;
}
}
@Override @Override
public void executeAsync(SQLHandler<SQLQuery> success, SQLExceptionHandler failure) { public void executeAsync(SQLHandler<SQLQuery> success, SQLExceptionHandler failure) {
try (SQLQueryImpl query = execute()) { try (SQLQueryImpl query = execute()) {
if (success != null) success.accept(query); if (success != null) success.accept(query);
} catch (SQLException exception) { } catch (SQLException exception) {
handleException(failure, exception); handleException(failure, exception);
} }
} }
} }
@@ -4,11 +4,15 @@ import cc.carm.lib.easysql.api.SQLBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl; import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public abstract class AbstractSQLBuilder implements SQLBuilder { public abstract class AbstractSQLBuilder implements SQLBuilder {
@NotNull SQLManagerImpl sqlManager; @NotNull
final SQLManagerImpl sqlManager;
public AbstractSQLBuilder(@NotNull SQLManagerImpl manager) { public AbstractSQLBuilder(@NotNull SQLManagerImpl manager) {
Objects.requireNonNull(manager, "SQLManager must not be null");
this.sqlManager = manager; this.sqlManager = manager;
} }
@@ -53,6 +53,7 @@ public abstract class AbstractConditionalBuilder<B extends ConditionalBuilder<B,
@NotNull String columnName, @NotNull String operator, @Nullable Object queryValue @NotNull String columnName, @NotNull String operator, @Nullable Object queryValue
) { ) {
Objects.requireNonNull(columnName, "columnName could not be null"); Objects.requireNonNull(columnName, "columnName could not be null");
Objects.requireNonNull(operator, "operator could not be null (e.g. > or = or <) ");
addCondition(withBackQuote(columnName) + " " + operator + " ?"); addCondition(withBackQuote(columnName) + " " + operator + " ?");
this.conditionParams.add(queryValue); this.conditionParams.add(queryValue);
return getThis(); return getThis();
@@ -62,6 +63,7 @@ public abstract class AbstractConditionalBuilder<B extends ConditionalBuilder<B,
public B addCondition( public B addCondition(
@NotNull String[] columnNames, @Nullable Object[] queryValues @NotNull String[] columnNames, @Nullable Object[] queryValues
) { ) {
Objects.requireNonNull(columnNames, "columnName could not be null");
if (queryValues == null || columnNames.length != queryValues.length) { if (queryValues == null || columnNames.length != queryValues.length) {
throw new RuntimeException("queryNames are not match with queryValues"); throw new RuntimeException("queryNames are not match with queryValues");
} }
@@ -7,44 +7,47 @@ import cc.carm.lib.easysql.api.builder.DeleteBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl; import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import static cc.carm.lib.easysql.api.SQLBuilder.withBackQuote; import static cc.carm.lib.easysql.api.SQLBuilder.withBackQuote;
public class DeleteBuilderImpl public class DeleteBuilderImpl
extends AbstractConditionalBuilder<DeleteBuilder, SQLAction<Integer>> extends AbstractConditionalBuilder<DeleteBuilder, SQLAction<Integer>>
implements DeleteBuilder { implements DeleteBuilder {
String tableName; protected final String tableName;
public DeleteBuilderImpl(@NotNull SQLManagerImpl manager, @NotNull String tableName) { public DeleteBuilderImpl(@NotNull SQLManagerImpl manager, @NotNull String tableName) {
super(manager); super(manager);
this.tableName = tableName; Objects.requireNonNull(tableName);
} this.tableName = tableName;
}
@Override @Override
public PreparedSQLUpdateAction build() { public PreparedSQLUpdateAction build() {
StringBuilder sqlBuilder = new StringBuilder(); StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("DELETE FROM ").append(withBackQuote(getTableName())); sqlBuilder.append("DELETE FROM ").append(withBackQuote(getTableName()));
if (hasConditions()) sqlBuilder.append(" ").append(buildConditionSQL()); if (hasConditions()) sqlBuilder.append(" ").append(buildConditionSQL());
if (limit > 0) sqlBuilder.append(" ").append(buildLimitSQL()); if (limit > 0) sqlBuilder.append(" ").append(buildLimitSQL());
return new PreparedSQLUpdateActionImpl( return new PreparedSQLUpdateActionImpl(
getManager(), sqlBuilder.toString(), getManager(), sqlBuilder.toString(),
hasConditionParams() ? getConditionParams() : null hasConditionParams() ? getConditionParams() : null
); );
} }
@Override @Override
public String getTableName() { public String getTableName() {
return tableName; return tableName;
} }
@Override @Override
protected DeleteBuilderImpl getThis() { protected DeleteBuilderImpl getThis() {
return this; return this;
} }
} }
@@ -8,44 +8,50 @@ import org.jetbrains.annotations.NotNull;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Objects;
import static cc.carm.lib.easysql.api.SQLBuilder.withBackQuote; import static cc.carm.lib.easysql.api.SQLBuilder.withBackQuote;
public abstract class InsertBuilderImpl<T extends SQLAction<?>> public abstract class InsertBuilderImpl<T extends SQLAction<?>>
extends AbstractSQLBuilder implements InsertBuilder<T> { extends AbstractSQLBuilder implements InsertBuilder<T> {
String tableName; protected final String tableName;
public InsertBuilderImpl(@NotNull SQLManagerImpl manager, String tableName) { public InsertBuilderImpl(@NotNull SQLManagerImpl manager, String tableName) {
super(manager); super(manager);
this.tableName = tableName; Objects.requireNonNull(tableName);
} this.tableName = tableName;
}
protected static String buildSQL(String tableName, List<String> columnNames) { protected static String buildSQL(String tableName, List<String> columnNames) {
int valueLength = columnNames.size(); return buildSQL("INSERT IGNORE INTO", tableName, columnNames);
StringBuilder sqlBuilder = new StringBuilder(); }
sqlBuilder.append("INSERT IGNORE INTO ").append(withBackQuote(tableName)).append("("); protected static String buildSQL(String sqlPrefix, String tableName, List<String> columnNames) {
Iterator<String> iterator = columnNames.iterator(); int valueLength = columnNames.size();
while (iterator.hasNext()) { StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append(withBackQuote(iterator.next()));
if (iterator.hasNext()) sqlBuilder.append(", ");
}
sqlBuilder.append(") VALUES ("); sqlBuilder.append(sqlPrefix).append(" ").append(withBackQuote(tableName)).append("(");
Iterator<String> iterator = columnNames.iterator();
while (iterator.hasNext()) {
sqlBuilder.append(withBackQuote(iterator.next()));
if (iterator.hasNext()) sqlBuilder.append(", ");
}
for (int i = 0; i < valueLength; i++) { sqlBuilder.append(") VALUES (");
sqlBuilder.append("?");
if (i != valueLength - 1) {
sqlBuilder.append(", ");
}
}
sqlBuilder.append(")");
return sqlBuilder.toString();
}
@Override for (int i = 0; i < valueLength; i++) {
public String getTableName() { sqlBuilder.append("?");
return tableName; if (i != valueLength - 1) {
} sqlBuilder.append(", ");
}
}
sqlBuilder.append(")");
return sqlBuilder.toString();
}
@Override
public String getTableName() {
return tableName;
}
} }
@@ -6,46 +6,24 @@ import cc.carm.lib.easysql.builder.AbstractSQLBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl; import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
import java.util.List; import java.util.List;
import static cc.carm.lib.easysql.api.SQLBuilder.withBackQuote;
public abstract class ReplaceBuilderImpl<T extends SQLAction<?>> public abstract class ReplaceBuilderImpl<T extends SQLAction<?>>
extends AbstractSQLBuilder implements ReplaceBuilder<T> { extends AbstractSQLBuilder implements ReplaceBuilder<T> {
String tableName; protected final @NotNull String tableName;
public ReplaceBuilderImpl(@NotNull SQLManagerImpl manager, String tableName) { public ReplaceBuilderImpl(@NotNull SQLManagerImpl manager, @NotNull String tableName) {
super(manager); super(manager);
this.tableName = tableName; this.tableName = tableName;
} }
protected static String buildSQL(String tableName, List<String> columnNames) { protected static String buildSQL(String tableName, List<String> columnNames) {
int valueLength = columnNames.size(); return InsertBuilderImpl.buildSQL("REPLACE INTO", tableName, columnNames);
StringBuilder sqlBuilder = new StringBuilder(); }
sqlBuilder.append("REPLACE INTO ").append(withBackQuote(tableName)).append("("); @Override
Iterator<String> iterator = columnNames.iterator(); public @NotNull String getTableName() {
while (iterator.hasNext()) { return tableName;
sqlBuilder.append(withBackQuote(iterator.next())); }
if (iterator.hasNext()) sqlBuilder.append(", ");
}
sqlBuilder.append(") VALUES (");
for (int i = 0; i < valueLength; i++) {
sqlBuilder.append("?");
if (i != valueLength - 1) {
sqlBuilder.append(", ");
}
}
sqlBuilder.append(")");
return sqlBuilder.toString();
}
@Override
public String getTableName() {
return tableName;
}
} }
@@ -16,121 +16,138 @@ import static cc.carm.lib.easysql.api.SQLBuilder.withQuote;
public class TableAlterBuilderImpl extends AbstractSQLBuilder implements TableAlterBuilder { public class TableAlterBuilderImpl extends AbstractSQLBuilder implements TableAlterBuilder {
protected final @NotNull String tableName; protected final @NotNull String tableName;
public TableAlterBuilderImpl(@NotNull SQLManagerImpl manager, @NotNull String tableName) { public TableAlterBuilderImpl(@NotNull SQLManagerImpl manager, @NotNull String tableName) {
super(manager); super(manager);
this.tableName = tableName; this.tableName = tableName;
} }
public @NotNull String getTableName() { public @NotNull String getTableName() {
return tableName; return tableName;
} }
@Override @Override
public SQLAction<Integer> renameTo(@NotNull String newTableName) { public SQLAction<Integer> renameTo(@NotNull String newTableName) {
Objects.requireNonNull(newTableName, "table name could not be null"); Objects.requireNonNull(newTableName, "table name could not be null");
return new SQLUpdateActionImpl(getManager(), return new SQLUpdateActionImpl(getManager(),
"ALTER TABLE " + withBackQuote(getTableName()) + " RENAME TO " + withBackQuote(newTableName) + "" "ALTER TABLE " + withBackQuote(tableName) + " RENAME TO " + withBackQuote(newTableName)
); );
} }
@Override @Override
public SQLAction<Integer> changeComment(@NotNull String newTableComment) { public SQLAction<Integer> changeComment(@NotNull String newTableComment) {
return new SQLUpdateActionImpl(getManager(), Objects.requireNonNull(newTableComment, "table comment could not be null");
"ALTER TABLE " + withBackQuote(getTableName()) + " COMMENT " + withQuote(newTableComment) return new SQLUpdateActionImpl(getManager(),
); "ALTER TABLE " + withBackQuote(getTableName()) + " COMMENT " + withQuote(newTableComment)
} );
}
@Override @Override
public SQLAction<Integer> setAutoIncrementIndex(int index) { public SQLAction<Integer> setAutoIncrementIndex(int index) {
return new SQLUpdateActionImpl(getManager(), return new SQLUpdateActionImpl(getManager(),
"ALTER TABLE " + withBackQuote(getTableName()) + " AUTO_INCREMENT=" + index "ALTER TABLE " + withBackQuote(getTableName()) + " AUTO_INCREMENT=" + index
); );
} }
@Override @Override
public SQLAction<Integer> addIndex(@NotNull IndexType indexType, @NotNull String indexName, @NotNull String columnName, @NotNull String... moreColumns) { public SQLAction<Integer> addIndex(@NotNull IndexType indexType, @Nullable String indexName,
return createAction( @NotNull String columnName, @NotNull String... moreColumns) {
"ALTER TABLE " + withBackQuote(getTableName()) + " ADD " Objects.requireNonNull(indexType, "indexType could not be null");
+ TableCreateBuilderImpl.buildIndexSettings(indexType, indexName, columnName, moreColumns) Objects.requireNonNull(columnName, "column names could not be null");
); Objects.requireNonNull(moreColumns, "column names could not be null");
} return createAction(
"ALTER TABLE " + withBackQuote(getTableName()) + " ADD "
+ TableCreateBuilderImpl.buildIndexSettings(indexType, indexName, columnName, moreColumns)
);
}
@Override @Override
public SQLAction<Integer> dropIndex(@NotNull String indexName) { public SQLAction<Integer> dropIndex(@NotNull String indexName) {
return createAction( Objects.requireNonNull(indexName, "indexName could not be null");
"ALTER TABLE " + withBackQuote(getTableName()) + " DROP INDEX " + withBackQuote(indexName) return createAction(
); "ALTER TABLE " + withBackQuote(getTableName()) + " DROP INDEX " + withBackQuote(indexName)
} );
}
@Override @Override
public SQLAction<Integer> dropForeignKey(@NotNull String keySymbol) { public SQLAction<Integer> dropForeignKey(@NotNull String keySymbol) {
return createAction( Objects.requireNonNull(keySymbol, "keySymbol could not be null");
"ALTER TABLE " + withBackQuote(getTableName()) + " DROP FOREIGN KEY " + withBackQuote(keySymbol) return createAction(
); "ALTER TABLE " + withBackQuote(getTableName()) + " DROP FOREIGN KEY " + withBackQuote(keySymbol)
} );
}
@Override @Override
public SQLAction<Integer> dropPrimaryKey() { public SQLAction<Integer> dropPrimaryKey() {
return createAction( return createAction(
"ALTER TABLE " + withBackQuote(getTableName()) + " DROP PRIMARY KEY" "ALTER TABLE " + withBackQuote(getTableName()) + " DROP PRIMARY KEY"
); );
} }
@Override @Override
public SQLAction<Integer> addColumn(@NotNull String columnName, @NotNull String settings, @Nullable String afterColumn) { public SQLAction<Integer> addColumn(@NotNull String columnName, @NotNull String settings, @Nullable String afterColumn) {
String orderSettings = null; Objects.requireNonNull(columnName, "columnName could not be null");
if (afterColumn != null) { Objects.requireNonNull(settings, "settings could not be null");
if (afterColumn.length() > 0) { String orderSettings = null;
orderSettings = "AFTER " + withBackQuote(afterColumn); if (afterColumn != null) {
} else { if (afterColumn.length() > 0) {
orderSettings = "FIRST"; orderSettings = "AFTER " + withBackQuote(afterColumn);
} } else {
} orderSettings = "FIRST";
}
}
return createAction( return createAction(
"ALTER TABLE " + withBackQuote(getTableName()) + " ADD " + withBackQuote(columnName) + " " + settings "ALTER TABLE " + withBackQuote(getTableName()) + " ADD " + withBackQuote(columnName) + " " + settings
+ (orderSettings != null ? " " + orderSettings : "") + (orderSettings != null ? " " + orderSettings : "")
); );
} }
@Override @Override
public SQLAction<Integer> renameColumn(@NotNull String columnName, @NotNull String newName) { public SQLAction<Integer> renameColumn(@NotNull String columnName, @NotNull String newName) {
return createAction( Objects.requireNonNull(columnName, "columnName could not be null");
"ALTER TABLE " + withBackQuote(getTableName()) + " RENAME COLUMN " + withBackQuote(columnName) + " TO " + withBackQuote(newName) Objects.requireNonNull(newName, "please specify new column name");
); return createAction(
} "ALTER TABLE " + withBackQuote(getTableName()) + " RENAME COLUMN " + withBackQuote(columnName) + " TO " + withBackQuote(newName)
);
}
@Override @Override
public SQLAction<Integer> modifyColumn(@NotNull String columnName, @NotNull String settings) { public SQLAction<Integer> modifyColumn(@NotNull String columnName, @NotNull String settings) {
return createAction( Objects.requireNonNull(columnName, "columnName could not be null");
"ALTER TABLE " + withBackQuote(getTableName()) + " MODIFY COLUMN " + withBackQuote(columnName) + " " + settings Objects.requireNonNull(settings, "please specify new column settings");
); return createAction(
} "ALTER TABLE " + withBackQuote(getTableName()) + " MODIFY COLUMN " + withBackQuote(columnName) + " " + settings
);
}
@Override @Override
public SQLAction<Integer> removeColumn(@NotNull String columnName) { public SQLAction<Integer> removeColumn(@NotNull String columnName) {
return createAction( Objects.requireNonNull(columnName, "columnName could not be null");
"ALTER TABLE " + withBackQuote(getTableName()) + " DROP " + withBackQuote(columnName) return createAction(
); "ALTER TABLE " + withBackQuote(getTableName()) + " DROP " + withBackQuote(columnName)
} );
}
@Override @Override
public SQLAction<Integer> setColumnDefault(@NotNull String columnName, @NotNull String defaultValue) { public SQLAction<Integer> setColumnDefault(@NotNull String columnName, @NotNull String defaultValue) {
return createAction( Objects.requireNonNull(columnName, "columnName could not be null");
"ALTER TABLE " + withBackQuote(getTableName()) + " ALTER " + withBackQuote(columnName) + " SET DEFAULT " + defaultValue Objects.requireNonNull(defaultValue, "defaultValue could not be null, if you need to remove the default value, please use #removeColumnDefault().");
); return createAction(
} "ALTER TABLE " + withBackQuote(getTableName()) + " ALTER " + withBackQuote(columnName) + " SET DEFAULT " + defaultValue
);
}
@Override @Override
public SQLAction<Integer> removeColumnDefault(@NotNull String columnName) { public SQLAction<Integer> removeColumnDefault(@NotNull String columnName) {
return createAction( Objects.requireNonNull(columnName, "columnName could not be null");
"ALTER TABLE " + withBackQuote(getTableName()) + " ALTER " + withBackQuote(columnName) + " DROP DEFAULT" return createAction(
); "ALTER TABLE " + withBackQuote(getTableName()) + " ALTER " + withBackQuote(columnName) + " DROP DEFAULT"
} );
}
private SQLUpdateActionImpl createAction(@NotNull String sql) { private SQLUpdateActionImpl createAction(@NotNull String sql) {
return new SQLUpdateActionImpl(getManager(), sql); return new SQLUpdateActionImpl(getManager(), sql);
} }
} }
@@ -14,148 +14,159 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects;
import static cc.carm.lib.easysql.api.SQLBuilder.withBackQuote; import static cc.carm.lib.easysql.api.SQLBuilder.withBackQuote;
import static cc.carm.lib.easysql.api.SQLBuilder.withQuote; import static cc.carm.lib.easysql.api.SQLBuilder.withQuote;
public class TableCreateBuilderImpl extends AbstractSQLBuilder implements TableCreateBuilder { public class TableCreateBuilderImpl extends AbstractSQLBuilder implements TableCreateBuilder {
protected final @NotNull String tableName; protected final @NotNull String tableName;
@NotNull
final List<String> indexes = new ArrayList<>();
@NotNull
final List<String> foreignKeys = new ArrayList<>();
@NotNull List<String> columns = new ArrayList<>();
@NotNull String tableSettings = defaultTablesSettings();
@Nullable String tableComment;
@NotNull List<String> columns = new ArrayList<>(); public TableCreateBuilderImpl(SQLManagerImpl manager, @NotNull String tableName) {
@NotNull List<String> indexes = new ArrayList<>(); super(manager);
@NotNull List<String> foreignKeys = new ArrayList<>(); this.tableName = tableName;
}
@NotNull String tableSettings = defaultTablesSettings(); protected static String buildIndexSettings(@NotNull IndexType indexType, @Nullable String indexName,
@Nullable String tableComment; @NotNull String columnName, @NotNull String... moreColumns) {
Objects.requireNonNull(indexType, "indexType could not be null");
Objects.requireNonNull(columnName, "column names could not be null");
Objects.requireNonNull(moreColumns, "column names could not be null");
StringBuilder indexBuilder = new StringBuilder();
public TableCreateBuilderImpl(SQLManagerImpl manager, @NotNull String tableName) { indexBuilder.append(indexType.getName()).append(" ");
super(manager); if (indexName != null) {
this.tableName = tableName; indexBuilder.append(withBackQuote(indexName));
} }
indexBuilder.append("(");
indexBuilder.append(withBackQuote(columnName));
@Override if (moreColumns.length > 0) {
public @NotNull String getTableName() { indexBuilder.append(", ");
return this.tableName;
}
@Override for (int i = 0; i < moreColumns.length; i++) {
public @NotNull String getTableSettings() { indexBuilder.append(withBackQuote(moreColumns[i]));
return this.tableSettings; if (i != moreColumns.length - 1) indexBuilder.append(", ");
} }
@Override }
public SQLUpdateAction build() {
StringBuilder createSQL = new StringBuilder();
createSQL.append("CREATE TABLE IF NOT EXISTS ").append(withBackQuote(tableName));
createSQL.append("(");
createSQL.append(String.join(", ", columns));
if (indexes.size() > 0) {
createSQL.append(", ");
createSQL.append(String.join(", ", indexes));
}
if (foreignKeys.size() > 0) {
createSQL.append(", ");
createSQL.append(String.join(", ", foreignKeys));
}
createSQL.append(") ").append(getTableSettings());
if (tableComment != null) { indexBuilder.append(")");
createSQL.append(" COMMENT ").append(withQuote(tableComment));
}
return new SQLUpdateActionImpl(getManager(), createSQL.toString()); return indexBuilder.toString();
} }
@Override @Override
public TableCreateBuilder addColumn(@NotNull String column) { public @NotNull String getTableName() {
this.columns.add(column); return this.tableName;
return this; }
}
@Override @Override
public TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, @Nullable NumberType numberType, public @NotNull String getTableSettings() {
boolean asPrimaryKey, boolean unsigned) { return this.tableSettings;
return addColumn(columnName, }
(numberType == null ? NumberType.INT : numberType).name()
+ (unsigned ? " UNSIGNED " : " ")
+ "NOT NULL AUTO_INCREMENT " + (asPrimaryKey ? "PRIMARY KEY" : "UNIQUE KEY")
);
}
@Override @Override
public TableCreateBuilder setIndex(@NotNull IndexType type, @Nullable String indexName, public SQLUpdateAction build() {
@NotNull String columnName, @NotNull String... moreColumns) { StringBuilder createSQL = new StringBuilder();
this.indexes.add(buildIndexSettings(type, indexName, columnName, moreColumns)); createSQL.append("CREATE TABLE IF NOT EXISTS ").append(withBackQuote(tableName));
return this; createSQL.append("(");
} createSQL.append(String.join(", ", columns));
if (indexes.size() > 0) {
createSQL.append(", ");
createSQL.append(String.join(", ", indexes));
}
if (foreignKeys.size() > 0) {
createSQL.append(", ");
createSQL.append(String.join(", ", foreignKeys));
}
createSQL.append(") ").append(getTableSettings());
@Override if (tableComment != null) {
public TableCreateBuilder addForeignKey(@NotNull String tableColumn, @Nullable String constraintName, createSQL.append(" COMMENT ").append(withQuote(tableComment));
@NotNull String foreignTable, @NotNull String foreignColumn, }
@Nullable ForeignKeyRule updateRule, @Nullable ForeignKeyRule deleteRule) {
StringBuilder keyBuilder = new StringBuilder();
keyBuilder.append("CONSTRAINT "); return new SQLUpdateActionImpl(getManager(), createSQL.toString());
if (constraintName == null) { }
keyBuilder.append(withBackQuote("fk_" + tableColumn + "_" + foreignTable));
} else {
keyBuilder.append(withBackQuote(constraintName));
}
keyBuilder.append(" ");
keyBuilder.append("FOREIGN KEY (").append(withBackQuote(tableColumn)).append(") ");
keyBuilder.append("REFERENCES ").append(withBackQuote(foreignTable)).append("(").append(withBackQuote(foreignColumn)).append(")");
if (updateRule != null) keyBuilder.append(" ON UPDATE ").append(updateRule.getRuleName()); @Override
if (deleteRule != null) keyBuilder.append(" ON DELETE ").append(deleteRule.getRuleName()); public TableCreateBuilder addColumn(@NotNull String column) {
Objects.requireNonNull(column, "column could not be null");
this.columns.add(column);
return this;
}
this.foreignKeys.add(keyBuilder.toString()); @Override
return this; public TableCreateBuilder addAutoIncrementColumn(@NotNull String columnName, @Nullable NumberType numberType,
} boolean asPrimaryKey, boolean unsigned) {
return addColumn(columnName,
(numberType == null ? NumberType.INT : numberType).name()
+ (unsigned ? " UNSIGNED " : " ")
+ "NOT NULL AUTO_INCREMENT " + (asPrimaryKey ? "PRIMARY KEY" : "UNIQUE KEY")
);
}
@Override @Override
public TableCreateBuilder setColumns(@NotNull String... columns) { public TableCreateBuilder setIndex(@NotNull IndexType type, @Nullable String indexName,
this.columns = Arrays.asList(columns); @NotNull String columnName, @NotNull String... moreColumns) {
return this; Objects.requireNonNull(columnName, "columnName could not be null");
} this.indexes.add(buildIndexSettings(type, indexName, columnName, moreColumns));
return this;
}
@Override @Override
public TableCreateBuilder setTableSettings(@NotNull String settings) { public TableCreateBuilder addForeignKey(@NotNull String tableColumn, @Nullable String constraintName,
this.tableSettings = settings; @NotNull String foreignTable, @NotNull String foreignColumn,
return this; @Nullable ForeignKeyRule updateRule, @Nullable ForeignKeyRule deleteRule) {
} Objects.requireNonNull(tableColumn, "tableColumn could not be null");
Objects.requireNonNull(foreignTable, "foreignTable could not be null");
Objects.requireNonNull(foreignColumn, "foreignColumn could not be null");
@Override StringBuilder keyBuilder = new StringBuilder();
public TableCreateBuilder setTableComment(@Nullable String comment) {
this.tableComment = comment;
return this;
}
protected static String buildIndexSettings(@NotNull IndexType indexType, @Nullable String indexName, keyBuilder.append("CONSTRAINT ");
@NotNull String columnName, @NotNull String... moreColumns) { if (constraintName == null) {
keyBuilder.append(withBackQuote("fk_" + tableColumn + "_" + foreignTable));
} else {
keyBuilder.append(withBackQuote(constraintName));
}
keyBuilder.append(" ");
keyBuilder.append("FOREIGN KEY (").append(withBackQuote(tableColumn)).append(") ");
keyBuilder.append("REFERENCES ").append(withBackQuote(foreignTable)).append("(").append(withBackQuote(foreignColumn)).append(")");
StringBuilder indexBuilder = new StringBuilder(); if (updateRule != null) keyBuilder.append(" ON UPDATE ").append(updateRule.getRuleName());
if (deleteRule != null) keyBuilder.append(" ON DELETE ").append(deleteRule.getRuleName());
indexBuilder.append(indexType.getName()).append(" "); this.foreignKeys.add(keyBuilder.toString());
if (indexName != null) { return this;
indexBuilder.append(withBackQuote(indexName)); }
}
indexBuilder.append("(");
indexBuilder.append(withBackQuote(columnName));
if (moreColumns.length > 0) { @Override
indexBuilder.append(", "); public TableCreateBuilder setColumns(@NotNull String... columns) {
Objects.requireNonNull(columns, "columns could not be null");
this.columns = Arrays.asList(columns);
return this;
}
for (int i = 0; i < moreColumns.length; i++) { @Override
indexBuilder.append(withBackQuote(moreColumns[i])); public TableCreateBuilder setTableSettings(@NotNull String settings) {
if (i != moreColumns.length - 1) indexBuilder.append(", "); Objects.requireNonNull(settings, "settings could not be null");
} this.tableSettings = settings;
return this;
}
} @Override
public TableCreateBuilder setTableComment(@Nullable String comment) {
indexBuilder.append(")"); this.tableComment = comment;
return this;
return indexBuilder.toString(); }
}
} }
@@ -12,81 +12,83 @@ import java.util.Objects;
import static cc.carm.lib.easysql.api.SQLBuilder.withBackQuote; import static cc.carm.lib.easysql.api.SQLBuilder.withBackQuote;
public class TableQueryBuilderImpl public class TableQueryBuilderImpl
extends AbstractConditionalBuilder<TableQueryBuilder, PreparedQueryAction> extends AbstractConditionalBuilder<TableQueryBuilder, PreparedQueryAction>
implements TableQueryBuilder { implements TableQueryBuilder {
@NotNull String tableName;
String[] columns;
@Nullable String orderBy;
int[] pageLimit;
public TableQueryBuilderImpl(@NotNull SQLManagerImpl manager, @NotNull String tableName) {
super(manager);
this.tableName = tableName;
}
@Override
public PreparedQueryActionImpl build() {
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("SELECT").append(" ");
if (columns == null || columns.length < 1) {
sqlBuilder.append("*");
} else {
for (int i = 0; i < columns.length; i++) {
String name = columns[i];
sqlBuilder.append(withBackQuote(name));
if (i != columns.length - 1) {
sqlBuilder.append(",");
}
}
}
sqlBuilder.append(" ").append("FROM").append(" ").append(withBackQuote(tableName));
if (hasConditions()) sqlBuilder.append(" ").append(buildConditionSQL());
if (orderBy != null) sqlBuilder.append(" ").append(orderBy);
if (pageLimit != null && pageLimit.length == 2) {
sqlBuilder.append(" LIMIT ").append(pageLimit[0]).append(",").append(pageLimit[1]);
} else if (limit > 0) {
sqlBuilder.append(" ").append(buildLimitSQL());
}
return new PreparedQueryActionImpl(getManager(), sqlBuilder.toString()) protected final @NotNull String tableName;
.setParams(hasConditionParams() ? getConditionParams() : null);
}
@Override String[] columns;
public @NotNull String getTableName() {
return tableName;
}
@Override @Nullable String orderBy;
public TableQueryBuilderImpl selectColumns(@NotNull String... columnNames) {
this.columns = columnNames;
return this;
}
@Override int[] pageLimit;
public TableQueryBuilder orderBy(@NotNull String columnName, boolean asc) {
Objects.requireNonNull(columnName, "columnName could not be null");
this.orderBy = "ORDER BY " + withBackQuote(columnName) + " " + (asc ? "ASC" : "DESC");
return this;
}
@Override public TableQueryBuilderImpl(@NotNull SQLManagerImpl manager, @NotNull String tableName) {
public TableQueryBuilder setPageLimit(int start, int end) { super(manager);
this.pageLimit = new int[]{start, end}; this.tableName = tableName;
return this; }
}
@Override @Override
protected TableQueryBuilderImpl getThis() { public PreparedQueryActionImpl build() {
return this; StringBuilder sqlBuilder = new StringBuilder();
} sqlBuilder.append("SELECT").append(" ");
if (columns == null || columns.length < 1) {
sqlBuilder.append("*");
} else {
for (int i = 0; i < columns.length; i++) {
String name = columns[i];
sqlBuilder.append(withBackQuote(name));
if (i != columns.length - 1) {
sqlBuilder.append(",");
}
}
}
sqlBuilder.append(" ").append("FROM").append(" ").append(withBackQuote(tableName));
if (hasConditions()) sqlBuilder.append(" ").append(buildConditionSQL());
if (orderBy != null) sqlBuilder.append(" ").append(orderBy);
if (pageLimit != null && pageLimit.length == 2) {
sqlBuilder.append(" LIMIT ").append(pageLimit[0]).append(",").append(pageLimit[1]);
} else if (limit > 0) {
sqlBuilder.append(" ").append(buildLimitSQL());
}
return new PreparedQueryActionImpl(getManager(), sqlBuilder.toString())
.setParams(hasConditionParams() ? getConditionParams() : null);
}
@Override
public @NotNull String getTableName() {
return tableName;
}
@Override
public TableQueryBuilderImpl selectColumns(@NotNull String... columnNames) {
Objects.requireNonNull(columnNames, "columnNames could not be null");
this.columns = columnNames;
return this;
}
@Override
public TableQueryBuilder orderBy(@NotNull String columnName, boolean asc) {
Objects.requireNonNull(columnName, "columnName could not be null");
this.orderBy = "ORDER BY " + withBackQuote(columnName) + " " + (asc ? "ASC" : "DESC");
return this;
}
@Override
public TableQueryBuilder setPageLimit(int start, int end) {
this.pageLimit = new int[]{start, end};
return this;
}
@Override
protected TableQueryBuilderImpl getThis() {
return this;
}
} }
@@ -16,7 +16,7 @@ public class UpdateBuilderImpl
extends AbstractConditionalBuilder<UpdateBuilder, SQLAction<Integer>> extends AbstractConditionalBuilder<UpdateBuilder, SQLAction<Integer>>
implements UpdateBuilder { implements UpdateBuilder {
String tableName; protected final @NotNull String tableName;
@NotNull LinkedHashMap<String, Object> columnData; @NotNull LinkedHashMap<String, Object> columnData;
@@ -51,7 +51,7 @@ public class UpdateBuilderImpl
} }
@Override @Override
public String getTableName() { public @NotNull String getTableName() {
return tableName; return tableName;
} }
@@ -26,169 +26,168 @@ import java.util.logging.Logger;
public class SQLManagerImpl implements SQLManager { public class SQLManagerImpl implements SQLManager {
private final Logger LOGGER; private final Logger LOGGER;
private final DataSource dataSource; private final DataSource dataSource;
protected ExecutorService executorPool; private final ConcurrentHashMap<UUID, SQLQuery> activeQuery = new ConcurrentHashMap<>();
ConcurrentHashMap<UUID, SQLQuery> activeQuery = new ConcurrentHashMap<>(); protected ExecutorService executorPool;
@NotNull Supplier<Boolean> debugMode = () -> Boolean.FALSE;
@NotNull Supplier<Boolean> debugMode = () -> false; public SQLManagerImpl(@NotNull DataSource dataSource) {
this(dataSource, null);
}
public SQLManagerImpl(@NotNull DataSource dataSource) { public SQLManagerImpl(@NotNull DataSource dataSource, @Nullable String name) {
this(dataSource, null); String managerName = "SQLManager" + (name != null ? "#" + name : "");
} this.LOGGER = Logger.getLogger(managerName);
this.dataSource = dataSource;
this.executorPool = Executors.newFixedThreadPool(3, r -> {
Thread thread = new Thread(r, managerName);
thread.setDaemon(true);
return thread;
});
}
public SQLManagerImpl(@NotNull DataSource dataSource, @Nullable String name) { @Override
String managerName = "SQLManager" + (name != null ? "#" + name : ""); public boolean isDebugMode() {
this.LOGGER = Logger.getLogger(managerName); return this.debugMode.get();
this.dataSource = dataSource; }
this.executorPool = Executors.newFixedThreadPool(3, r -> {
Thread thread = new Thread(r, managerName);
thread.setDaemon(true);
return thread;
});
}
@Override @Override
public boolean isDebugMode() { public void setDebugMode(@NotNull Supplier<@NotNull Boolean> debugMode) {
return this.debugMode.get(); this.debugMode = debugMode;
} }
@Override public void debug(String msg) {
public void setDebugMode(@NotNull Supplier<@NotNull Boolean> debugMode) { if (isDebugMode()) getLogger().info("[DEBUG] " + msg);
this.debugMode = debugMode; }
}
public void debug(String msg) { @Override
if (isDebugMode()) getLogger().info("[DEBUG] " + msg); public Logger getLogger() {
} return LOGGER;
}
@Override public ExecutorService getExecutorPool() {
public Logger getLogger() { return executorPool;
return LOGGER; }
}
public ExecutorService getExecutorPool() { @Override
return executorPool; public @NotNull DataSource getDataSource() {
} return this.dataSource;
}
@Override @Override
public @NotNull DataSource getDataSource() { public @NotNull Connection getConnection() throws SQLException {
return this.dataSource; return getDataSource().getConnection();
} }
@Override @Override
public @NotNull Connection getConnection() throws SQLException { public @NotNull Map<UUID, SQLQuery> getActiveQuery() {
return getDataSource().getConnection(); return this.activeQuery;
} }
@Override @Override
public @NotNull Map<UUID, SQLQuery> getActiveQuery() { public Integer executeSQL(String sql) {
return this.activeQuery; return new SQLUpdateActionImpl(this, sql).execute(null);
} }
@Override @Override
public Integer executeSQL(String sql) { public Integer executeSQL(String sql, Object[] params) {
return new SQLUpdateActionImpl(this, sql).execute(null); return new PreparedSQLUpdateActionImpl(this, sql, params).execute(null);
} }
@Override @Override
public Integer executeSQL(String sql, Object[] params) { public List<Integer> executeSQLBatch(String sql, Iterable<Object[]> paramsBatch) {
return new PreparedSQLUpdateActionImpl(this, sql, params).execute(null); return new PreparedSQLBatchUpdateActionImpl(this, sql)
} .setAllParams(paramsBatch)
.execute(null);
}
@Override @Override
public List<Integer> executeSQLBatch(String sql, Iterable<Object[]> paramsBatch) { public List<Integer> executeSQLBatch(@NotNull String sql, String... moreSQL) {
return new PreparedSQLBatchUpdateActionImpl(this, sql) SQLUpdateBatchAction action = new SQLUpdateBatchActionImpl(this, sql);
.setAllParams(paramsBatch) if (moreSQL != null && moreSQL.length > 0) {
.execute(null); Arrays.stream(moreSQL).forEach(action::addBatch);
} }
return action.execute(null);
}
@Override @Override
public List<Integer> executeSQLBatch(@NotNull String sql, String... moreSQL) { public @Nullable List<Integer> executeSQLBatch(@NotNull Iterable<String> sqlBatch) {
SQLUpdateBatchAction action = new SQLUpdateBatchActionImpl(this, sql); Iterator<String> iterator = sqlBatch.iterator();
if (moreSQL != null && moreSQL.length > 0) { if (!iterator.hasNext()) return null; // PLEASE GIVE IT SOMETHING
Arrays.stream(moreSQL).forEach(action::addBatch);
}
return action.execute(null);
}
@Override SQLUpdateBatchAction action = new SQLUpdateBatchActionImpl(this, iterator.next());
public @Nullable List<Integer> executeSQLBatch(@NotNull Iterable<String> sqlBatch) { while (iterator.hasNext()) {
Iterator<String> iterator = sqlBatch.iterator(); action.addBatch(iterator.next());
if (!iterator.hasNext()) return null; // PLEASE GIVE IT SOMETHING }
SQLUpdateBatchAction action = new SQLUpdateBatchActionImpl(this, iterator.next()); return action.execute(null);
while (iterator.hasNext()) { }
action.addBatch(iterator.next());
}
return action.execute(null); @Override
} public TableCreateBuilder createTable(@NotNull String tableName) {
return new TableCreateBuilderImpl(this, tableName);
}
@Override @Override
public TableCreateBuilder createTable(@NotNull String tableName) { public TableAlterBuilder alterTable(@NotNull String tableName) {
return new TableCreateBuilderImpl(this, tableName); return new TableAlterBuilderImpl(this, tableName);
} }
@Override @Override
public TableAlterBuilder alterTable(@NotNull String tableName) { public QueryBuilder createQuery() {
return new TableAlterBuilderImpl(this, tableName); return new QueryBuilderImpl(this);
} }
@Override @Override
public QueryBuilder createQuery() { public InsertBuilder<PreparedSQLUpdateBatchAction> createInsertBatch(@NotNull String tableName) {
return new QueryBuilderImpl(this); return new InsertBuilderImpl<PreparedSQLUpdateBatchAction>(this, tableName) {
} @Override
public PreparedSQLUpdateBatchAction setColumnNames(List<String> columnNames) {
return new PreparedSQLBatchUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames));
}
};
}
@Override @Override
public InsertBuilder<PreparedSQLUpdateBatchAction> createInsertBatch(@NotNull String tableName) { public InsertBuilder<PreparedSQLUpdateAction> createInsert(@NotNull String tableName) {
return new InsertBuilderImpl<PreparedSQLUpdateBatchAction>(this, tableName) { return new InsertBuilderImpl<PreparedSQLUpdateAction>(this, tableName) {
@Override @Override
public PreparedSQLUpdateBatchAction setColumnNames(List<String> columnNames) { public PreparedSQLUpdateAction setColumnNames(List<String> columnNames) {
return new PreparedSQLBatchUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames)); return new PreparedSQLUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames));
} }
}; };
} }
@Override @Override
public InsertBuilder<PreparedSQLUpdateAction> createInsert(@NotNull String tableName) { public ReplaceBuilder<PreparedSQLUpdateBatchAction> createReplaceBatch(@NotNull String tableName) {
return new InsertBuilderImpl<PreparedSQLUpdateAction>(this, tableName) { return new ReplaceBuilderImpl<PreparedSQLUpdateBatchAction>(this, tableName) {
@Override @Override
public PreparedSQLUpdateAction setColumnNames(List<String> columnNames) { public PreparedSQLUpdateBatchAction setColumnNames(List<String> columnNames) {
return new PreparedSQLUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames)); return new PreparedSQLBatchUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames));
} }
}; };
} }
@Override @Override
public ReplaceBuilder<PreparedSQLUpdateBatchAction> createReplaceBatch(@NotNull String tableName) { public ReplaceBuilder<PreparedSQLUpdateAction> createReplace(@NotNull String tableName) {
return new ReplaceBuilderImpl<PreparedSQLUpdateBatchAction>(this, tableName) { return new ReplaceBuilderImpl<PreparedSQLUpdateAction>(this, tableName) {
@Override @Override
public PreparedSQLUpdateBatchAction setColumnNames(List<String> columnNames) { public PreparedSQLUpdateAction setColumnNames(List<String> columnNames) {
return new PreparedSQLBatchUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames)); return new PreparedSQLUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames));
} }
}; };
} }
@Override @Override
public ReplaceBuilder<PreparedSQLUpdateAction> createReplace(@NotNull String tableName) { public UpdateBuilder createUpdate(@NotNull String tableName) {
return new ReplaceBuilderImpl<PreparedSQLUpdateAction>(this, tableName) { return new UpdateBuilderImpl(this, tableName);
@Override }
public PreparedSQLUpdateAction setColumnNames(List<String> columnNames) {
return new PreparedSQLUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames));
}
};
}
@Override @Override
public UpdateBuilder createUpdate(@NotNull String tableName) { public DeleteBuilder createDelete(@NotNull String tableName) {
return new UpdateBuilderImpl(this, tableName); return new DeleteBuilderImpl(this, tableName);
} }
@Override
public DeleteBuilder createDelete(@NotNull String tableName) {
return new DeleteBuilderImpl(this, tableName);
}
} }
@@ -11,85 +11,83 @@ import java.sql.Statement;
public class SQLQueryImpl implements SQLQuery { public class SQLQueryImpl implements SQLQuery {
protected final long executeTime; protected final long executeTime;
protected SQLManagerImpl sqlManager; protected final SQLManagerImpl sqlManager;
protected QueryActionImpl queryAction; final Connection connection;
final Statement statement;
final ResultSet resultSet;
protected QueryActionImpl queryAction;
Connection connection; public SQLQueryImpl(
Statement statement; SQLManagerImpl sqlManager, QueryActionImpl queryAction,
Connection connection, Statement statement, ResultSet resultSet
) {
this(sqlManager, queryAction, connection, statement, resultSet, System.currentTimeMillis());
}
ResultSet resultSet; public SQLQueryImpl(
SQLManagerImpl sqlManager, QueryActionImpl queryAction,
Connection connection, Statement statement, ResultSet resultSet,
long executeTime
) {
this.executeTime = executeTime;
this.sqlManager = sqlManager;
this.queryAction = queryAction;
this.connection = connection;
this.statement = statement;
this.resultSet = resultSet;
}
public SQLQueryImpl( @Override
SQLManagerImpl sqlManager, QueryActionImpl queryAction, public long getExecuteTime() {
Connection connection, Statement statement, ResultSet resultSet return this.executeTime;
) { }
this(sqlManager, queryAction, connection, statement, resultSet, System.currentTimeMillis());
}
public SQLQueryImpl( @Override
SQLManagerImpl sqlManager, QueryActionImpl queryAction, public SQLManagerImpl getManager() {
Connection connection, Statement statement, ResultSet resultSet, return this.sqlManager;
long executeTime }
) {
this.executeTime = executeTime;
this.sqlManager = sqlManager;
this.queryAction = queryAction;
this.connection = connection;
this.statement = statement;
this.resultSet = resultSet;
}
@Override @Override
public long getExecuteTime() { public QueryActionImpl getAction() {
return this.executeTime; return this.queryAction;
} }
@Override @Override
public SQLManagerImpl getManager() { public ResultSet getResultSet() {
return this.sqlManager; return this.resultSet;
} }
@Override @Override
public QueryActionImpl getAction() { public String getSQLContent() {
return this.queryAction; return getAction().getSQLContent();
} }
@Override @Override
public ResultSet getResultSet() { public void close() {
return this.resultSet; try {
} if (getResultSet() != null && !getResultSet().isClosed()) getResultSet().close();
if (getStatement() != null && !getStatement().isClosed()) getStatement().close();
if (getConnection() != null && !getConnection().isClosed()) getConnection().close();
@Override getManager().debug("#" + getAction().getShortID() +
public String getSQLContent() { " -> finished after " + (System.currentTimeMillis() - getExecuteTime()) + " ms."
return getAction().getSQLContent(); );
} getManager().getActiveQuery().remove(getAction().getActionUUID());
} catch (SQLException e) {
getAction().handleException(getAction().defaultExceptionHandler(), e);
}
this.queryAction = null;
}
@Override @Override
public void close() { public Statement getStatement() {
try { return this.statement;
if (getResultSet() != null) getResultSet().close(); }
if (getStatement() != null) getStatement().close();
if (getConnection() != null) getConnection().close();
getManager().debug("#" + getAction().getShortID() + @Override
" -> finished after " + (System.currentTimeMillis() - getExecuteTime()) + " ms." public Connection getConnection() {
); return this.connection;
getManager().getActiveQuery().remove(getAction().getActionUUID()); }
} catch (SQLException e) {
getAction().handleException(getAction().defaultExceptionHandler(), e);
}
this.queryAction = null;
}
@Override
public Statement getStatement() {
return this.statement;
}
@Override
public Connection getConnection() {
return this.connection;
}
} }
@@ -10,201 +10,201 @@ import java.util.UUID;
public class StatementUtil { public class StatementUtil {
/** /**
* 创建一个 {@link PreparedStatement} 。 * 创建一个 {@link PreparedStatement} 。
* *
* @param connection 数据库连接 * @param connection 数据库连接
* @param sql SQL语句,使用"?"做为占位符 * @param sql SQL语句,使用"?"做为占位符
* @param params "?"所代表的对应参数列表 * @param params "?"所代表的对应参数列表
* @return 完成参数填充的 {@link PreparedStatement} * @return 完成参数填充的 {@link PreparedStatement}
*/ */
public static PreparedStatement createPrepareStatement( public static PreparedStatement createPrepareStatement(
Connection connection, String sql, Object[] params Connection connection, String sql, Object[] params
) throws SQLException { ) throws SQLException {
return createPrepareStatement(connection, sql, params, false); return createPrepareStatement(connection, sql, params, false);
} }
/** /**
* 创建一个 {@link PreparedStatement} 。 * 创建一个 {@link PreparedStatement} 。
* *
* @param connection 数据库连接 * @param connection 数据库连接
* @param sql SQL语句,使用"?"做为占位符 * @param sql SQL语句,使用"?"做为占位符
* @param params "?"所代表的对应参数列表 * @param params "?"所代表的对应参数列表
* @param returnGeneratedKey 是否会返回自增主键 * @param returnGeneratedKey 是否会返回自增主键
* @return 完成参数填充的 {@link PreparedStatement} * @return 完成参数填充的 {@link PreparedStatement}
*/ */
public static PreparedStatement createPrepareStatement( public static PreparedStatement createPrepareStatement(
Connection connection, String sql, Object[] params, boolean returnGeneratedKey Connection connection, String sql, Object[] params, boolean returnGeneratedKey
) throws SQLException { ) throws SQLException {
sql = sql.trim(); sql = sql.trim();
PreparedStatement statement = connection.prepareStatement(sql, returnGeneratedKey ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS); PreparedStatement statement = connection.prepareStatement(sql, returnGeneratedKey ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS);
Map<Integer, Integer> nullTypeMap = new HashMap<>(); Map<Integer, Integer> nullTypeMap = new HashMap<>();
if (params != null) fillParams(statement, Arrays.asList(params), nullTypeMap); if (params != null) fillParams(statement, Arrays.asList(params), nullTypeMap);
statement.addBatch(); statement.addBatch();
return statement; return statement;
} }
/** /**
* 创建批量操作的一个 {@link PreparedStatement} 。 * 创建批量操作的一个 {@link PreparedStatement} 。
* *
* @param connection 数据库连接 * @param connection 数据库连接
* @param sql SQL语句,使用"?"做为占位符 * @param sql SQL语句,使用"?"做为占位符
* @param paramsBatch "?"所代表的对应参数列表 * @param paramsBatch "?"所代表的对应参数列表
* @return 完成参数填充的 {@link PreparedStatement} * @return 完成参数填充的 {@link PreparedStatement}
*/ */
public static PreparedStatement createPrepareStatementBatch( public static PreparedStatement createPrepareStatementBatch(
Connection connection, String sql, Iterable<Object[]> paramsBatch Connection connection, String sql, Iterable<Object[]> paramsBatch
) throws SQLException { ) throws SQLException {
return createPrepareStatementBatch(connection, sql, paramsBatch, false); return createPrepareStatementBatch(connection, sql, paramsBatch, false);
} }
/** /**
* 创建批量操作的一个 {@link PreparedStatement} 。 * 创建批量操作的一个 {@link PreparedStatement} 。
* *
* @param connection 数据库连接 * @param connection 数据库连接
* @param sql SQL语句,使用"?"做为占位符 * @param sql SQL语句,使用"?"做为占位符
* @param paramsBatch "?"所代表的对应参数列表 * @param paramsBatch "?"所代表的对应参数列表
* @param returnGeneratedKey 是否会返回自增主键 * @param returnGeneratedKey 是否会返回自增主键
* @return 完成参数填充的 {@link PreparedStatement} * @return 完成参数填充的 {@link PreparedStatement}
*/ */
public static PreparedStatement createPrepareStatementBatch( public static PreparedStatement createPrepareStatementBatch(
Connection connection, String sql, Iterable<Object[]> paramsBatch, boolean returnGeneratedKey Connection connection, String sql, Iterable<Object[]> paramsBatch, boolean returnGeneratedKey
) throws SQLException { ) throws SQLException {
sql = sql.trim(); sql = sql.trim();
PreparedStatement statement = connection.prepareStatement(sql, returnGeneratedKey ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS); PreparedStatement statement = connection.prepareStatement(sql, returnGeneratedKey ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS);
Map<Integer, Integer> nullTypeMap = new HashMap<>(); Map<Integer, Integer> nullTypeMap = new HashMap<>();
for (Object[] params : paramsBatch) { for (Object[] params : paramsBatch) {
fillParams(statement, Arrays.asList(params), nullTypeMap); fillParams(statement, Arrays.asList(params), nullTypeMap);
statement.addBatch(); statement.addBatch();
} }
return statement; return statement;
} }
/** /**
* 填充PreparedStatement的参数。 * 填充PreparedStatement的参数。
* *
* @param statement PreparedStatement * @param statement PreparedStatement
* @param params SQL参数 * @param params SQL参数
* @return {@link PreparedStatement} 填充参数后的PreparedStatement * @return {@link PreparedStatement} 填充参数后的PreparedStatement
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
*/ */
public static PreparedStatement fillParams( public static PreparedStatement fillParams(
PreparedStatement statement, Iterable<?> params PreparedStatement statement, Iterable<?> params
) throws SQLException { ) throws SQLException {
return fillParams(statement, params, null); return fillParams(statement, params, null);
} }
/** /**
* 填充PreparedStatement的参数。 * 填充PreparedStatement的参数。
* *
* @param statement PreparedStatement * @param statement PreparedStatement
* @param params SQL参数 * @param params SQL参数
* @param nullCache null参数的类型缓存,避免循环中重复获取类型 * @param nullCache null参数的类型缓存,避免循环中重复获取类型
* @return 完成参数填充的 {@link PreparedStatement} * @return 完成参数填充的 {@link PreparedStatement}
*/ */
public static PreparedStatement fillParams( public static PreparedStatement fillParams(
PreparedStatement statement, Iterable<?> params, Map<Integer, Integer> nullCache PreparedStatement statement, Iterable<?> params, Map<Integer, Integer> nullCache
) throws SQLException { ) throws SQLException {
if (null == params) { if (null == params) {
return statement;// 无参数 return statement;// 无参数
} }
int paramIndex = 1;//第一个参数从1计数 int paramIndex = 1;//第一个参数从1计数
for (Object param : params) { for (Object param : params) {
setParam(statement, paramIndex++, param, nullCache); setParam(statement, paramIndex++, param, nullCache);
} }
return statement; return statement;
} }
/** /**
* 获取null字段对应位置的数据类型 * 获取null字段对应位置的数据类型
* 如果类型获取失败将使用默认的 {@link Types#VARCHAR} * 如果类型获取失败将使用默认的 {@link Types#VARCHAR}
* *
* @param statement {@link PreparedStatement} * @param statement {@link PreparedStatement}
* @param paramIndex 参数序列,第一位从1开始 * @param paramIndex 参数序列,第一位从1开始
* @return 数据类型,默认为 {@link Types#VARCHAR} * @return 数据类型,默认为 {@link Types#VARCHAR}
*/ */
public static int getNullType(PreparedStatement statement, int paramIndex) { public static int getNullType(PreparedStatement statement, int paramIndex) {
try { try {
ParameterMetaData pmd = statement.getParameterMetaData(); ParameterMetaData pmd = statement.getParameterMetaData();
return pmd.getParameterType(paramIndex); return pmd.getParameterType(paramIndex);
} catch (SQLException ignore) { } catch (SQLException ignore) {
return Types.VARCHAR; return Types.VARCHAR;
} }
} }
/** /**
* 为 {@link PreparedStatement} 设置单个参数 * 为 {@link PreparedStatement} 设置单个参数
* *
* @param preparedStatement {@link PreparedStatement} * @param preparedStatement {@link PreparedStatement}
* @param paramIndex 参数序列,从1开始 * @param paramIndex 参数序列,从1开始
* @param param 参数,不能为{@code null} * @param param 参数,不能为{@code null}
* @param nullCache 用于缓存参数为null位置的类型,避免重复获取 * @param nullCache 用于缓存参数为null位置的类型,避免重复获取
*/ */
private static void setParam( private static void setParam(
PreparedStatement preparedStatement, int paramIndex, Object param, PreparedStatement preparedStatement, int paramIndex, Object param,
Map<Integer, Integer> nullCache Map<Integer, Integer> nullCache
) throws SQLException { ) throws SQLException {
if (param == null) { if (param == null) {
Integer type = (null == nullCache) ? null : nullCache.get(paramIndex); Integer type = (null == nullCache) ? null : nullCache.get(paramIndex);
if (null == type) { if (null == type) {
type = getNullType(preparedStatement, paramIndex); type = getNullType(preparedStatement, paramIndex);
if (null != nullCache) { if (null != nullCache) {
nullCache.put(paramIndex, type); nullCache.put(paramIndex, type);
} }
} }
preparedStatement.setNull(paramIndex, type); preparedStatement.setNull(paramIndex, type);
} }
// 针对UUID特殊处理,避免元数据直接传入 // 针对UUID特殊处理,避免元数据直接传入
if (param instanceof UUID) { if (param instanceof UUID) {
preparedStatement.setString(paramIndex, param.toString()); preparedStatement.setString(paramIndex, param.toString());
return; return;
} }
// 针对StringBuilder或StringBuffer进行处理,避免元数据传入 // 针对StringBuilder或StringBuffer进行处理,避免元数据传入
if (param instanceof StringBuilder || param instanceof StringBuffer) { if (param instanceof StringBuilder || param instanceof StringBuffer) {
preparedStatement.setString(paramIndex, param.toString()); preparedStatement.setString(paramIndex, param.toString());
return; return;
} }
// 日期特殊处理,默认按照时间戳传入,避免精度丢失 // 日期特殊处理,默认按照时间戳传入,避免精度丢失
if (param instanceof java.util.Date) { if (param instanceof java.util.Date) {
if (param instanceof Date) { if (param instanceof Date) {
preparedStatement.setDate(paramIndex, (Date) param); preparedStatement.setDate(paramIndex, (Date) param);
} else if (param instanceof Time) { } else if (param instanceof Time) {
preparedStatement.setTime(paramIndex, (Time) param); preparedStatement.setTime(paramIndex, (Time) param);
} else { } else {
preparedStatement.setTimestamp(paramIndex, new Timestamp(((java.util.Date) param).getTime())); preparedStatement.setTimestamp(paramIndex, new Timestamp(((java.util.Date) param).getTime()));
} }
return; return;
} }
// 针对大数字类型的特殊处理 // 针对大数字类型的特殊处理
if (param instanceof Number) { if (param instanceof Number) {
if (param instanceof BigDecimal) { if (param instanceof BigDecimal) {
// BigDecimal的转换交给JDBC驱动处理 // BigDecimal的转换交给JDBC驱动处理
preparedStatement.setBigDecimal(paramIndex, (BigDecimal) param); preparedStatement.setBigDecimal(paramIndex, (BigDecimal) param);
return; return;
} else if (param instanceof BigInteger) { } else if (param instanceof BigInteger) {
preparedStatement.setBigDecimal(paramIndex, new BigDecimal((BigInteger) param)); preparedStatement.setBigDecimal(paramIndex, new BigDecimal((BigInteger) param));
return; return;
} }
// 其它数字类型按照默认类型传入 // 其它数字类型按照默认类型传入
} }
if (param instanceof Enum) { if (param instanceof Enum) {
//枚举类采用 name() //枚举类采用 name()
preparedStatement.setString(paramIndex, ((Enum<?>) param).name()); preparedStatement.setString(paramIndex, ((Enum<?>) param).name());
return; return;
} }
// 其它参数类型直接传入 // 其它参数类型直接传入
preparedStatement.setObject(paramIndex, param); preparedStatement.setObject(paramIndex, param);
} }
} }
@@ -1,36 +0,0 @@
package cc.carm.lib.easysql.testrunner;
import cc.carm.lib.easysql.api.SQLManager;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.sql.SQLException;
public abstract class EasySQLTest {
@ApiStatus.OverrideOnly
public abstract void onTest(SQLManager sqlManager) throws SQLException;
public boolean executeTest(int index, SQLManager sqlManager) {
String testName = getClass().getSimpleName();
print(" #%s 测试 @%s 开始", index, testName);
long start = System.currentTimeMillis();
try {
onTest(sqlManager);
print(" #%s 测试 @%s 成功,耗时 %s ms。", index, testName, (System.currentTimeMillis() - start));
return true;
} catch (Exception exception) {
print(" #%s 测试 @%s 失败,耗时 %s ms。", index, testName, (System.currentTimeMillis() - start));
exception.printStackTrace();
return false;
}
}
protected static void print(@NotNull String format, Object... params) {
Main.print(format, params);
}
}
@@ -1,93 +0,0 @@
package cc.carm.lib.easysql.testrunner;
import cc.carm.lib.easysql.EasySQL;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.testrunner.tests.DeleteTest;
import cc.carm.lib.easysql.testrunner.tests.QueryCloseTest;
import cc.carm.lib.easysql.testrunner.tests.QueryFunctionTest;
import cc.carm.lib.easysql.testrunner.tests.TableCreateTest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Scanner;
import java.util.Set;
@TestOnly
@SuppressWarnings("all")
public class Main {
public static void main(String[] args) {
if (args.length < 4) {
print("请提供以下参数:<数据库驱动> <数据库地址(JDBC)> <数据库用户> <数据库密码> [是否采用DEBUG(y/n)]");
return;
}
SQLManager sqlManager;
try {
print("初始化 SQLManager...");
print("数据库驱动 %s", args[0]);
print("数据库地址 %s", args[1]);
print("数据库用户 %s", args[2]);
print("数据库密码 %s", args[3]);
sqlManager = EasySQL.createManager(args[0], args[1], args[2], args[3]);
sqlManager.setDebugMode(args.length > 4);
print("SQLManager 初始化完成!");
} catch (Exception exception) {
print("SQLManager 初始化失败,请检查数据库配置。");
exception.printStackTrace();
return;
}
print("加载测试类...");
Set<EasySQLTest> tests = new LinkedHashSet<>();
tests.add(new TableCreateTest());
// tests.add(new TableAlterTest());
// tests.add(new TableRenameTest());
// tests.add(new QueryNotCloseTest());
tests.add(new QueryCloseTest());
// tests.add(new SQLUpdateBatchTests());
// tests.add(new SQLUpdateReturnKeysTest());
tests.add(new QueryFunctionTest());
tests.add(new DeleteTest());
print("准备进行测试...");
int index = 1;
int success = 0;
Iterator<EasySQLTest> testIterator = tests.iterator();
print("准备完成,请按回车键开始执行测试。");
while (testIterator.hasNext()) {
Scanner scanner = new Scanner(System.in);
if (scanner.nextLine() != null) {
EasySQLTest currentTest = testIterator.next();
if (currentTest.executeTest(index, sqlManager)) {
success++;
}
index++;
}
}
print(" ");
print("全部测试执行完毕,成功 %s 个,失败 %s 个。",
success, (tests.size() - success)
);
EasySQL.shutdownManager(sqlManager);
}
public static void print(@NotNull String format, Object... params) {
System.out.printf((format) + "%n", params);
}
}
@@ -1,22 +0,0 @@
package cc.carm.lib.easysql.testrunner.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.testrunner.EasySQLTest;
import java.sql.SQLException;
public class DeleteTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
Integer changes = sqlManager.createDelete("test_user_table")
.addCondition("id", ">", 5)
.addNotNullCondition("username")
.build().execute();
System.out.println("change(s): " + changes);
}
}
@@ -1,31 +0,0 @@
package cc.carm.lib.easysql.testrunner.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.SQLQuery;
import cc.carm.lib.easysql.testrunner.EasySQLTest;
import java.sql.ResultSet;
import java.sql.SQLException;
public class QueryCloseTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
try (SQLQuery query = sqlManager.createQuery()
.inTable("test_user_table")
.orderBy("id", false)
.setLimit(5)
.build().execute()) {
ResultSet resultSet = query.getResultSet();
while (resultSet.next()) {
System.out.println("id: " + resultSet.getInt("id") + " username: " + resultSet.getString("username"));
}
}
}
}
@@ -1,34 +0,0 @@
package cc.carm.lib.easysql.testrunner.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.testrunner.EasySQLTest;
import java.sql.SQLException;
public class QueryFunctionTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
Integer id_1 = sqlManager.createQuery()
.inTable("test_user_table")
.orderBy("id", false)
.setLimit(1)
.build().executeFunction(query -> {
if (!query.getResultSet().next()) return -1;
else return query.getResultSet().getInt("id");
});
System.out.println("id (ps): " + id_1);
Integer id_2 = sqlManager.createQuery().withSQL("SELECT id FROM test_user_table ORDER BY id DESC LIMIT 1")
.executeFunction(query -> {
if (!query.getResultSet().next()) return -1;
else return query.getResultSet().getInt("id");
});
System.out.println("id (s): " + id_2);
}
}
@@ -1,30 +0,0 @@
package cc.carm.lib.easysql.testrunner.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.SQLQuery;
import cc.carm.lib.easysql.testrunner.EasySQLTest;
import java.sql.ResultSet;
import java.sql.SQLException;
public class QueryNotCloseTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
SQLQuery query = sqlManager.createQuery()
.inTable("test_user_table")
.orderBy("id", false)
.setLimit(5)
.build().execute();
ResultSet resultSet = query.getResultSet();
while (resultSet.next()) {
System.out.println("id: " + resultSet.getInt("id") + " username: " + resultSet.getString("username"));
}
}
}
@@ -1,38 +0,0 @@
package cc.carm.lib.easysql.testrunner.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.testrunner.EasySQLTest;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class SQLUpdateBatchTests extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
List<Integer> updates = sqlManager.createInsertBatch("test_user_table")
.setColumnNames("uuid", "username", "age")
.setAllParams(generateParams())
.execute();
System.out.println("changes " + Arrays.toString(updates.toArray()));
}
protected List<Object[]> generateParams() {
return IntStream.range(0, 5).mapToObj(i -> generateParam()).collect(Collectors.toList());
}
protected Object[] generateParam() {
UUID uuid = UUID.randomUUID();
return new Object[]{uuid, uuid.toString().substring(0, 5), (int) (Math.random() * 50)};
}
}
@@ -1,24 +0,0 @@
package cc.carm.lib.easysql.testrunner.tests;
import cc.carm.lib.easysql.api.SQLManager;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
public class SQLUpdateReturnKeysTest extends SQLUpdateBatchTests {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
List<Integer> generatedKeys = sqlManager.createInsertBatch("test_user_table")
.setColumnNames("uuid", "username", "age")
.setAllParams(generateParams())
.returnGeneratedKeys()
.execute();
System.out.println("generated " + Arrays.toString(generatedKeys.toArray()));
}
}
@@ -1,35 +0,0 @@
package cc.carm.lib.easysql.testrunner.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.enums.NumberType;
import cc.carm.lib.easysql.testrunner.EasySQLTest;
import java.sql.SQLException;
public class TableAlterTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
print(" 修改 test_user_table");
sqlManager.alterTable("test_user_table")
.addColumn("test", "VARCHAR(16) NOT NULL")
.execute();
sqlManager.alterTable("test_user_table")
.addColumn("test2", "VARCHAR(16) NOT NULL", "username")
.execute();
print(" 修改 test_user_info");
sqlManager.alterTable("test_user_info")
.addAutoIncrementColumn("num", NumberType.BIGINT, false, true)
.execute();
sqlManager.alterTable("test_user_info")
.addColumn("a", "VARCHAR(16) NOT NULL", "")
.execute();
}
}
@@ -1,38 +0,0 @@
package cc.carm.lib.easysql.testrunner.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.enums.ForeignKeyRule;
import cc.carm.lib.easysql.api.enums.IndexType;
import cc.carm.lib.easysql.testrunner.EasySQLTest;
import java.sql.SQLException;
public class TableCreateTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
print(" 创建 test_user_table");
sqlManager.createTable("test_user_table")
.addAutoIncrementColumn("id")
.addColumn("uuid", "VARCHAR(36) NOT NULL", "用户UUID")
.addColumn("username", "VARCHAR(16) NOT NULL", "用户名")
.addColumn("age", "TINYINT DEFAULT 0 NOT NULL", "年龄")
.setIndex("uuid", IndexType.UNIQUE_KEY)
.build().execute();
print(" 创建 test_user_info");
sqlManager.createTable("test_user_info")
.addColumn("uid", "INT UNSIGNED NOT NULL")
.addColumn("info", "TEXT", "相关信息")
.addForeignKey("uid", "user",
"test_user_table", "id",
ForeignKeyRule.CASCADE, ForeignKeyRule.CASCADE
)
.setIndex(IndexType.FULLTEXT_INDEX, "sign", "info")
.build().execute();
}
}
@@ -1,16 +0,0 @@
package cc.carm.lib.easysql.testrunner.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.testrunner.EasySQLTest;
import java.sql.SQLException;
public class TableRenameTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
print(" 重命名 test_user_table");
sqlManager.alterTable("test_user_table")
.renameTo("test_user_table2")
.execute();
}
}
@@ -115,7 +115,7 @@
</descriptorRefs> </descriptorRefs>
<archive> <archive>
<manifest> <manifest>
<mainClass>cc.carm.lib.easysql.testrunner.Main</mainClass> <mainClass>cc.carm.lib.easysql.tester.Main</mainClass>
</manifest> </manifest>
</archive> </archive>
</configuration> </configuration>
@@ -0,0 +1,36 @@
package cc.carm.lib.easysql.tester;
import cc.carm.lib.easysql.api.SQLManager;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.sql.SQLException;
public abstract class EasySQLTest {
protected static void print(@NotNull String format, Object... params) {
Main.print(format, params);
}
@ApiStatus.OverrideOnly
public abstract void onTest(SQLManager sqlManager) throws SQLException;
public boolean executeTest(int index, SQLManager sqlManager) {
String testName = getClass().getSimpleName();
print(" #%s 测试 @%s 开始", index, testName);
long start = System.currentTimeMillis();
try {
onTest(sqlManager);
print(" #%s 测试 @%s 成功,耗时 %s ms。", index, testName, (System.currentTimeMillis() - start));
return true;
} catch (Exception exception) {
print(" #%s 测试 @%s 失败,耗时 %s ms。", index, testName, (System.currentTimeMillis() - start));
exception.printStackTrace();
return false;
}
}
}
@@ -0,0 +1,93 @@
package cc.carm.lib.easysql.tester;
import cc.carm.lib.easysql.EasySQL;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.tester.tests.DeleteTest;
import cc.carm.lib.easysql.tester.tests.QueryCloseTest;
import cc.carm.lib.easysql.tester.tests.QueryFunctionTest;
import cc.carm.lib.easysql.tester.tests.TableCreateTest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Scanner;
import java.util.Set;
@TestOnly
@SuppressWarnings("all")
public class Main {
public static void main(String[] args) {
if (args.length < 4) {
print("请提供以下参数:<数据库驱动> <数据库地址(JDBC)> <数据库用户> <数据库密码> [是否采用DEBUG(y/n)]");
return;
}
SQLManager sqlManager;
try {
print("初始化 SQLManager...");
print("数据库驱动 %s", args[0]);
print("数据库地址 %s", args[1]);
print("数据库用户 %s", args[2]);
print("数据库密码 %s", args[3]);
sqlManager = EasySQL.createManager(args[0], args[1], args[2], args[3]);
sqlManager.setDebugMode(args.length > 4);
print("SQLManager 初始化完成!");
} catch (Exception exception) {
print("SQLManager 初始化失败,请检查数据库配置。");
exception.printStackTrace();
return;
}
print("加载测试类...");
Set<EasySQLTest> tests = new LinkedHashSet<>();
tests.add(new TableCreateTest());
// tests.add(new TableAlterTest());
// tests.add(new TableRenameTest());
// tests.add(new QueryNotCloseTest());
tests.add(new QueryCloseTest());
// tests.add(new SQLUpdateBatchTests());
// tests.add(new SQLUpdateReturnKeysTest());
tests.add(new QueryFunctionTest());
tests.add(new DeleteTest());
print("准备进行测试...");
int index = 1;
int success = 0;
Iterator<EasySQLTest> testIterator = tests.iterator();
print("准备完成,请按回车键开始执行测试。");
while (testIterator.hasNext()) {
Scanner scanner = new Scanner(System.in);
if (scanner.nextLine() != null) {
EasySQLTest currentTest = testIterator.next();
if (currentTest.executeTest(index, sqlManager)) {
success++;
}
index++;
}
}
print(" ");
print("全部测试执行完毕,成功 %s 个,失败 %s 个。",
success, (tests.size() - success)
);
EasySQL.shutdownManager(sqlManager);
}
public static void print(@NotNull String format, Object... params) {
System.out.printf((format) + "%n", params);
}
}
@@ -0,0 +1,22 @@
package cc.carm.lib.easysql.tester.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.tester.EasySQLTest;
import java.sql.SQLException;
public class DeleteTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
Integer changes = sqlManager.createDelete("test_user_table")
.addCondition("id", ">", 5)
.addNotNullCondition("username")
.build().execute();
System.out.println("change(s): " + changes);
}
}
@@ -0,0 +1,35 @@
package cc.carm.lib.easysql.tester.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.SQLQuery;
import cc.carm.lib.easysql.tester.EasySQLTest;
import java.sql.ResultSet;
import java.sql.SQLException;
public class QueryCloseTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
try (SQLQuery query = sqlManager.createQuery()
.inTable("test_user_table")
.orderBy("id", false)
.setLimit(5)
.build().execute()) {
ResultSet resultSet = query.getResultSet();
while (resultSet.next()) {
System.out.printf(
"id: %d username: %s%n",
resultSet.getInt("id"),
resultSet.getString("username")
);
}
}
}
}
@@ -0,0 +1,26 @@
package cc.carm.lib.easysql.tester.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.tester.EasySQLTest;
import java.sql.SQLException;
public class QueryFunctionTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
Integer id_1 = sqlManager.createQuery()
.inTable("test_user_table")
.orderBy("id", false)
.setLimit(1)
.build().executeFunction(query -> {
if (!query.getResultSet().next()) return -1;
else return query.getResultSet().getInt("id");
});
System.out.println("id (ps): " + id_1);
}
}
@@ -0,0 +1,30 @@
package cc.carm.lib.easysql.tester.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.SQLQuery;
import cc.carm.lib.easysql.tester.EasySQLTest;
import java.sql.ResultSet;
import java.sql.SQLException;
public class QueryNotCloseTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
SQLQuery query = sqlManager.createQuery()
.inTable("test_user_table")
.orderBy("id", false)
.setLimit(5)
.build().execute();
ResultSet resultSet = query.getResultSet();
while (resultSet.next()) {
System.out.printf("id: %d username: %s%n", resultSet.getInt("id"), resultSet.getString("username"));
}
}
}
@@ -0,0 +1,38 @@
package cc.carm.lib.easysql.tester.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.tester.EasySQLTest;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class SQLUpdateBatchTests extends EasySQLTest {
protected static List<Object[]> generateParams() {
return IntStream.range(0, 5).mapToObj(i -> generateParam()).collect(Collectors.toList());
}
protected static Object[] generateParam() {
UUID uuid = UUID.randomUUID();
return new Object[]{uuid, uuid.toString().substring(0, 5), (int) (Math.random() * 50)};
}
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
List<Integer> updates = sqlManager.createInsertBatch("test_user_table")
.setColumnNames("uuid", "username", "age")
.setAllParams(generateParams())
.execute();
System.out.println("changes " + Arrays.toString(updates.toArray()));
}
}
@@ -0,0 +1,24 @@
package cc.carm.lib.easysql.tester.tests;
import cc.carm.lib.easysql.api.SQLManager;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
public class SQLUpdateReturnKeysTest extends SQLUpdateBatchTests {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
List<Integer> generatedKeys = sqlManager.createInsertBatch("test_user_table")
.setColumnNames("uuid", "username", "age")
.setAllParams(generateParams())
.returnGeneratedKeys()
.execute();
System.out.println("generated " + Arrays.toString(generatedKeys.toArray()));
}
}
@@ -0,0 +1,35 @@
package cc.carm.lib.easysql.tester.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.enums.NumberType;
import cc.carm.lib.easysql.tester.EasySQLTest;
import java.sql.SQLException;
public class TableAlterTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
print(" 修改 test_user_table");
sqlManager.alterTable("test_user_table")
.addColumn("test", "VARCHAR(16) NOT NULL")
.execute();
sqlManager.alterTable("test_user_table")
.addColumn("test2", "VARCHAR(16) NOT NULL", "username")
.execute();
print(" 修改 test_user_info");
sqlManager.alterTable("test_user_info")
.addAutoIncrementColumn("num", NumberType.BIGINT, false, true)
.execute();
sqlManager.alterTable("test_user_info")
.addColumn("a", "VARCHAR(16) NOT NULL", "")
.execute();
}
}
@@ -0,0 +1,38 @@
package cc.carm.lib.easysql.tester.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.enums.ForeignKeyRule;
import cc.carm.lib.easysql.api.enums.IndexType;
import cc.carm.lib.easysql.tester.EasySQLTest;
import java.sql.SQLException;
public class TableCreateTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
print(" 创建 test_user_table");
sqlManager.createTable("test_user_table")
.addAutoIncrementColumn("id")
.addColumn("uuid", "VARCHAR(36) NOT NULL", "用户UUID")
.addColumn("username", "VARCHAR(16) NOT NULL", "用户名")
.addColumn("age", "TINYINT DEFAULT 0 NOT NULL", "年龄")
.setIndex("uuid", IndexType.UNIQUE_KEY)
.build().execute();
print(" 创建 test_user_info");
sqlManager.createTable("test_user_info")
.addColumn("uid", "INT UNSIGNED NOT NULL")
.addColumn("info", "TEXT", "相关信息")
.addForeignKey("uid", "user",
"test_user_table", "id",
ForeignKeyRule.CASCADE, ForeignKeyRule.CASCADE
)
.setIndex(IndexType.FULLTEXT_INDEX, "sign", "info")
.build().execute();
}
}
@@ -0,0 +1,16 @@
package cc.carm.lib.easysql.tester.tests;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.tester.EasySQLTest;
import java.sql.SQLException;
public class TableRenameTest extends EasySQLTest {
@Override
public void onTest(SQLManager sqlManager) throws SQLException {
print(" 重命名 test_user_table");
sqlManager.alterTable("test_user_table")
.renameTo("test_user_table2")
.execute();
}
}
+1
View File
@@ -72,6 +72,7 @@
<!--项目地址 https://github.com/brettwooldridge/HikariCP/ --> <!--项目地址 https://github.com/brettwooldridge/HikariCP/ -->
<groupId>com.zaxxer</groupId> <groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId> <artifactId>HikariCP</artifactId>
<!--suppress MavenPackageUpdate -->
<version>4.0.3</version> <version>4.0.3</version>
<optional>true</optional> <optional>true</optional>
<scope>compile</scope> <scope>compile</scope>