创建简单的 JdbcUtil,并借助 MyBatis 的 SQL 构建器简化 SQL 的拼接。

This commit is contained in:
2023-05-09 01:05:12 +08:00
parent 85ababc482
commit fa3f4695f1
8 changed files with 1081 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
package xyz.zhouxy.plusone.commons.exception;
import com.google.common.annotations.Beta;
@Beta
public class DbException extends RuntimeException {
public DbException(String message) {
super(message);
}
public DbException(Throwable cause) {
super(cause);
}
public DbException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,145 @@
package xyz.zhouxy.plusone.commons.jdbc;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;
import org.apache.commons.lang3.ArrayUtils;
import com.google.common.annotations.Beta;
import xyz.zhouxy.plusone.commons.util.DbRecord;
import xyz.zhouxy.plusone.commons.util.MoreCollections;
@Beta
public class JdbcUtil {
public static JdbcExecutor connect(Connection conn) {
return new JdbcExecutor(conn);
}
private JdbcUtil() {
throw new IllegalStateException("Utility class");
}
public static class JdbcExecutor {
private final Connection conn;
public JdbcExecutor(Connection conn) {
this.conn = conn;
}
public <T> List<T> query(String sql, Object[] params, ResultMap<T> resultMap) throws SQLException {
try (PreparedStatement stmt = this.conn.prepareStatement(sql)) {
if (params != null && params.length > 0) {
for (int i = 0; i < params.length; i++) {
stmt.setObject(i + 1, params[i]);
}
}
try (ResultSet rs = stmt.executeQuery()) {
List<T> result = new ArrayList<>();
while (rs.next()) {
T e = resultMap.map(rs);
result.add(e);
}
return result;
}
}
}
public static final ResultMap<Map<String, Object>> mapResultMap = rs -> {
Map<String, Object> result = new HashMap<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
String colName = metaData.getColumnName(i);
result.put(colName, rs.getObject(colName));
}
return result;
};
public List<Map<String, Object>> query(String sql, Object... params) throws SQLException {
return query(sql, params, mapResultMap);
}
public static final ResultMap<DbRecord> recordResultMap = rs -> {
DbRecord result = new DbRecord();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
String colName = metaData.getColumnName(i);
result.put(colName, rs.getObject(colName));
}
return result;
};
public List<DbRecord> queryToRecordList(String sql, Object... params) throws SQLException {
return query(sql, params, recordResultMap);
}
public Optional<String> queryToString(String sql, Object... params) throws SQLException {
List<String> result = query(sql, params, (ResultSet rs) -> rs.getString(1));
return MoreCollections.isNotEmpty(result) ? Optional.ofNullable(result.get(0)) : Optional.empty();
}
public OptionalInt queryToInt(String sql, Object... params) throws SQLException {
List<Integer> result = query(sql, params, (ResultSet rs) -> rs.getBigDecimal(1).intValue());
Integer i = MoreCollections.isNotEmpty(result) ? result.get(0) : null;
return i != null ? OptionalInt.of(i) : OptionalInt.empty();
}
public OptionalLong queryToLong(String sql, Object... params) throws SQLException {
List<Long> result = query(sql, params, (ResultSet rs) -> rs.getBigDecimal(1).longValue());
Long i = MoreCollections.isNotEmpty(result) ? result.get(0) : null;
return i != null ? OptionalLong.of(i) : OptionalLong.empty();
}
public Optional<BigDecimal> queryToBigDecimal(String sql, Object... params) throws SQLException {
List<BigDecimal> result = query(sql, params, (ResultSet rs) -> rs.getBigDecimal(1));
return MoreCollections.isNotEmpty(result) ? Optional.ofNullable(result.get(0)) : Optional.empty();
}
public int update(String sql, Object... params) throws SQLException {
try (PreparedStatement stmt = this.conn.prepareStatement(sql)) {
if (params != null && params.length > 0) {
for (int i = 0; i < params.length; i++) {
stmt.setObject(i + 1, params[i]);
}
}
return stmt.executeUpdate();
}
}
public int[] batchUpdate(String sql, Collection<Object[]> params, int batchSize) throws SQLException {
int[] result = {};
try (PreparedStatement stmt = this.conn.prepareStatement(sql)) {
int i = 0;
for (Object[] ps : params) {
i++;
for (int j = 0; j < ps.length; j++) {
stmt.setObject(j + 1, ps[j]);
}
stmt.addBatch();
if (i % batchSize == 0 || i >= params.size()) {
int[] n = stmt.executeBatch();
result = ArrayUtils.addAll(result, n);
stmt.clearBatch();
}
}
return result;
}
}
}
}

View File

@@ -0,0 +1,12 @@
package xyz.zhouxy.plusone.commons.jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.google.common.annotations.Beta;
@Beta
@FunctionalInterface
public interface ResultMap<T> {
T map(ResultSet rs) throws SQLException;
}

View File

@@ -0,0 +1,25 @@
package xyz.zhouxy.plusone.commons.jdbc;
import org.apache.ibatis.jdbc.AbstractSQL;
import com.google.common.annotations.Beta;
/**
* @author ZhouXY
*/
@Beta
public class SQL extends AbstractSQL<SQL> {
@Override
public SQL getSelf() {
return this;
}
public SQL WHERE_IF(boolean condition, String sqlConditions) {
if (condition) {
return WHERE(sqlConditions);
}
return getSelf();
}
}

View File

@@ -0,0 +1,61 @@
package xyz.zhouxy.plusone.commons.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.Set;
import com.google.common.annotations.Beta;
@Beta
public class DbRecord extends AbstractMapWrapper<String, Object, DbRecord> {
public DbRecord() {
super(new HashMap<>(), k -> Assert.isNotBlank(k, "Key can not be null."), null);
}
public DbRecord(Map<String, Object> map) {
super(map, k -> Assert.isNotBlank(k, "Key can not be null."), null);
}
public Optional<String> getValueAsString(String key) {
return this.<String>getAndConvert(key);
}
public <T> List<T> getValueAsList(String key) {
return this.<Collection<T>>getAndConvert(key)
.<List<T>>map(l -> (l instanceof List) ? (List<T>) l : new ArrayList<>(l))
.orElse(Collections.<T>emptyList());
}
public <T> Set<T> getValueAsSet(String key) {
return this.<Collection<T>>getAndConvert(key)
.<Set<T>>map(l -> (l instanceof Set) ? (Set<T>) l : new HashSet<>(l))
.orElse(Collections.<T>emptySet());
}
public OptionalInt getValueAsInt(String key) {
return OptionalUtil.toOptionalInt(this.<Integer>getAndConvert(key));
}
public OptionalLong getValueAsLong(String key) {
return OptionalUtil.toOptionalLong(this.<Long>getAndConvert(key));
}
public OptionalDouble getValueAsDouble(String key) {
return OptionalUtil.toOptionalDouble(this.<Double>getAndConvert(key));
}
@Override
protected DbRecord getSelf() {
return this;
}
}