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

初始版本完成

This commit is contained in:
2021-12-14 05:39:38 +08:00
parent 0f20ae2913
commit 6f278ee8b0
49 changed files with 2312 additions and 54 deletions
+2 -34
View File
@@ -5,14 +5,14 @@
<parent>
<artifactId>easysql-parent</artifactId>
<groupId>cc.carm.lib</groupId>
<version>1.0.0</version>
<version>v0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>easysql-impl</artifactId>
<packaging>jar</packaging>
<name>EasySQL-Impl</name>
<name>01-EasySQL-Impl</name>
<description>EasySQL的实现部分。</description>
<url>https://github.com/CarmJos/${project.parent.name}</url>
@@ -44,38 +44,10 @@
<scope>compile</scope>
</dependency>
<dependency>
<!-- https://github.com/alibaba/fastjson -->
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<!--项目地址 https://github.com/Chris2018998/BeeCP -->
<groupId>com.github.chris2018998</groupId>
<artifactId>beecp</artifactId>
<version>3.3.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
@@ -92,10 +64,6 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
</plugins>
</build>
@@ -1,7 +0,0 @@
package cc.carm.lib.easysql;
public class EasySQL {
}
@@ -0,0 +1,82 @@
package cc.carm.lib.easysql.action;
import cc.carm.lib.easysql.api.SQLAction;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
import java.sql.SQLException;
import java.util.UUID;
import java.util.function.Consumer;
public abstract class AbstractSQLAction<T> implements SQLAction<T> {
private final @NotNull SQLManagerImpl sqlManager;
private final @NotNull UUID uuid;
private final long createTime;
protected @NotNull String sqlContent;
protected @NotNull Consumer<SQLException> exceptionHandler = defaultExceptionHandler();
public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql) {
this(manager, sql, System.currentTimeMillis());
}
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, long createTime) {
this(manager, sql, UUID.randomUUID(), createTime);
}
public AbstractSQLAction(@NotNull SQLManagerImpl manager, @NotNull String sql,
@NotNull UUID uuid, long createTime) {
this.sqlManager = manager;
this.sqlContent = sql;
this.uuid = uuid;
this.createTime = createTime;
}
@Override
public @NotNull UUID getActionUUID() {
return this.uuid;
}
@Override
public @NotNull String getShortID() {
return getActionUUID().toString().substring(0, 8);
}
@Override
public long getCreateTime() {
return this.createTime;
}
@Override
public @NotNull String getSQLContent() {
return this.sqlContent.trim();
}
@Override
public @NotNull SQLManagerImpl getManager() {
return this.sqlManager;
}
protected void outputDebugMessage() {
getManager().debug("#" + getShortID() + " ->" + getSQLContent());
}
@Override
public SQLAction<T> handleException(Consumer<SQLException> handler) {
this.exceptionHandler = handler;
return this;
}
@NotNull
public Consumer<SQLException> getExceptionHandler() {
return exceptionHandler;
}
}
@@ -0,0 +1,79 @@
package cc.carm.lib.easysql.action;
import cc.carm.lib.easysql.api.action.PreparedSQLUpdateBatchAction;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import cc.carm.lib.easysql.util.StatementUtil;
import org.jetbrains.annotations.NotNull;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class PreparedSQLBatchUpdateActionImpl extends SQLUpdateBatchActionImpl implements PreparedSQLUpdateBatchAction {
int keyIndex = -1;
List<Object[]> allParams;
public PreparedSQLBatchUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
super(manager, sql);
this.allParams = new ArrayList<>();
}
@Override
public PreparedSQLUpdateBatchAction setAllParams(Iterable<Object[]> allParams) {
List<Object[]> paramsList = new ArrayList<>();
allParams.forEach(paramsList::add);
this.allParams = paramsList;
return this;
}
@Override
public PreparedSQLUpdateBatchAction addParamsBatch(Object[] params) {
this.allParams.add(params);
return this;
}
@Override
public PreparedSQLUpdateBatchAction setKeyIndex(int keyColumnIndex) {
this.keyIndex = keyColumnIndex;
return this;
}
@Override
public @NotNull List<Integer> execute() throws SQLException {
List<Integer> returnedValues;
Connection connection = getManager().getConnection();
PreparedStatement statement = StatementUtil.createPrepareStatementBatch(
connection, getSQLContent(), allParams, keyIndex > 0
);
outputDebugMessage();
if (keyIndex > 0) {
List<Integer> generatedKeys = new ArrayList<>();
ResultSet resultSet = statement.getGeneratedKeys();
if (resultSet != null) {
while (resultSet.next()) generatedKeys.add(resultSet.getInt(keyIndex));
resultSet.close();
}
returnedValues = generatedKeys;
} else {
int[] executed = statement.executeBatch();
returnedValues = Arrays.stream(executed).boxed().collect(Collectors.toList());
}
statement.close();
connection.close();
return returnedValues;
}
@Override
public void executeAsync(Consumer<List<Integer>> success, Consumer<SQLException> failure) {
}
}
@@ -0,0 +1,71 @@
package cc.carm.lib.easysql.action;
import cc.carm.lib.easysql.api.action.PreparedSQLUpdateAction;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import cc.carm.lib.easysql.util.StatementUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.function.Consumer;
public class PreparedSQLUpdateActionImpl extends SQLUpdateActionImpl implements PreparedSQLUpdateAction {
Object[] params;
public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
this(manager, sql, (Object[]) null);
}
public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql,
@Nullable List<Object> params) {
this(manager, sql, params == null ? null : params.toArray());
}
public PreparedSQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql,
@Nullable Object[] params) {
super(manager, sql);
this.params = params;
}
@Override
public PreparedSQLUpdateActionImpl setParams(Object[] params) {
this.params = params;
return this;
}
@Override
public @NotNull Integer execute() throws SQLException {
int value = -1;
Connection connection = getManager().getConnection();
PreparedStatement statement = StatementUtil.createPrepareStatement(
connection, getSQLContent(), params, keyIndex > 0
);
outputDebugMessage();
if (keyIndex > 0) {
ResultSet resultSet = statement.getGeneratedKeys();
if (resultSet != null) {
if (resultSet.next()) value = resultSet.getInt(keyIndex);
resultSet.close();
}
} else {
value = statement.executeUpdate(getSQLContent());
}
statement.close();
connection.close();
return value;
}
@Override
public void executeAsync(Consumer<Integer> success, Consumer<SQLException> failure) {
}
}
@@ -0,0 +1,57 @@
package cc.carm.lib.easysql.action;
import cc.carm.lib.easysql.api.action.SQLUpdateAction;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.function.Consumer;
public class SQLUpdateActionImpl extends AbstractSQLAction<Integer> implements SQLUpdateAction {
int keyIndex = -1;
public SQLUpdateActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
super(manager, sql);
}
@Override
public @NotNull Integer execute() throws SQLException {
int returnedValue = -1;
Connection connection = getManager().getConnection();
Statement statement = connection.createStatement();
outputDebugMessage();
if (keyIndex > 0) {
statement.executeUpdate(getSQLContent(), Statement.RETURN_GENERATED_KEYS);
ResultSet resultSet = statement.getGeneratedKeys();
if (resultSet != null) {
if (resultSet.next()) {
returnedValue = resultSet.getInt(keyIndex);
}
resultSet.close();
}
} else {
returnedValue = statement.executeUpdate(getSQLContent());
}
statement.close();
connection.close();
return returnedValue;
}
@Override
public void executeAsync(Consumer<Integer> success, Consumer<SQLException> failure) {
}
@Override
public SQLUpdateActionImpl setKeyIndex(int keyIndex) {
this.keyIndex = keyIndex;
return this;
}
}
@@ -0,0 +1,61 @@
package cc.carm.lib.easysql.action;
import cc.carm.lib.easysql.api.action.SQLUpdateBatchAction;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class SQLUpdateBatchActionImpl extends AbstractSQLAction<List<Integer>> implements SQLUpdateBatchAction {
List<String> sqlContents = new ArrayList<>();
public SQLUpdateBatchActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
super(manager, sql);
this.sqlContents.add(sql);
}
@Override
public @NotNull String getSQLContent() {
return this.sqlContents.stream()
.map(content -> "[" + content + "]" + " ")
.collect(Collectors.joining());
}
@Override
public SQLUpdateBatchAction addBatch(@NotNull String sql) {
this.sqlContents.add(sql);
return this;
}
@Override
public @NotNull List<Integer> execute() throws SQLException {
Connection connection = getManager().getConnection();
Statement statement = connection.createStatement();
outputDebugMessage();
for (String content : this.sqlContents) {
statement.addBatch(content);
}
int[] executed = statement.executeBatch();
List<Integer> returnedValues = Arrays.stream(executed).boxed().collect(Collectors.toList());
statement.close();
connection.close();
return returnedValues;
}
@Override
public void executeAsync(Consumer<List<Integer>> success, Consumer<SQLException> failure) {
}
}
@@ -0,0 +1,76 @@
package cc.carm.lib.easysql.action.query;
import cc.carm.lib.easysql.api.SQLQuery;
import cc.carm.lib.easysql.api.action.query.PreparedQueryAction;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import cc.carm.lib.easysql.query.SQLQueryImpl;
import cc.carm.lib.easysql.util.StatementUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class PreparedQueryActionImpl extends QueryActionImpl implements PreparedQueryAction {
Consumer<PreparedStatement> handler;
Object[] params;
public PreparedQueryActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
super(manager, sql);
}
@Override
public PreparedQueryActionImpl setParams(@Nullable Object[] params) {
this.params = params;
return this;
}
@Override
public PreparedQueryActionImpl setParams(@Nullable Iterable<Object> params) {
if (params == null) {
return setParams((Object[]) null);
} else {
List<Object> paramsList = new ArrayList<>();
for (Object param : params) {
paramsList.add(param);
}
return setParams(paramsList.toArray());
}
}
@Override
public PreparedQueryActionImpl handleStatement(@Nullable Consumer<PreparedStatement> statement) {
this.handler = statement;
return this;
}
@Override
public @NotNull SQLQueryImpl execute() throws SQLException {
Connection connection = getManager().getConnection();
getManager().debug("#" + getShortID() + " ->" + getSQLContent());
PreparedStatement preparedStatement;
if (handler == null) {
preparedStatement = StatementUtil.createPrepareStatement(connection, getSQLContent(), this.params);
} else {
preparedStatement = connection.prepareStatement(getSQLContent());
handler.accept(preparedStatement);
}
ResultSet resultSet = preparedStatement.executeQuery();
return new SQLQueryImpl(getManager(), this, connection, preparedStatement, resultSet);
}
@Override
public void executeAsync(Consumer<SQLQuery> success, Consumer<SQLException> failure) {
}
}
@@ -0,0 +1,40 @@
package cc.carm.lib.easysql.action.query;
import cc.carm.lib.easysql.action.AbstractSQLAction;
import cc.carm.lib.easysql.api.SQLQuery;
import cc.carm.lib.easysql.api.action.query.QueryAction;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import cc.carm.lib.easysql.query.SQLQueryImpl;
import org.jetbrains.annotations.NotNull;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.function.Consumer;
public class QueryActionImpl extends AbstractSQLAction<SQLQuery> implements QueryAction {
public QueryActionImpl(@NotNull SQLManagerImpl manager, @NotNull String sql) {
super(manager, sql);
}
@Override
public @NotNull SQLQuery execute() throws SQLException {
Connection connection = getManager().getConnection();
Statement statement = connection.createStatement();
outputDebugMessage();
ResultSet resultSet = statement.executeQuery(getSQLContent());
SQLQueryImpl query = new SQLQueryImpl(getManager(), this, connection, statement, resultSet);
getManager().getActiveQuery().put(getActionUUID(), query);
return query;
}
@Override
public void executeAsync(Consumer<SQLQuery> success, Consumer<SQLException> failure) {
}
}
@@ -0,0 +1,19 @@
package cc.carm.lib.easysql.builder;
import cc.carm.lib.easysql.api.SQLBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
public abstract class AbstractSQLBuilder implements SQLBuilder {
@NotNull SQLManagerImpl sqlManager;
public AbstractSQLBuilder(@NotNull SQLManagerImpl manager) {
this.sqlManager = manager;
}
@Override
public @NotNull SQLManagerImpl getManager() {
return this.sqlManager;
}
}
@@ -0,0 +1,139 @@
package cc.carm.lib.easysql.builder.impl;
import cc.carm.lib.easysql.api.builder.ConditionalBuilder;
import cc.carm.lib.easysql.builder.AbstractSQLBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
public abstract class AbstractConditionalBuilder<T> extends AbstractSQLBuilder implements ConditionalBuilder<T> {
ArrayList<String> conditionSQLs = new ArrayList<>();
ArrayList<Object> conditionParams = new ArrayList<>();
int limit = -1;
public AbstractConditionalBuilder(@NotNull SQLManagerImpl manager) {
super(manager);
}
@Override
public AbstractConditionalBuilder<T> setConditions(@Nullable String condition) {
this.conditionSQLs = new ArrayList<>();
this.conditionParams = new ArrayList<>();
if (condition != null) this.conditionSQLs.add(condition);
return this;
}
@Override
public AbstractConditionalBuilder<T> addCondition(@Nullable String condition) {
this.conditionSQLs.add(condition);
return this;
}
@Override
public AbstractConditionalBuilder<T> addNotNullCondition(@NotNull String queryName) {
return addCondition("`" + queryName + "` IS NOT NULL");
}
@Override
public AbstractConditionalBuilder<T> addCondition(
@NotNull String queryName, @NotNull String operator, @Nullable Object queryValue
) {
addCondition("`" + queryName + "` " + operator + " ?");
this.conditionParams.add(queryValue);
return this;
}
@Override
public AbstractConditionalBuilder<T> addCondition(
@NotNull String[] queryNames, @Nullable Object[] queryValues
) {
if (queryNames.length != queryValues.length) {
throw new RuntimeException("queryNames are not match with queryValues");
}
for (int i = 0; i < queryNames.length; i++) {
addCondition(queryNames[i], queryValues[i]);
}
return this;
}
@Override
public AbstractConditionalBuilder<T> addTimeCondition(
@NotNull String queryName, @Nullable Date startDate, @Nullable Date endDate
) {
if (startDate == null && endDate == null) return this; // 都不限定时间,不用判断了
if (startDate != null) {
addCondition("`" + queryName + "` BETWEEN ? AND ?");
this.conditionParams.add(startDate);
if (endDate != null) {
this.conditionParams.add(endDate);
} else {
if (startDate instanceof java.sql.Date) {
this.conditionParams.add(new java.sql.Date(System.currentTimeMillis()));
} else if (startDate instanceof Time) {
this.conditionParams.add(new Time(System.currentTimeMillis()));
} else {
this.conditionParams.add(new Timestamp(System.currentTimeMillis()));
}
}
} else {
addCondition(queryName, "<=", endDate);
}
return this;
}
@Override
public AbstractConditionalBuilder<T> setConditions(
LinkedHashMap<@NotNull String, @Nullable Object> conditions
) {
conditions.forEach(this::addCondition);
return this;
}
@Override
public AbstractConditionalBuilder<T> setLimit(int limit) {
this.limit = limit;
return this;
}
protected String buildConditionSQL() {
if (!conditionSQLs.isEmpty()) {
StringBuilder conditionBuilder = new StringBuilder();
conditionBuilder.append("WHERE").append(" ");
Iterator<String> iterator = conditionSQLs.iterator();
while (iterator.hasNext()) {
conditionBuilder.append(iterator.next());
if (iterator.hasNext()) conditionBuilder.append(" ");
}
return conditionBuilder.toString();
} else {
return null;
}
}
protected String buildLimitSQL() {
return limit > 0 ? "LIMIT " + limit : "";
}
protected ArrayList<Object> getConditionParams() {
return conditionParams;
}
protected boolean hasConditions() {
return this.conditionSQLs != null && !this.conditionSQLs.isEmpty();
}
protected boolean hasConditionParams() {
return hasConditions() && getConditionParams() != null && !getConditionParams().isEmpty();
}
}
@@ -0,0 +1,42 @@
package cc.carm.lib.easysql.builder.impl;
import cc.carm.lib.easysql.action.PreparedSQLUpdateActionImpl;
import cc.carm.lib.easysql.api.action.PreparedSQLUpdateAction;
import cc.carm.lib.easysql.api.builder.DeleteBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
public class DeleteBuilderImpl
extends AbstractConditionalBuilder<PreparedSQLUpdateAction>
implements DeleteBuilder {
String tableName;
public DeleteBuilderImpl(@NotNull SQLManagerImpl manager, @NotNull String tableName) {
super(manager);
this.tableName = tableName;
}
@Override
public PreparedSQLUpdateAction build() {
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("DELETE FROM `").append(getTableName()).append("`");
if (hasConditions()) sqlBuilder.append(" ").append(buildConditionSQL());
if (limit > 0) sqlBuilder.append(" ").append(buildLimitSQL());
return new PreparedSQLUpdateActionImpl(
getManager(), sqlBuilder.toString(),
hasConditionParams() ? getConditionParams() : null
);
}
@Override
public String getTableName() {
return tableName;
}
}
@@ -0,0 +1,51 @@
package cc.carm.lib.easysql.builder.impl;
import cc.carm.lib.easysql.api.builder.InsertBuilder;
import cc.carm.lib.easysql.builder.AbstractSQLBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
import java.util.List;
public abstract class InsertBuilderImpl<T> extends AbstractSQLBuilder implements InsertBuilder<T> {
String tableName;
public InsertBuilderImpl(@NotNull SQLManagerImpl manager, String tableName) {
super(manager);
this.tableName = tableName;
}
protected static String buildSQL(String tableName, List<String> columnNames) {
int valueLength = columnNames.size();
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("INSERT IGNORE INTO `").append(tableName).append("`(");
Iterator<String> iterator = columnNames.iterator();
while (iterator.hasNext()) {
sqlBuilder.append("`").append(iterator.next()).append("`");
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();
}
public String getTableName() {
return tableName;
}
public InsertBuilderImpl<T> setTableName(String tableName) {
this.tableName = tableName;
return this;
}
}
@@ -0,0 +1,33 @@
package cc.carm.lib.easysql.builder.impl;
import cc.carm.lib.easysql.action.query.PreparedQueryActionImpl;
import cc.carm.lib.easysql.action.query.QueryActionImpl;
import cc.carm.lib.easysql.api.action.query.PreparedQueryAction;
import cc.carm.lib.easysql.api.action.query.QueryAction;
import cc.carm.lib.easysql.api.builder.QueryBuilder;
import cc.carm.lib.easysql.api.builder.TableQueryBuilder;
import cc.carm.lib.easysql.builder.AbstractSQLBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
public class QueryBuilderImpl extends AbstractSQLBuilder implements QueryBuilder {
public QueryBuilderImpl(@NotNull SQLManagerImpl manager) {
super(manager);
}
@Override
public QueryAction withSQL(@NotNull String sql) {
return new QueryActionImpl(getManager(), sql);
}
@Override
public PreparedQueryAction withPreparedSQL(@NotNull String sql) {
return new PreparedQueryActionImpl(getManager(), sql);
}
@Override
public TableQueryBuilder inTable(@NotNull String tableName) {
return new TableQueryBuilderImpl(getManager(), tableName);
}
}
@@ -0,0 +1,51 @@
package cc.carm.lib.easysql.builder.impl;
import cc.carm.lib.easysql.api.builder.ReplaceBuilder;
import cc.carm.lib.easysql.builder.AbstractSQLBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
import java.util.List;
public abstract class ReplaceBuilderImpl<T> extends AbstractSQLBuilder implements ReplaceBuilder<T> {
String tableName;
public ReplaceBuilderImpl(@NotNull SQLManagerImpl manager, String tableName) {
super(manager);
this.tableName = tableName;
}
protected static String buildSQL(String tableName, List<String> columnNames) {
int valueLength = columnNames.size();
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("REPLACE INTO `").append(tableName).append("`(");
Iterator<String> iterator = columnNames.iterator();
while (iterator.hasNext()) {
sqlBuilder.append("`").append(iterator.next()).append("`");
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();
}
public String getTableName() {
return tableName;
}
public ReplaceBuilderImpl<T> setTableName(String tableName) {
this.tableName = tableName;
return this;
}
}
@@ -0,0 +1,77 @@
package cc.carm.lib.easysql.builder.impl;
import cc.carm.lib.easysql.action.SQLUpdateActionImpl;
import cc.carm.lib.easysql.api.action.SQLUpdateAction;
import cc.carm.lib.easysql.api.builder.TableCreateBuilder;
import cc.carm.lib.easysql.builder.AbstractSQLBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TableCreateBuilderImpl extends AbstractSQLBuilder implements TableCreateBuilder {
String tableName;
List<String> columns;
String tableSettings;
public TableCreateBuilderImpl(SQLManagerImpl manager, String tableName) {
super(manager);
this.tableName = tableName;
this.columns = new ArrayList<>();
defaultTablesSettings();
}
@Override
public @NotNull String getTableName() {
return this.tableName;
}
@Override
public @NotNull String getTableSettings() {
return this.tableSettings;
}
@Override
public SQLUpdateAction build() {
StringBuilder createSQL = new StringBuilder();
createSQL.append("CREATE TABLE IF NOT EXISTS `").append(tableName).append("`");
createSQL.append("(");
for (int i = 0; i < columns.size(); i++) {
createSQL.append(columns.get(i));
if (i != columns.size() - 1) createSQL.append(", ");
}
createSQL.append(") ").append(tableSettings);
return new SQLUpdateActionImpl(getManager(), createSQL.toString());
}
@Override
public TableCreateBuilder setTableName(@NotNull String tableName) {
this.tableName = tableName;
return this;
}
@Override
public TableCreateBuilder addColumn(@NotNull String column) {
this.columns.add(column);
return this;
}
@Override
public TableCreateBuilder setColumns(@NotNull String[] columns) {
this.columns = Arrays.asList(columns);
return this;
}
@Override
public TableCreateBuilder setTableSettings(@NotNull String settings) {
this.tableSettings = settings;
return this;
}
}
@@ -0,0 +1,62 @@
package cc.carm.lib.easysql.builder.impl;
import cc.carm.lib.easysql.action.query.PreparedQueryActionImpl;
import cc.carm.lib.easysql.api.action.query.PreparedQueryAction;
import cc.carm.lib.easysql.api.builder.TableQueryBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
public class TableQueryBuilderImpl
extends AbstractConditionalBuilder<PreparedQueryAction>
implements TableQueryBuilder {
@NotNull String tableName;
ArrayList<Object> params = new ArrayList<>();
String[] columns;
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("`").append(name).append("`");
if (i != columns.length - 1) {
sqlBuilder.append(",");
}
}
}
sqlBuilder.append(" ").append("FROM").append(" ");
sqlBuilder.append("`").append(tableName).append("`");
if (hasConditions()) sqlBuilder.append(" ").append(buildConditionSQL());
if (limit > 0) sqlBuilder.append(" ").append(buildLimitSQL());
return new PreparedQueryActionImpl(getManager(), sqlBuilder.toString())
.setParams(hasConditionParams() ? params : null);
}
@Override
public @NotNull String getTableName() {
return tableName;
}
@Override
public TableQueryBuilderImpl selectColumns(@NotNull String[] columnNames) {
this.columns = columnNames;
return this;
}
}
@@ -0,0 +1,76 @@
package cc.carm.lib.easysql.builder.impl;
import cc.carm.lib.easysql.action.PreparedSQLUpdateActionImpl;
import cc.carm.lib.easysql.api.action.PreparedSQLUpdateAction;
import cc.carm.lib.easysql.api.builder.UpdateBuilder;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class UpdateBuilderImpl
extends AbstractConditionalBuilder<PreparedSQLUpdateAction>
implements UpdateBuilder {
String tableName;
List<String> columnNames;
List<Object> columnValues;
public UpdateBuilderImpl(@NotNull SQLManagerImpl manager, @NotNull String tableName) {
super(manager);
this.tableName = tableName;
}
@Override
public PreparedSQLUpdateAction build() {
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("UPDATE `").append(getTableName()).append("` SET ");
Iterator<String> iterator = this.columnNames.iterator();
while (iterator.hasNext()) {
sqlBuilder.append("`").append(iterator.next()).append("` = ?");
if (iterator.hasNext()) sqlBuilder.append(" , ");
}
List<Object> allParams = new ArrayList<>(this.columnValues);
if (hasConditions()) {
sqlBuilder.append(" ").append(buildConditionSQL());
allParams.addAll(getConditionParams());
}
if (limit > 0) sqlBuilder.append(" ").append(buildLimitSQL());
return new PreparedSQLUpdateActionImpl(getManager(), sqlBuilder.toString(), allParams);
}
@Override
public String getTableName() {
return tableName;
}
@Override
public UpdateBuilder setColumnValues(LinkedHashMap<String, Object> columnData) {
this.columnNames = new ArrayList<>();
this.columnValues = new ArrayList<>();
columnData.forEach((name, value) -> {
this.columnNames.add(name);
this.columnValues.add(value);
});
return this;
}
@Override
public UpdateBuilder setColumnValues(String[] columnNames, Object[] columnValues) {
if (columnNames.length != columnValues.length) {
throw new RuntimeException("columnNames are not match with columnValues");
}
this.columnNames = Arrays.asList(columnNames);
this.columnValues = Arrays.asList(columnValues);
return this;
}
}
@@ -0,0 +1,176 @@
package cc.carm.lib.easysql.manager;
import cc.carm.lib.easysql.action.PreparedSQLBatchUpdateActionImpl;
import cc.carm.lib.easysql.action.PreparedSQLUpdateActionImpl;
import cc.carm.lib.easysql.action.SQLUpdateActionImpl;
import cc.carm.lib.easysql.action.SQLUpdateBatchActionImpl;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.SQLQuery;
import cc.carm.lib.easysql.api.action.PreparedSQLUpdateAction;
import cc.carm.lib.easysql.api.action.PreparedSQLUpdateBatchAction;
import cc.carm.lib.easysql.api.action.SQLUpdateBatchAction;
import cc.carm.lib.easysql.api.builder.*;
import cc.carm.lib.easysql.builder.impl.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
public class SQLManagerImpl implements SQLManager {
private final Logger LOGGER;
private final DataSource dataSource;
ConcurrentHashMap<UUID, SQLQuery> activeQuery = new ConcurrentHashMap<>();
boolean debug = false;
public SQLManagerImpl(@NotNull DataSource dataSource) {
this(dataSource, null);
}
public SQLManagerImpl(@NotNull DataSource dataSource, @Nullable String name) {
this.LOGGER = Logger.getLogger("SQLManager" + (name != null ? "#" + name : ""));
this.dataSource = dataSource;
}
@Override
public boolean isDebugMode() {
return this.debug;
}
@Override
public void setDebugMode(boolean enable) {
this.debug = enable;
}
public void debug(String msg) {
if (isDebugMode()) getLogger().info("[DEBUG] " + msg);
}
public Logger getLogger() {
return LOGGER;
}
@Override
public @NotNull DataSource getDataSource() {
return this.dataSource;
}
@Override
public @NotNull Connection getConnection() throws SQLException {
return getDataSource().getConnection();
}
@Override
public @NotNull Map<UUID, SQLQuery> getActiveQuery() {
return this.activeQuery;
}
@Override
public Integer executeSQL(String sql) {
return new SQLUpdateActionImpl(this, sql).execute(null);
}
@Override
public Integer executeSQL(String sql, Object[] params) {
return new PreparedSQLUpdateActionImpl(this, sql, params).execute(null);
}
@Override
public List<Integer> executeSQLBatch(String sql, Iterable<Object[]> paramsBatch) {
return new PreparedSQLBatchUpdateActionImpl(this, sql)
.setAllParams(paramsBatch)
.execute(null);
}
@Override
public List<Integer> executeSQLBatch(@NotNull String sql, String[] moreSQL) {
SQLUpdateBatchAction action = new SQLUpdateBatchActionImpl(this, sql);
if (moreSQL != null && moreSQL.length > 0) {
Arrays.stream(moreSQL).forEach(action::addBatch);
}
return action.execute(null);
}
@Override
public @Nullable List<Integer> executeSQLBatch(@NotNull Iterable<String> sqlBatch) {
Iterator<String> iterator = sqlBatch.iterator();
if (!iterator.hasNext()) return null; // PLEASE GIVE IT SOMETHING
SQLUpdateBatchAction action = new SQLUpdateBatchActionImpl(this, iterator.next());
while (iterator.hasNext()) {
action.addBatch(iterator.next());
}
return action.execute(null);
}
@Override
public TableCreateBuilder createTable(@NotNull String tableName) {
return new TableCreateBuilderImpl(this, tableName);
}
@Override
public QueryBuilder createQuery() {
return new QueryBuilderImpl(this);
}
@Override
public InsertBuilder<PreparedSQLUpdateBatchAction> createInsertBatch(@NotNull String tableName) {
return new InsertBuilderImpl<PreparedSQLUpdateBatchAction>(this, tableName) {
@Override
public PreparedSQLUpdateBatchAction setColumnNames(List<String> columnNames) {
return new PreparedSQLBatchUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames));
}
};
}
@Override
public InsertBuilder<PreparedSQLUpdateAction> createInsert(@NotNull String tableName) {
return new InsertBuilderImpl<PreparedSQLUpdateAction>(this, tableName) {
@Override
public PreparedSQLUpdateAction setColumnNames(List<String> columnNames) {
return new PreparedSQLUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames));
}
};
}
@Override
public ReplaceBuilder<PreparedSQLUpdateBatchAction> createReplaceBatch(@NotNull String tableName) {
return new ReplaceBuilderImpl<PreparedSQLUpdateBatchAction>(this, tableName) {
@Override
public PreparedSQLUpdateBatchAction setColumnNames(List<String> columnNames) {
return new PreparedSQLBatchUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames));
}
};
}
@Override
public ReplaceBuilder<PreparedSQLUpdateAction> createReplace(@NotNull String tableName) {
return new ReplaceBuilderImpl<PreparedSQLUpdateAction>(this, tableName) {
@Override
public PreparedSQLUpdateAction setColumnNames(List<String> columnNames) {
return new PreparedSQLUpdateActionImpl(getManager(), buildSQL(getTableName(), columnNames));
}
};
}
@Override
public UpdateBuilder createUpdate(@NotNull String tableName) {
return new UpdateBuilderImpl(this, tableName);
}
@Override
public DeleteBuilder createDelete(@NotNull String tableName) {
return new DeleteBuilderImpl(this, tableName);
}
}
@@ -0,0 +1,87 @@
package cc.carm.lib.easysql.query;
import cc.carm.lib.easysql.action.query.QueryActionImpl;
import cc.carm.lib.easysql.api.SQLQuery;
import cc.carm.lib.easysql.manager.SQLManagerImpl;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQLQueryImpl implements SQLQuery {
protected final long executeTime;
protected SQLManagerImpl sqlManager;
protected QueryActionImpl queryAction;
Connection connection;
Statement statement;
ResultSet resultSet;
public SQLQueryImpl(
SQLManagerImpl sqlManager, QueryActionImpl queryAction,
Connection connection, Statement statement, ResultSet resultSet
) {
this.executeTime = System.currentTimeMillis();
this.sqlManager = sqlManager;
this.queryAction = queryAction;
this.connection = connection;
this.statement = statement;
this.resultSet = resultSet;
}
@Override
public long getExecuteTime() {
return this.executeTime;
}
@Override
public SQLManagerImpl getManager() {
return this.sqlManager;
}
@Override
public QueryActionImpl getAction() {
return this.queryAction;
}
@Override
public ResultSet getResultSet() {
return this.resultSet;
}
@Override
public String getSQLContent() {
return getAction().getSQLContent();
}
@Override
public void close() {
try {
if (getResultSet() != null) getResultSet().close();
if (getStatement() != null) getStatement().close();
if (getConnection() != null) getConnection().close();
getManager().debug("#" + getAction().getShortID() +
" -> finished after " + (System.currentTimeMillis() - getExecuteTime()) + " ms."
);
getManager().getActiveQuery().remove(getAction().getActionUUID());
} catch (SQLException e) {
getAction().getExceptionHandler().accept(e);
}
this.queryAction = null;
}
@Override
public Statement getStatement() {
return this.statement;
}
@Override
public Connection getConnection() {
return this.connection;
}
}
@@ -0,0 +1,205 @@
package cc.carm.lib.easysql.util;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class StatementUtil {
/**
* 创建一个 {@link PreparedStatement} 。
*
* @param connection 数据库连接
* @param sql SQL语句,使用"?"做为占位符
* @param params "?"所代表的对应参数列表
* @return 完成参数填充的 {@link PreparedStatement}
*/
public static PreparedStatement createPrepareStatement(
Connection connection, String sql, Object[] params
) throws SQLException {
return createPrepareStatement(connection, sql, params, false);
}
/**
* 创建一个 {@link PreparedStatement} 。
*
* @param connection 数据库连接
* @param sql SQL语句,使用"?"做为占位符
* @param params "?"所代表的对应参数列表
* @param returnGeneratedKey 是否会返回自增主键
* @return 完成参数填充的 {@link PreparedStatement}
*/
public static PreparedStatement createPrepareStatement(
Connection connection, String sql, Object[] params, boolean returnGeneratedKey
) throws SQLException {
sql = sql.trim();
PreparedStatement statement = connection.prepareStatement(sql, returnGeneratedKey ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS);
final Map<Integer, Integer> nullTypeMap = new HashMap<>();
if (params != null) {
fillParams(statement, Arrays.asList(params), nullTypeMap);
}
return statement;
}
/**
* 创建批量操作的一个 {@link PreparedStatement} 。
*
* @param connection 数据库连接
* @param sql SQL语句,使用"?"做为占位符
* @param paramsBatch "?"所代表的对应参数列表
* @return 完成参数填充的 {@link PreparedStatement}
*/
public static PreparedStatement createPrepareStatementBatch(
Connection connection, String sql, Iterable<Object[]> paramsBatch
) throws SQLException {
return createPrepareStatementBatch(connection, sql, paramsBatch, false);
}
/**
* 创建批量操作的一个 {@link PreparedStatement} 。
*
* @param connection 数据库连接
* @param sql SQL语句,使用"?"做为占位符
* @param paramsBatch "?"所代表的对应参数列表
* @param returnGeneratedKey 是否会返回自增主键
* @return 完成参数填充的 {@link PreparedStatement}
*/
public static PreparedStatement createPrepareStatementBatch(
Connection connection, String sql, Iterable<Object[]> paramsBatch, boolean returnGeneratedKey
) throws SQLException {
sql = sql.trim();
PreparedStatement statement = connection.prepareStatement(sql, returnGeneratedKey ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS);
final Map<Integer, Integer> nullTypeMap = new HashMap<>();
for (Object[] params : paramsBatch) {
fillParams(statement, Arrays.asList(params), nullTypeMap);
statement.addBatch();
}
return statement;
}
/**
* 填充PreparedStatement的参数。
*
* @param statement PreparedStatement
* @param params SQL参数
* @return {@link PreparedStatement} 填充参数后的PreparedStatement
* @throws SQLException SQL执行异常
*/
public static PreparedStatement fillParams(
PreparedStatement statement, Iterable<?> params
) throws SQLException {
return fillParams(statement, params, null);
}
/**
* 填充PreparedStatement的参数。
*
* @param statement PreparedStatement
* @param params SQL参数
* @param nullCache null参数的类型缓存,避免循环中重复获取类型
* @return 完成参数填充的 {@link PreparedStatement}
*/
public static PreparedStatement fillParams(
PreparedStatement statement, Iterable<?> params, Map<Integer, Integer> nullCache
) throws SQLException {
if (null == params) {
return statement;// 无参数
}
int paramIndex = 1;//第一个参数从1计数
for (Object param : params) {
setParam(statement, paramIndex++, param, nullCache);
}
return statement;
}
/**
* 获取null字段对应位置的数据类型
* 如果类型获取失败将使用默认的 {@link Types#VARCHAR}
*
* @param statement {@link PreparedStatement}
* @param paramIndex 参数序列,第一位从1开始
* @return 数据类型,默认为 {@link Types#VARCHAR}
*/
public static int getNullType(PreparedStatement statement, int paramIndex) {
int sqlType = Types.VARCHAR;
final ParameterMetaData pmd;
try {
pmd = statement.getParameterMetaData();
sqlType = pmd.getParameterType(paramIndex);
} catch (SQLException ignore) {
}
return sqlType;
}
/**
* 为 {@link PreparedStatement} 设置单个参数
*
* @param preparedStatement {@link PreparedStatement}
* @param paramIndex 参数序列,从1开始
* @param param 参数,不能为{@code null}
* @param nullCache 用于缓存参数为null位置的类型,避免重复获取
*/
private static void setParam(
PreparedStatement preparedStatement, int paramIndex, Object param,
Map<Integer, Integer> nullCache
) throws SQLException {
if (param == null) {
Integer type = (null == nullCache) ? null : nullCache.get(paramIndex);
if (null == type) {
type = getNullType(preparedStatement, paramIndex);
if (null != nullCache) {
nullCache.put(paramIndex, type);
}
}
preparedStatement.setNull(paramIndex, type);
}
// 针对UUID特殊处理,避免元数据直接插入
if (param instanceof UUID) {
preparedStatement.setString(paramIndex, param.toString());
return;
}
// 日期特殊处理,默认按照时间戳传入,避免毫秒丢失
if (param instanceof java.util.Date) {
if (param instanceof Date) {
preparedStatement.setDate(paramIndex, (Date) param);
} else if (param instanceof Time) {
preparedStatement.setTime(paramIndex, (Time) param);
} else {
preparedStatement.setTimestamp(paramIndex, new Timestamp(((java.util.Date) param).getTime()));
}
return;
}
// 针对大数字类型的特殊处理
if (param instanceof Number) {
if (param instanceof BigDecimal) {
// BigDecimal的转换交给JDBC驱动处理
preparedStatement.setBigDecimal(paramIndex, (BigDecimal) param);
return;
}
if (param instanceof BigInteger) {
// BigInteger转为BigDecimal
preparedStatement.setBigDecimal(paramIndex, new BigDecimal((BigInteger) param));
return;
}
// 忽略其它数字类型,按照默认类型传入
}
// 其它参数类型直接插入
preparedStatement.setObject(paramIndex, param);
}
}