1、包结构修改
2、dict的bug修改 3、arangodb查询find()默认1000条修改为库里所有数据
This commit is contained in:
57
src/main/java/net/tccn/base/dbq/DbExecutors.java
Normal file
57
src/main/java/net/tccn/base/dbq/DbExecutors.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package net.tccn.base.dbq;
|
||||
|
||||
import net.tccn.base.MetaKit;
|
||||
import net.tccn.base.PageBean;
|
||||
import net.tccn.base.dbq.fbean.FBean;
|
||||
import net.tccn.base.dbq.jdbc.api.DbKit;
|
||||
import net.tccn.base.dbq.parser.ParseMysql;
|
||||
import net.tccn.meta.MetaService;
|
||||
import net.tccn.meta.MetaTable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* Db 调度层
|
||||
*/
|
||||
public class DbExecutors {
|
||||
private final static ParseMysql PARSER = new ParseMysql();
|
||||
|
||||
public static PageBean findPage(FBean fBean) throws ExecutionException, InterruptedException {
|
||||
//sql解析
|
||||
String[] sqls = PARSER.parseList(fBean);
|
||||
|
||||
//当前的业务 => 获取主表 信息 => 数据源信息 => 数据源对象 => 创建数据工具对象 => 查询数据
|
||||
MetaService metaService = MetaKit.getMetaService(fBean.getName(), fBean.getPlatToken());
|
||||
MetaTable mainTable = MetaKit.getMetaTableByAlias(metaService.getTable());
|
||||
DbKit dbKit = MetaKit.getDbKit(mainTable.getDbPlatId(), mainTable.getCatalog());
|
||||
//System.out.printf("----------------%n countSql:%s%n findSql:%s%n----------------%n", sqls[0], sqls[1]);
|
||||
|
||||
CompletableFuture<Integer> countFuture = CompletableFuture.supplyAsync(() -> dbKit.queryColumn(sqls[0], int.class));
|
||||
CompletableFuture<List<Map>> listFuture = CompletableFuture.supplyAsync(() -> dbKit.findList(sqls[1], Map.class));
|
||||
|
||||
List<Map> rows = listFuture.get();
|
||||
Integer total = countFuture.get();
|
||||
|
||||
return PageBean.by(rows, total);
|
||||
}
|
||||
|
||||
public static void del(String name, Map data, String token) {
|
||||
MetaService metaService = MetaKit.getMetaService(name, token);
|
||||
MetaTable mainTable = MetaKit.getMetaTableByAlias(metaService.getTable());
|
||||
DbKit dbKit = MetaKit.getDbKit(mainTable.getDbPlatId(), mainTable.getCatalog());
|
||||
|
||||
String delSql = PARSER.parseDel(name, data, token);
|
||||
dbKit.exetute(delSql);
|
||||
}
|
||||
|
||||
public static void save(String name, Map data, String token) {
|
||||
MetaTable mainTable = MetaKit.getMainTable(name, token);
|
||||
DbKit dbKit = MetaKit.getDbKit(mainTable.getDbPlatId(), mainTable.getCatalog());
|
||||
|
||||
String sql = PARSER.parseSave(name, data, token);
|
||||
dbKit.exetute(sql);
|
||||
}
|
||||
}
|
||||
8
src/main/java/net/tccn/base/dbq/fbean/DbType.java
Normal file
8
src/main/java/net/tccn/base/dbq/fbean/DbType.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package net.tccn.base.dbq.fbean;
|
||||
|
||||
/**
|
||||
* Created by liangxianyou at 2018/12/14 15:34.
|
||||
*/ //数据库类型
|
||||
public enum DbType {
|
||||
MYSQL, ARANGODB
|
||||
}
|
||||
24
src/main/java/net/tccn/base/dbq/fbean/FBean.java
Normal file
24
src/main/java/net/tccn/base/dbq/fbean/FBean.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package net.tccn.base.dbq.fbean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 查询用实体
|
||||
* @author: liangxianyou at 2018/10/25 14:49.
|
||||
*/
|
||||
@Data
|
||||
public class FBean {
|
||||
|
||||
private String platToken; // 平台token
|
||||
private String name; // 业务名称
|
||||
private String type; // 操作类型 list:列表,export:导出
|
||||
|
||||
private List<Filter> filters;//[{f:xx, v: v, type:t}] -- t,
|
||||
private List<Order> orders;//{f1: 1, f2: -1}
|
||||
private Limit limit;//{pn: 1, ps: 10}
|
||||
|
||||
//-----------------------------------
|
||||
|
||||
}
|
||||
68
src/main/java/net/tccn/base/dbq/fbean/Filter.java
Normal file
68
src/main/java/net/tccn/base/dbq/fbean/Filter.java
Normal file
@@ -0,0 +1,68 @@
|
||||
package net.tccn.base.dbq.fbean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 查询条件实体
|
||||
* Created by liangxianyou at 2018/12/14 15:34.
|
||||
*/
|
||||
@Data
|
||||
public class Filter {
|
||||
private String col;
|
||||
private String value;
|
||||
private String type;
|
||||
//----------------------
|
||||
|
||||
public static Filter by(String col, Object value) {
|
||||
return by(col, "==", value + "");//todo: == 不是mysql 语法,不具备通用性
|
||||
}
|
||||
|
||||
public static Filter by(String col, String type, String value) {
|
||||
Filter filter = new Filter();
|
||||
filter.setCol(col);
|
||||
filter.setType(type);
|
||||
filter.setValue(value);
|
||||
return filter;
|
||||
}
|
||||
|
||||
//mysql 查询组装
|
||||
public static String filter(List<Filter> filters) {
|
||||
if (filters == null || filters.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(" where 1=1");
|
||||
filters.forEach(x -> {
|
||||
buf.append(FilterType.buildSql(x));
|
||||
});
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String filter(List<Filter> filters, DbType dbType) {
|
||||
if (DbType.MYSQL == dbType) {
|
||||
return filter(filters);
|
||||
} else if (DbType.ARANGODB == dbType) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(" filter 1==1");
|
||||
if (filters == null || filters.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
filters.forEach(x -> {
|
||||
buf.append(" and d.").append(x.col).append(" " + (x.type == null ? "==" : x.type) + " ");
|
||||
//处理数值型字段查询
|
||||
if ("sysPlatId".equals(x.col) || "platId".equals(x.col) || "status".equals(x.col) || false) {
|
||||
buf.append(x.value);
|
||||
} else {
|
||||
buf.append("'" + x.value + "'");
|
||||
}
|
||||
});
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
81
src/main/java/net/tccn/base/dbq/fbean/FilterType.java
Normal file
81
src/main/java/net/tccn/base/dbq/fbean/FilterType.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package net.tccn.base.dbq.fbean;
|
||||
|
||||
import net.tccn.base.Kv;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by liangxianyou at 2018/12/14 15:34.
|
||||
*/
|
||||
public enum FilterType {
|
||||
EQUAL("=", "等于"),
|
||||
NOTEQUAL("!=", "不等于"),
|
||||
GREATERTHANOREQUALTO(">=", ">="),
|
||||
LESSTHAN("<", "小于"),
|
||||
LIKE("LIKE", "LIKE"),
|
||||
IN("IN", "包含");
|
||||
|
||||
private String expre;
|
||||
private String remark;
|
||||
|
||||
FilterType(String expre, String remark) {
|
||||
this.expre = expre;
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
//不同的条件构建过滤语句
|
||||
public static String buildSql(Filter filter) {
|
||||
if (filter.getValue() == null || filter.getValue().length() == 0) {
|
||||
return "";
|
||||
}
|
||||
FilterType filterType = getFilterType(filter.getType());
|
||||
if (filterType == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String _sql;
|
||||
switch (filterType) {
|
||||
case IN:
|
||||
_sql = String.format(" AND %s IN (%s)", filter.getCol(), filter.getValue());
|
||||
break;
|
||||
case LIKE:
|
||||
_sql = String.format(" AND %s LIKE '%s'", filter.getCol(), "%" + filter.getValue() + "%");
|
||||
break;
|
||||
default:
|
||||
_sql = String.format(" AND %s %s '%s'", filter.getCol(), filterType.expre, filter.getValue());
|
||||
break;
|
||||
}
|
||||
|
||||
return _sql;
|
||||
}
|
||||
|
||||
public static FilterType getFilterType(String name) {
|
||||
for (FilterType t : FilterType.values()) {
|
||||
if (t.name().equalsIgnoreCase(name)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//获取所有的查询类型
|
||||
public static List<Map> getAllTypes() {
|
||||
List<Map> list = new ArrayList<>();
|
||||
for (FilterType type : FilterType.values()) {
|
||||
Kv kv = Kv.of("name", type.name())/*.set("expre", type.expre)*/.set("remark", type.remark);
|
||||
list.add(kv);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public String getExpre() {
|
||||
return expre;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}}
|
||||
32
src/main/java/net/tccn/base/dbq/fbean/Limit.java
Normal file
32
src/main/java/net/tccn/base/dbq/fbean/Limit.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package net.tccn.base.dbq.fbean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Created by liangxianyou at 2018/12/14 15:36.
|
||||
*/
|
||||
@Data
|
||||
public class Limit {
|
||||
private int pn;
|
||||
private int ps;
|
||||
|
||||
public Limit() {
|
||||
}
|
||||
|
||||
public Limit(int pn, int ps) {
|
||||
this.pn = pn;
|
||||
this.ps = ps;
|
||||
}
|
||||
|
||||
//--------------------
|
||||
public String limit() {
|
||||
if (pn < 1) {
|
||||
pn = 1;
|
||||
}
|
||||
if (ps < 1) {
|
||||
ps = 10;
|
||||
}
|
||||
return String.format(" LIMIT %s, %s", (pn - 1) * ps, ps);
|
||||
}
|
||||
}
|
||||
|
||||
42
src/main/java/net/tccn/base/dbq/fbean/Order.java
Normal file
42
src/main/java/net/tccn/base/dbq/fbean/Order.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package net.tccn.base.dbq.fbean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by liangxianyou at 2018/12/14 15:36.
|
||||
*/
|
||||
public class Order {
|
||||
private String col;
|
||||
private int desc;//1 or -1
|
||||
|
||||
public Order() {
|
||||
}
|
||||
|
||||
public Order(String col, int desc) {
|
||||
this.col = col;
|
||||
this.desc = desc;
|
||||
}
|
||||
// --------------------------------
|
||||
|
||||
public static String order(List<Order> orders, DbType dbType) {
|
||||
if (orders == null || orders.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder buf = new StringBuilder();
|
||||
switch (dbType) {
|
||||
case MYSQL:
|
||||
buf.append(" ORDER BY");
|
||||
orders.forEach(x -> {
|
||||
buf.append(String.format(" %s %s,", x.col, (x.desc == 1 ? "desc" : "asc")));
|
||||
});
|
||||
buf.deleteCharAt(buf.length() - 1);
|
||||
break;
|
||||
|
||||
case ARANGODB:
|
||||
// 待实现
|
||||
break;
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
37
src/main/java/net/tccn/base/dbq/jdbc/api/DbAccount.java
Normal file
37
src/main/java/net/tccn/base/dbq/jdbc/api/DbAccount.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package net.tccn.base.dbq.jdbc.api;
|
||||
|
||||
import lombok.Data;
|
||||
import net.tccn.base.arango.Doc;
|
||||
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 数据库平台
|
||||
* @author: liangxianyou at 2018/11/14 12:58.
|
||||
*/
|
||||
@Data
|
||||
@Table(name = "db_plat", catalog = "db_dev")
|
||||
public class DbAccount extends Doc<DbAccount> {
|
||||
public static DbAccount dao = dao(DbAccount.class);
|
||||
|
||||
private String name; //名称
|
||||
private String cate; //类型 mysql|ArangoDb
|
||||
private String remark; //备注
|
||||
private String url; //数据库连接地址
|
||||
private String user; //账号
|
||||
private String pwd; //密码
|
||||
private String[] catalogs; //库
|
||||
|
||||
//----------------------------
|
||||
|
||||
public String accountKey() {
|
||||
int start = url.indexOf("//") + 2;
|
||||
int end = url.indexOf("/", start);
|
||||
int endDef = url.indexOf("?", end);
|
||||
if (endDef == -1) {
|
||||
endDef = url.length();
|
||||
}
|
||||
String host = url.substring(start, end == -1 ? url.length() : end);
|
||||
return user + "@" + host;
|
||||
}
|
||||
}
|
||||
104
src/main/java/net/tccn/base/dbq/jdbc/api/DbKit.java
Normal file
104
src/main/java/net/tccn/base/dbq/jdbc/api/DbKit.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package net.tccn.base.dbq.jdbc.api;
|
||||
|
||||
import net.tccn.base.X;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Db 最终执行层
|
||||
* Created by liangxianyou at 2019/3/12 14:11.
|
||||
*/
|
||||
public class DbKit implements DbSource{
|
||||
|
||||
private DbAccount dbAccount;
|
||||
private DbSource dbSource;
|
||||
private String catalog;
|
||||
|
||||
/*public DbKit(DbAccount dbAccount) {
|
||||
this.dbAccount = dbAccount;
|
||||
try {
|
||||
DbSource dbSource = X.getDbSource(DbSource.class, dbAccount.getCate());
|
||||
dbSource.setDbAccount(dbAccount);
|
||||
|
||||
this.dbSource = dbSource;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(String.format("创建DbKit失败:数据库类型[cate:%s]未知", dbAccount.getCate()));
|
||||
}
|
||||
}*/
|
||||
public DbKit(DbAccount dbAccount, String catalog) {
|
||||
this.dbAccount = dbAccount;
|
||||
this.catalog = catalog;
|
||||
|
||||
try {
|
||||
DbSource dbSource = X.getDbSource(DbSource.class, dbAccount.getCate());
|
||||
dbSource.setDbAccount(dbAccount);
|
||||
dbSource.setCatalog(catalog);
|
||||
|
||||
this.dbSource = dbSource;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(String.format("创建DbKit失败:数据库类型[cate:%s]未知", dbAccount.getCate()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setDbAccount(DbAccount dbAccount) {
|
||||
this.dbAccount = dbAccount;
|
||||
dbSource.setDbAccount(dbAccount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCatalog(String catelog) {
|
||||
this.catalog = catelog;
|
||||
dbSource.setCatalog(catalog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> findList(String sql, Class<T> type) {
|
||||
return dbSource.findList(sql, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T findFirst(String sql, Class<T> type) {
|
||||
return dbSource.findFirst(sql, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T queryColumn(String sql, Class<T> type) {
|
||||
return dbSource.queryColumn(sql, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTable(String sql) {
|
||||
dbSource.createTable(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropTable(String tableName) {
|
||||
dbSource.dropTable(tableName);
|
||||
}
|
||||
|
||||
public void exetute(String sql) {
|
||||
dbSource.exetute(sql);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
public <T> CompletableFuture<T> findfirstAsync(String sql, Class<T> type) {
|
||||
return CompletableFuture.supplyAsync(() -> findFirst(sql, type));
|
||||
}
|
||||
public <T> CompletableFuture<List<T>> findListAsync(String sql, Class<T> type) {
|
||||
return CompletableFuture.supplyAsync(() -> findList(sql, type));
|
||||
}
|
||||
public <T> CompletableFuture<T> queryColumnAsync(String sql, Class<T> type) {
|
||||
return CompletableFuture.supplyAsync(() -> queryColumn(sql, type));
|
||||
}
|
||||
public CompletableFuture<Void> exetuteAsync(String sql) {
|
||||
return CompletableFuture.runAsync(() -> exetute(sql));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
45
src/main/java/net/tccn/base/dbq/jdbc/api/DbSource.java
Normal file
45
src/main/java/net/tccn/base/dbq/jdbc/api/DbSource.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package net.tccn.base.dbq.jdbc.api;
|
||||
|
||||
import net.tccn.base.IService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by liangxianyou at 2019/3/12 14:07.
|
||||
*/
|
||||
public interface DbSource extends IService {
|
||||
|
||||
void setDbAccount(DbAccount dbAccount);
|
||||
void setCatalog(String catelog);
|
||||
|
||||
<T> List<T> findList(String sql, Class<T> type);
|
||||
|
||||
<T> T findFirst(String sql, Class<T> type);
|
||||
|
||||
<T> T queryColumn(String sql, Class<T> type);
|
||||
|
||||
//待实现
|
||||
default <T> void save(String tableName, T t) {}
|
||||
|
||||
//待实现
|
||||
default <T> void update(String tableName, T t) {}
|
||||
|
||||
default int queryInt(String sql) {
|
||||
return queryColumn(sql, int.class);
|
||||
}
|
||||
default long queryLong(String sql) {
|
||||
return queryColumn(sql, long.class);
|
||||
}
|
||||
default double queryDouble(String sql) {
|
||||
return queryColumn(sql, double.class);
|
||||
}
|
||||
default Date queryDate(String sql) {
|
||||
return queryColumn(sql, Date.class);
|
||||
}
|
||||
|
||||
void createTable(String sql);
|
||||
void dropTable(String tableName);
|
||||
|
||||
void exetute(String sql);
|
||||
}
|
||||
226
src/main/java/net/tccn/base/dbq/jdbc/api/DbSourceMysql.java
Normal file
226
src/main/java/net/tccn/base/dbq/jdbc/api/DbSourceMysql.java
Normal file
@@ -0,0 +1,226 @@
|
||||
package net.tccn.base.dbq.jdbc.api;
|
||||
|
||||
import net.tccn.base.CfgException;
|
||||
import net.tccn.base.Kv;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Created by liangxianyou at 2019/3/12 14:20.
|
||||
*/
|
||||
public class DbSourceMysql implements DbSource {
|
||||
|
||||
private static ConcurrentHashMap<String, LinkedBlockingQueue<Connection>> conns = new ConcurrentHashMap<>();
|
||||
private static ConcurrentHashMap<String, AtomicInteger> counter = new ConcurrentHashMap<>();
|
||||
|
||||
private String accountKey;
|
||||
private DbAccount dbAccount;
|
||||
private String catalog;
|
||||
|
||||
public DbSourceMysql() {
|
||||
|
||||
}
|
||||
|
||||
public void setDbAccount(DbAccount dbAccount) {
|
||||
this.dbAccount = dbAccount;
|
||||
this.accountKey = dbAccount.accountKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCatalog(String catalog) {
|
||||
this.catalog = catalog;
|
||||
}
|
||||
|
||||
public DbSourceMysql(DbAccount dbAccount) {
|
||||
this.dbAccount = dbAccount;
|
||||
this.accountKey = dbAccount.accountKey();
|
||||
}
|
||||
public DbSourceMysql(DbAccount dbAccount, String catalog) {
|
||||
this.dbAccount = dbAccount;
|
||||
this.catalog = catalog;
|
||||
this.accountKey = dbAccount.accountKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "mysql";
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> findList(String sql, Class<T> type) {
|
||||
Connection connection = connection();
|
||||
try (
|
||||
PreparedStatement ps = connection.prepareStatement(sql);
|
||||
ResultSet rs = ps.executeQuery()) {
|
||||
List list = new ArrayList();
|
||||
while (rs.next()) {
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
int count = metaData.getColumnCount();
|
||||
|
||||
Map row = new HashMap();
|
||||
for (int i = 1; i <= count; i++) {
|
||||
String columnTypeName = metaData.getColumnTypeName(i);
|
||||
//String columnName = metaData.getColumnName(i);
|
||||
String columnLabel = metaData.getColumnLabel(i);
|
||||
row.put(columnLabel, null);
|
||||
|
||||
if (rs.getObject(i) != null) {
|
||||
switch (columnTypeName) {
|
||||
case "DATETIME":
|
||||
case "TIMESTAMP":
|
||||
case "DATE":
|
||||
row.put(columnLabel, rs.getTimestamp(i).getTime()); break;
|
||||
default:
|
||||
row.put(columnLabel, rs.getObject(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
list.add(Map.class == type ? row : Kv.toBean(row, type));
|
||||
}
|
||||
|
||||
return list;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
release(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T findFirst(String sql, Class<T> type) {
|
||||
List<T> list = findList(sql, type);
|
||||
return list.size() > 0 ? list.get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T queryColumn(String sql, Class<T> type) {
|
||||
Connection connection = connection();
|
||||
try (
|
||||
PreparedStatement ps = connection.prepareStatement(sql);
|
||||
ResultSet rs = ps.executeQuery()
|
||||
) {
|
||||
Object v = null;
|
||||
while (rs.next()) {
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
int count = metaData.getColumnCount();
|
||||
|
||||
for (int i = 1; i <= count; i++) {
|
||||
String columnTypeName = metaData.getColumnTypeName(i);
|
||||
if (rs.getObject(i) != null) {
|
||||
switch (columnTypeName) {
|
||||
case "DATETIME":
|
||||
case "TIMESTAMP":
|
||||
case "DATE":
|
||||
v = rs.getTimestamp(i).getTime(); break;
|
||||
default:
|
||||
v = rs.getObject(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Kv.toAs(v, type);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
release(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTable(String sql) {
|
||||
new RuntimeException("DbSourceMysql.createTable NOT SUPPORT right now" ); // todo:
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropTable(String tableName) {
|
||||
new RuntimeException("[DbSourceMysql.dropTable] NOT SUPPORT right now" ); // todo:
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exetute(String sql) {
|
||||
Connection connection = connection();
|
||||
try (
|
||||
PreparedStatement ps = connection.prepareStatement(sql);
|
||||
){
|
||||
ps.execute();
|
||||
//ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
throw new CfgException("SQL 执行失败:", sql);
|
||||
} finally {
|
||||
release(connection);
|
||||
}
|
||||
}
|
||||
|
||||
//fixme: lxy 处理连接超过8小时失效问题
|
||||
private Connection connection() {
|
||||
Connection connection = connection(0);
|
||||
if (connection != null && catalog != null && !catalog.isEmpty()) {
|
||||
try {
|
||||
connection.setCatalog(catalog); //还回连接的时候是否需要重置catalog? 后续观察
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
private Connection connection(int n) {
|
||||
LinkedBlockingQueue<Connection> queue = conns.getOrDefault(accountKey, new LinkedBlockingQueue<>(15));
|
||||
|
||||
Connection conn = null;
|
||||
AtomicInteger num = counter.getOrDefault(accountKey, new AtomicInteger(0));
|
||||
try {
|
||||
if (queue.size() == 0 && num.get() < 15) {
|
||||
conn = DriverManager.getConnection(dbAccount.getUrl(), dbAccount.getUser(), dbAccount.getPwd());
|
||||
int x = num.incrementAndGet();
|
||||
counter.put(accountKey, num);
|
||||
System.out.println("创建新的连接:" + x);
|
||||
} else {
|
||||
conn = queue.take();
|
||||
if (conn.isClosed()) {
|
||||
System.out.println("connetion had closed,");
|
||||
conn = connection(n);
|
||||
}
|
||||
}
|
||||
} catch (SQLException | InterruptedException e) {
|
||||
if (e instanceof InterruptedException) {
|
||||
try {
|
||||
conn = DriverManager.getConnection(dbAccount.getUrl(), dbAccount.getUser(), dbAccount.getPwd());
|
||||
num.getAndIncrement();
|
||||
if (conn != null) {
|
||||
System.out.println("获取连接异常,并重新创建成功");
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
new IllegalArgumentException("创建连接失败", e);
|
||||
}
|
||||
num.getAndIncrement();
|
||||
counter.put(accountKey, num);
|
||||
} else {
|
||||
new IllegalArgumentException("获取连接失败", e);
|
||||
}
|
||||
}
|
||||
conns.put(accountKey, queue);
|
||||
return conn;
|
||||
}
|
||||
private void release(Connection connection) {
|
||||
LinkedBlockingQueue<Connection> queue = conns.getOrDefault(accountKey, new LinkedBlockingQueue<>(15));
|
||||
try {
|
||||
if (connection != null) {
|
||||
queue.put(connection);
|
||||
conns.put(accountKey, queue);
|
||||
//System.out.println("还回连接:" + connection);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/main/java/net/tccn/base/dbq/parser/ParseArango.java
Normal file
14
src/main/java/net/tccn/base/dbq/parser/ParseArango.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package net.tccn.base.dbq.parser;
|
||||
|
||||
import net.tccn.base.dbq.fbean.FBean;
|
||||
|
||||
/**
|
||||
* Created by liangxianyou at 2018/12/24 15:49.
|
||||
*/
|
||||
public class ParseArango implements Parser {
|
||||
|
||||
@Override
|
||||
public String[] parseList(FBean fBean) {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
15
src/main/java/net/tccn/base/dbq/parser/ParseEs.java
Normal file
15
src/main/java/net/tccn/base/dbq/parser/ParseEs.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package net.tccn.base.dbq.parser;
|
||||
|
||||
import net.tccn.base.dbq.fbean.FBean;
|
||||
|
||||
/**
|
||||
* Created by liangxianyou at 2018/12/24 15:49.
|
||||
*/
|
||||
public class ParseEs implements Parser {
|
||||
|
||||
|
||||
@Override
|
||||
public String[] parseList(FBean fBean) {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
215
src/main/java/net/tccn/base/dbq/parser/ParseMysql.java
Normal file
215
src/main/java/net/tccn/base/dbq/parser/ParseMysql.java
Normal file
@@ -0,0 +1,215 @@
|
||||
package net.tccn.base.dbq.parser;
|
||||
|
||||
import net.tccn.base.*;
|
||||
import net.tccn.base.dbq.fbean.*;
|
||||
import net.tccn.meta.MetaLink;
|
||||
import net.tccn.meta.MetaService;
|
||||
import net.tccn.meta.MetaTable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 查询的数据是否同库,
|
||||
* 是:支持副表过滤
|
||||
* 否:只支持主表过滤
|
||||
* Created by liangxianyou at 2018/12/24 15:49.
|
||||
*/
|
||||
public class ParseMysql implements Parser {
|
||||
|
||||
Predicate<Kv<String, MetaTable>> sameDbFun = (kv) -> {
|
||||
String dbPlatId = null;
|
||||
for (MetaTable metaTable : kv.values()) {
|
||||
if (dbPlatId == null) {
|
||||
dbPlatId = metaTable.getDbPlatId();
|
||||
} else if (!dbPlatId.equals(metaTable.getDbPlatId())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询数据解析
|
||||
* @param fBean
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String[] parseList(FBean fBean) {
|
||||
MetaService metaService = MetaKit.getMetaService(fBean.getName(), fBean.getPlatToken());
|
||||
|
||||
Kv<String, MetaTable> tables = MetaKit.getMetaTables(metaService, false);//所有的关联表信息
|
||||
MetaTable metaTable = tables.get(metaService.getTable());//基础元数据
|
||||
List<Map<String, String>> shows = metaService.getShows();//查询的属性-列表
|
||||
List<Map<String, String>> exports = metaService.getExports();//查询的属性-导出
|
||||
|
||||
List<String> _filters = fBean.getFilters().stream().map(Filter::getCol).collect(Collectors.toList());
|
||||
List<MetaLink> links = MetaKit.getMetaLinks(
|
||||
metaService.getTable(),
|
||||
shows.stream().map(x -> x.get("col")).collect(Collectors.toList()),
|
||||
_filters
|
||||
);
|
||||
//查询条件
|
||||
List<Filter> filters = fBean.getFilters();
|
||||
Limit limit = fBean.getLimit();
|
||||
List<Order> orders = fBean.getOrders();
|
||||
//Map<String, List<Filter>> filterMap = filters.stream().collect(Collectors.groupingBy(x -> x.getCol().split("[.]")[0]));
|
||||
//Map<String, List<String>> showMap = shows.stream().collect(Collectors.groupingBy(x -> x.split("[.]")[0]));
|
||||
|
||||
|
||||
//判断是否为同库
|
||||
if (sameDbFun.test(tables) || true) {
|
||||
// where 1=1 and xx=xx
|
||||
StringBuffer bufWhere = new StringBuffer();
|
||||
if (!X.isEmpty(filters)) {
|
||||
bufWhere.append(Filter.filter(filters, DbType.MYSQL));
|
||||
}
|
||||
|
||||
//select a.x, b.y, c.z
|
||||
StringBuffer bufSelect = new StringBuffer();
|
||||
bufSelect.append("select ");
|
||||
if ("export".equals(fBean.getType()) && !X.isEmpty(exports)) {
|
||||
exports.forEach(x -> {
|
||||
bufSelect.append(x.get("col")).append(" as ").append("'").append(x.get("col")).append("',");
|
||||
});
|
||||
bufSelect.deleteCharAt(bufSelect.length() - 1);
|
||||
}
|
||||
else if ("list".equals(fBean.getType()) && !X.isEmpty(shows)) {
|
||||
shows.forEach(x -> {
|
||||
bufSelect.append(x.get("col")).append(" as ").append("'").append(x.get("col")).append("',");
|
||||
});
|
||||
bufSelect.deleteCharAt(bufSelect.length() - 1);
|
||||
} else {
|
||||
bufSelect.append("*");
|
||||
}
|
||||
|
||||
//from
|
||||
StringBuilder bufFrom = new StringBuilder();
|
||||
bufFrom.append(" from ").append(metaTable.getCatalog()).append(".`").append(metaTable.getName()).append("` ").append(metaTable.getAlias());
|
||||
//left join
|
||||
if (!X.isEmpty(links)) {
|
||||
links.forEach(x -> {
|
||||
MetaTable rightTable = tables.get(metaTable.getAlias().equals(x.getTables()[0]) ? x.getTables()[1] : x.getTables()[0]);
|
||||
if (rightTable != null) {
|
||||
bufFrom.append(" left join ").append(rightTable.getCatalog()).append(".").append(rightTable.getName()).append(" ").append(rightTable.getAlias()).append(" on ");
|
||||
int tag = bufFrom.length();
|
||||
x.getLink().forEach((k, v) -> {
|
||||
if (bufFrom.length() > tag) {
|
||||
bufFrom.append(" and ");
|
||||
}
|
||||
bufFrom.append(k).append("=").append(v);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
StringBuffer bufOth = new StringBuffer();
|
||||
//order by
|
||||
if (!X.isEmpty(orders)) {
|
||||
bufOth.append(" ").append(Order.order(orders, DbType.MYSQL));
|
||||
}
|
||||
//limit
|
||||
bufOth.append(" ").append(limit.limit());
|
||||
|
||||
return new String[]{
|
||||
"select count(1) " + bufFrom + bufWhere,
|
||||
"" + bufSelect + bufFrom + bufWhere + bufOth
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除执行语句解析
|
||||
* @param name
|
||||
* @param data
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public String parseDel(String name, Map data, String token) {
|
||||
MetaService metaService = MetaKit.getMetaService(name, token);
|
||||
Map<String, String> dels = metaService.getDels();
|
||||
MetaTable mainTable = MetaKit.getMetaTableByAlias(metaService.getTable());
|
||||
|
||||
String sql = "";
|
||||
if ("UP_FIELD".equalsIgnoreCase(dels.get("cate"))) {
|
||||
data.put("table", mainTable.getName());
|
||||
sql = TplKit.parseTpl("update #(table) set status=9 where id=#(id)", data);
|
||||
} else if ("SQL".equalsIgnoreCase(dels.get("cate"))) {
|
||||
sql = TplKit.parseTpl(dels.get("sql"), data);
|
||||
} else if ("QTASK".equalsIgnoreCase(dels.get("cate"))) {
|
||||
sql = TplKit.parseTpl("qtask", data);
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据解析逻辑:
|
||||
* 1.得到主表信息
|
||||
* 2.根据主表信息 使用数据创建sql
|
||||
* @param serviceName 业务名称
|
||||
* @param data 待保存的数据
|
||||
* @param token 平台token
|
||||
* @return sql 待执行的sql语句
|
||||
*/
|
||||
public String parseSave(String serviceName, Map<String, String> data, String token) {
|
||||
MetaTable mainTable = MetaKit.getMainTable(serviceName, token);
|
||||
String alias = mainTable.getAlias();
|
||||
String[] pks = mainTable.pk();
|
||||
|
||||
// 异常 sql: update `user2` set `aa.name`='null',`aa.deptId`='null',`aa.id`='null' where `id` = '1';
|
||||
|
||||
// 取出有效的数据key
|
||||
List<String> keys = data.keySet()
|
||||
.stream()
|
||||
.filter(x ->
|
||||
x.startsWith(alias + ".") || !X.isEmpty(data.get(alias + "." + x))
|
||||
).collect(Collectors.toList());
|
||||
if (pks.length == 0) {
|
||||
throw new CfgException("保存数据失败,检查业务主表[%s-%S]主键配置", mainTable.getName(), mainTable.getComment());
|
||||
} else if (keys.size() == 0) {
|
||||
throw new CfgException("保存数据失败,提交数据不能改空");
|
||||
}
|
||||
|
||||
|
||||
//单主键
|
||||
String pv = data.get(alias + "." + pks[0]);
|
||||
if (X.isEmpty(pv)) { //新增
|
||||
String sqlTpl = "INSERT INTO `%s` (%s) VALUES %s;"; // para: table、 ks、 vs
|
||||
StringBuffer ks = new StringBuffer();// `k1`,`k2`,`k3`, ...
|
||||
StringBuffer vs = new StringBuffer();// `v1`,`v2`,`v3`, ...
|
||||
|
||||
for (String k : keys) {
|
||||
ks.append(String.format("`%s`,", k.substring(k.indexOf(".") + 1)));
|
||||
vs.append(String.format("'%s',", data.get(k)));
|
||||
}
|
||||
if (ks.length() > 0) {
|
||||
ks.deleteCharAt(ks.length() - 1);
|
||||
vs.deleteCharAt(vs.length() - 1);
|
||||
}
|
||||
|
||||
return String.format(sqlTpl, mainTable.getName(), ks, vs);
|
||||
}
|
||||
|
||||
else { //修改
|
||||
String sqlTpl = "update `%s` set %s where `%s` = '%s';"; // para: table、 kvs、 pk、 pv
|
||||
StringBuilder kvs = new StringBuilder(); // `k1`='v1',`k2`='v2', ...
|
||||
String pk = pks[0];
|
||||
|
||||
for (String k : keys) {
|
||||
kvs.append(String.format("`%s`='%s',", k.substring(k.indexOf(".") + 1), data.get(k)));
|
||||
}
|
||||
|
||||
if (kvs.length() > 0) {
|
||||
kvs.deleteCharAt(kvs.length() - 1);
|
||||
}
|
||||
|
||||
return String.format(sqlTpl, mainTable.getName(), kvs, pk, pv);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/main/java/net/tccn/base/dbq/parser/Parser.java
Normal file
26
src/main/java/net/tccn/base/dbq/parser/Parser.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package net.tccn.base.dbq.parser;
|
||||
|
||||
import net.tccn.base.dbq.fbean.FBean;
|
||||
|
||||
/**
|
||||
* Db 执行解释层
|
||||
* Created by liangxianyou at 2018/12/24 15:47.
|
||||
*/
|
||||
public interface Parser {
|
||||
|
||||
/**
|
||||
* 组装完整分页查询
|
||||
* @param fBean
|
||||
* @return [countSql, listSql]
|
||||
*/
|
||||
String[] parseList(FBean fBean);
|
||||
|
||||
|
||||
/**
|
||||
* 解析入库语句
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
//String parseSave(MetaService ms, Map data);
|
||||
|
||||
}
|
||||
29
src/main/java/net/tccn/base/dbq/qtask/Qtask.java
Normal file
29
src/main/java/net/tccn/base/dbq/qtask/Qtask.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package net.tccn.base.dbq.qtask;
|
||||
|
||||
import lombok.Data;
|
||||
import net.tccn.base.arango.Doc;
|
||||
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author: liangxianyou at 2018/11/13 14:59.
|
||||
*/
|
||||
@Data
|
||||
@Table(name = "qtask", catalog = "db_dev")
|
||||
public class Qtask extends Doc<Qtask> {
|
||||
public static Qtask dao = dao(Qtask.class);
|
||||
|
||||
private String queryId; //查询id
|
||||
private String name; //业务名称
|
||||
private String remark; //说明
|
||||
private String sql; //SQL
|
||||
private String para; //默认查询参数
|
||||
private String cate; //任务类型 find|update
|
||||
private Integer sysPlatId; //数据平台id
|
||||
private Integer platId; //数据平台id
|
||||
private String catalog; //数据库名
|
||||
private Integer status; //状态 1启用|0未启用|-1删除
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
}
|
||||
30
src/main/java/net/tccn/base/dbq/table/Column.java
Normal file
30
src/main/java/net/tccn/base/dbq/table/Column.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package net.tccn.base.dbq.table;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 数据库表的列
|
||||
* @author: liangxianyou at 2018/10/8 10:59.
|
||||
*/
|
||||
@Data
|
||||
public class Column {
|
||||
private String field; //列名称
|
||||
private String type; //列类型
|
||||
private boolean notNull; //不为null
|
||||
private String comment; //列说明
|
||||
|
||||
public Column() {
|
||||
}
|
||||
|
||||
public Column(String name, String type, boolean notNull, String comment) {
|
||||
this.field = name;
|
||||
this.type = type;
|
||||
this.notNull = notNull;
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
//-----------------------
|
||||
public void setNull(String notNull) {
|
||||
this.notNull = "NO".equalsIgnoreCase(notNull) ? true : false;
|
||||
}
|
||||
}
|
||||
66
src/main/java/net/tccn/base/dbq/table/Field.java
Normal file
66
src/main/java/net/tccn/base/dbq/table/Field.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package net.tccn.base.dbq.table;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: liangxianyou at 2018/10/17 17:24.
|
||||
*/
|
||||
@Data
|
||||
public class Field {
|
||||
private String name;
|
||||
private String label;
|
||||
private String remark;
|
||||
private String type;
|
||||
private String inType;
|
||||
private String inExt;
|
||||
private Boolean pk; // 是否主键
|
||||
|
||||
public Field() {}
|
||||
|
||||
//------------------------------------
|
||||
public enum InType {
|
||||
SELECT_EXT("SELECT_EXT"),
|
||||
INPUT_DT("INPUT_DT"),
|
||||
FMT_FUN("FMT_FUN");
|
||||
|
||||
String name;
|
||||
|
||||
InType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public enum QueryType {
|
||||
|
||||
}
|
||||
|
||||
public String showField() {
|
||||
if (InType.SELECT_EXT.name.equalsIgnoreCase(inType)) {
|
||||
return name + "|" + inExt;
|
||||
} else if (InType.INPUT_DT.name.equalsIgnoreCase(inType)) {
|
||||
return name + "=dt";
|
||||
} else if (InType.FMT_FUN.name.equalsIgnoreCase(inType)) {
|
||||
return name + "=" + inExt;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isDict() {
|
||||
return InType.SELECT_EXT.name.equalsIgnoreCase(inType);
|
||||
}
|
||||
|
||||
public static Field toAs(Column column) {
|
||||
Field _bean = new Field();
|
||||
_bean.setName(column.getField());
|
||||
_bean.setType(column.getType());
|
||||
_bean.setLabel(column.getComment());
|
||||
|
||||
return _bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object name) {
|
||||
return (this.name == null && name == null) || this.name.equals(name);
|
||||
}
|
||||
}
|
||||
43
src/main/java/net/tccn/base/dbq/table/Table.java
Normal file
43
src/main/java/net/tccn/base/dbq/table/Table.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package net.tccn.base.dbq.table;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库表.
|
||||
* @author: liangxianyou at 2018/10/8 10:58.
|
||||
*/
|
||||
@Data
|
||||
public class Table {
|
||||
private String catalog; //库名称
|
||||
private String name; //表名称
|
||||
private String comment; //表备注
|
||||
private List<Column> columns = new ArrayList<>(); //表的字段列
|
||||
|
||||
public Table() {}
|
||||
public Table(String name, String comment) {
|
||||
this.name = name;
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
|
||||
//Dev
|
||||
public String _getTableDdl() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
buf.append("CREATE TABLE " + name + "(");
|
||||
columns.forEach(x -> {
|
||||
buf.append("\n " + x.getField() + " " + x.getType() + ",");
|
||||
});
|
||||
|
||||
buf.deleteCharAt(buf.length() - 1);
|
||||
buf.append("\n) COMMENT '" + comment + "';");
|
||||
return buf.toString();
|
||||
}
|
||||
//----------
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user