use of org.sagacity.sqltoy.model.QueryExecutor in project sagacity-sqltoy by chenrenfei.
the class SqlToyDaoSupport method findEntityBase.
/**
* @TODO 提供findEntity的基础实现,供对外接口包装,额外开放了resultClass的自定义功能
* @param entityClass
* @param page 如分页查询则需指定,非分页则传null
* @param entityQuery
* @param resultClass 指定返回结果类型
* @param isCount
* @return
*/
private Object findEntityBase(Class entityClass, Page page, EntityQuery entityQuery, Class resultClass, boolean isCount) {
EntityMeta entityMeta = getEntityMeta(entityClass);
EntityQueryExtend innerModel = entityQuery.getInnerModel();
String translateFields = "";
// 将缓存翻译对应的查询补充到select column 上,形成select keyColumn as viewColumn 模式
if (!innerModel.translates.isEmpty()) {
Iterator<Translate> iter = innerModel.translates.values().iterator();
String keyColumn;
TranslateExtend extend;
while (iter.hasNext()) {
extend = iter.next().getExtend();
// 将java模式的字段名称转化为数据库字段名称
keyColumn = entityMeta.getColumnName(extend.keyColumn);
if (keyColumn == null) {
keyColumn = extend.keyColumn;
}
// 保留字处理
keyColumn = ReservedWordsUtil.convertWord(keyColumn, null);
translateFields = translateFields.concat(",").concat(keyColumn).concat(" as ").concat(extend.column);
}
}
// 将notSelect构造成select,形成统一处理机制
String[] selectFieldAry = null;
Set<String> notSelect = innerModel.notSelectFields;
if (notSelect != null) {
List<String> selectFields = new ArrayList<String>();
for (String field : entityMeta.getFieldsArray()) {
if (!notSelect.contains(field.toLowerCase())) {
selectFields.add(field);
}
}
if (selectFields.size() > 0) {
selectFieldAry = new String[selectFields.size()];
selectFields.toArray(selectFieldAry);
}
} else {
selectFieldAry = innerModel.fields;
}
// 指定的查询字段
String fields = "";
if (selectFieldAry != null && selectFieldAry.length > 0) {
int index = 0;
String colName;
HashSet<String> cols = new HashSet<String>();
boolean notAllPureField = false;
for (String field : selectFieldAry) {
// 去除重复字段
if (!cols.contains(field)) {
colName = entityMeta.getColumnName(field);
// 非表字段对应pojo的属性名称
if (colName == null) {
colName = field;
// 非字段名称
if (!entityMeta.getColumnFieldMap().containsKey(colName.toLowerCase())) {
notAllPureField = true;
} else {
// 保留字处理
colName = ReservedWordsUtil.convertWord(colName, null);
}
} else {
// 保留字处理
colName = ReservedWordsUtil.convertWord(colName, null);
}
if (index > 0) {
fields = fields.concat(",");
}
fields = fields.concat(colName);
index++;
cols.add(field);
}
}
// select 字段中可能存在max(field)或field as xxx等非字段形式
if (notAllPureField) {
fields = SqlUtil.convertFieldsToColumns(entityMeta, fields);
}
} else {
fields = entityMeta.getAllColumnNames();
}
String sql = "select ".concat((innerModel.distinct) ? " distinct " : "").concat(fields).concat(translateFields).concat(" from ").concat(entityMeta.getSchemaTable(null, null));
// where条件
String where = "";
// 动态组织where 后面的条件语句,此功能并不建议使用,where 一般需要指定明确条件
if (StringUtil.isBlank(innerModel.where)) {
if (innerModel.values != null && innerModel.values.length > 0) {
where = SqlUtil.wrapWhere(entityMeta);
}
} else {
where = SqlUtil.convertFieldsToColumns(entityMeta, innerModel.where);
}
if (StringUtil.isNotBlank(where)) {
sql = sql.concat(" where ").concat(where);
}
// 分组和having
if (StringUtil.isNotBlank(innerModel.groupBy)) {
sql = sql.concat(" group by ").concat(SqlUtil.convertFieldsToColumns(entityMeta, innerModel.groupBy));
if (StringUtil.isNotBlank(innerModel.having)) {
sql = sql.concat(" having ").concat(SqlUtil.convertFieldsToColumns(entityMeta, innerModel.having));
}
}
// 处理order by 排序
if (!innerModel.orderBy.isEmpty()) {
sql = sql.concat(" order by ");
Iterator<Entry<String, String>> iter = innerModel.orderBy.entrySet().iterator();
Entry<String, String> entry;
String columnName;
int index = 0;
while (iter.hasNext()) {
entry = iter.next();
columnName = entityMeta.getColumnName(entry.getKey());
if (columnName == null) {
columnName = entry.getKey();
}
// 保留字处理
columnName = ReservedWordsUtil.convertWord(columnName, null);
if (index > 0) {
sql = sql.concat(",");
}
// entry.getValue() is order way,like: desc or " "
sql = sql.concat(columnName).concat(entry.getValue());
index++;
}
}
QueryExecutor queryExecutor;
Class resultType = (resultClass == null) ? entityClass : resultClass;
// :named 模式(named模式参数值必须存在)
if (SqlConfigParseUtils.hasNamedParam(where) && StringUtil.isBlank(innerModel.names)) {
queryExecutor = new QueryExecutor(sql, (innerModel.values == null || innerModel.values.length == 0) ? null : (Serializable) innerModel.values[0]).resultType(resultType).dataSource(getDataSource(innerModel.dataSource)).fetchSize(innerModel.fetchSize).maxRows(innerModel.maxRows);
} else {
queryExecutor = new QueryExecutor(sql).names(innerModel.names).values(innerModel.values).resultType(resultType).dataSource(getDataSource(innerModel.dataSource)).fetchSize(innerModel.fetchSize).maxRows(innerModel.maxRows);
}
// 设置是否空白转null
queryExecutor.getInnerModel().blankToNull = innerModel.blankToNull;
// 设置额外的缓存翻译
if (!innerModel.translates.isEmpty()) {
queryExecutor.getInnerModel().translates.putAll(innerModel.translates);
}
// 设置额外的参数条件过滤
if (!innerModel.paramFilters.isEmpty()) {
queryExecutor.getInnerModel().paramFilters.addAll(innerModel.paramFilters);
}
// 设置安全脱敏
if (!innerModel.secureMask.isEmpty()) {
queryExecutor.getInnerModel().secureMask.putAll(innerModel.secureMask);
}
// 设置分页优化
queryExecutor.getInnerModel().pageOptimize = innerModel.pageOptimize;
SqlToyConfig sqlToyConfig = sqlToyContext.getSqlToyConfig(queryExecutor, SqlType.search, getDialect(queryExecutor.getInnerModel().dataSource));
// 加密字段,查询时解密
if (entityMeta.getSecureColumns() != null) {
sqlToyConfig.setDecryptColumns(entityMeta.getSecureColumns());
}
// 分库分表策略
setEntitySharding(queryExecutor, entityMeta);
if (innerModel.dbSharding != null) {
queryExecutor.getInnerModel().dbSharding = innerModel.dbSharding;
}
if (innerModel.tableSharding != null) {
ShardingStrategyConfig shardingConfig = innerModel.tableSharding;
// 补充表名称
shardingConfig.setTables(new String[] { entityMeta.getTableName() });
List<ShardingStrategyConfig> tableShardings = new ArrayList<ShardingStrategyConfig>();
tableShardings.add(shardingConfig);
queryExecutor.getInnerModel().tableShardings = tableShardings;
}
DataSource realDataSource = getDataSource(queryExecutor.getInnerModel().dataSource, sqlToyConfig);
// 取count数量
if (isCount) {
return dialectFactory.getCountBySql(sqlToyContext, queryExecutor, sqlToyConfig, realDataSource);
}
// 非分页
if (page == null) {
// 取top
if (innerModel.pickType == 0) {
return dialectFactory.findTop(sqlToyContext, queryExecutor, sqlToyConfig, innerModel.pickSize, realDataSource).getRows();
} else // 取随机记录
if (innerModel.pickType == 1) {
return dialectFactory.getRandomResult(sqlToyContext, queryExecutor, sqlToyConfig, innerModel.pickSize, realDataSource).getRows();
} else {
return dialectFactory.findByQuery(sqlToyContext, queryExecutor, sqlToyConfig, innerModel.lockMode, realDataSource).getRows();
}
}
// 跳过总记录数形式的分页
if (page.getSkipQueryCount()) {
return dialectFactory.findSkipTotalCountPage(sqlToyContext, queryExecutor, sqlToyConfig, page.getPageNo(), page.getPageSize(), realDataSource).getPageResult();
}
return dialectFactory.findPage(sqlToyContext, queryExecutor, sqlToyConfig, page.getPageNo(), page.getPageSize(), realDataSource).getPageResult();
}
use of org.sagacity.sqltoy.model.QueryExecutor in project sagacity-sqltoy by chenrenfei.
the class SqlToyDaoSupport method parallQuery.
/**
* @TODO 并行查询并返回一维List,有几个查询List中就包含几个结果对象,paramNames和paramValues是全部sql的条件参数的合集
* @param parallQueryList
* @param paramNames
* @param paramValues
* @param parallelConfig
* @return
*/
protected <T> List<QueryResult<T>> parallQuery(List<ParallQuery> parallQueryList, String[] paramNames, Object[] paramValues, ParallelConfig parallelConfig) {
if (parallQueryList == null || parallQueryList.isEmpty()) {
return null;
}
ParallelConfig parallConfig = parallelConfig;
if (parallConfig == null) {
parallConfig = new ParallelConfig();
}
// 并行线程数量(默认最大十个)
if (parallConfig.getMaxThreads() == null) {
parallConfig.maxThreads(10);
}
int thread = parallConfig.getMaxThreads();
if (parallQueryList.size() < thread) {
thread = parallQueryList.size();
}
List<QueryResult<T>> results = new ArrayList<QueryResult<T>>();
ExecutorService pool = null;
try {
pool = Executors.newFixedThreadPool(thread);
List<Future<ParallQueryResult>> futureResult = new ArrayList<Future<ParallQueryResult>>();
SqlToyConfig sqlToyConfig;
Future<ParallQueryResult> future;
for (ParallQuery query : parallQueryList) {
sqlToyConfig = sqlToyContext.getSqlToyConfig(new QueryExecutor(query.getExtend().sql).resultType(query.getExtend().resultType), SqlType.search, getDialect(query.getExtend().dataSource));
// 自定义条件参数
if (query.getExtend().selfCondition) {
future = pool.submit(new ParallQueryExecutor(sqlToyContext, dialectFactory, sqlToyConfig, query, query.getExtend().names, query.getExtend().values, getDataSource(query.getExtend().dataSource, sqlToyConfig)));
} else {
future = pool.submit(new ParallQueryExecutor(sqlToyContext, dialectFactory, sqlToyConfig, query, paramNames, paramValues, getDataSource(query.getExtend().dataSource, sqlToyConfig)));
}
futureResult.add(future);
}
pool.shutdown();
// 设置最大等待时长
if (parallConfig.getMaxWaitSeconds() != null) {
pool.awaitTermination(parallConfig.getMaxWaitSeconds(), TimeUnit.SECONDS);
} else {
pool.awaitTermination(SqlToyConstants.PARALLEL_MAXWAIT_SECONDS, TimeUnit.SECONDS);
}
ParallQueryResult item;
int index = 0;
for (Future<ParallQueryResult> result : futureResult) {
index++;
item = result.get();
// 存在执行异常则整体抛出
if (item != null && !item.isSuccess()) {
throw new DataAccessException("第:{} 个sql执行异常:{}!", index, item.getMessage());
}
results.add(item.getResult());
}
} catch (Exception e) {
e.printStackTrace();
throw new DataAccessException("并行查询执行错误:" + e.getMessage(), e);
} finally {
if (pool != null) {
pool.shutdownNow();
}
}
return results;
}
use of org.sagacity.sqltoy.model.QueryExecutor in project sagacity-sqltoy by chenrenfei.
the class SqlToyDaoSupport method deleteByQuery.
/**
* @TODO 提供单表简易查询进行删除操作(删除操作filters过滤无效)
* @param entityClass
* @param entityQuery
* @return
*/
protected Long deleteByQuery(Class entityClass, EntityQuery entityQuery) {
EntityQueryExtend innerModel = entityQuery.getInnerModel();
if (null == entityClass || null == entityQuery || StringUtil.isBlank(innerModel.where) || StringUtil.isBlank(innerModel.values)) {
throw new IllegalArgumentException("deleteByQuery entityClass、where、value 值不能为空!");
}
// 做一个必要提示
if (!innerModel.paramFilters.isEmpty()) {
logger.warn("删除操作设置动态条件过滤是无效的,数据删除查询条件必须是精准的!");
}
EntityMeta entityMeta = getEntityMeta(entityClass);
String where = SqlUtil.convertFieldsToColumns(entityMeta, innerModel.where);
String sql = "delete from ".concat(entityMeta.getSchemaTable(null, null)).concat(" where ").concat(where);
SqlToyConfig sqlToyConfig = getSqlToyConfig(sql, SqlType.update);
QueryExecutor queryExecutor = null;
// :named 模式
if (SqlConfigParseUtils.hasNamedParam(where) && StringUtil.isBlank(innerModel.names)) {
queryExecutor = new QueryExecutor(sql, (Serializable) innerModel.values[0]);
} else {
queryExecutor = new QueryExecutor(sql).names(innerModel.names).values(innerModel.values);
}
if (innerModel.paramFilters != null && innerModel.paramFilters.size() > 0) {
queryExecutor.getInnerModel().paramFilters.addAll(innerModel.paramFilters);
}
// 分库分表策略
setEntitySharding(queryExecutor, entityMeta);
return dialectFactory.executeSql(sqlToyContext, sqlToyConfig, queryExecutor, null, null, getDataSource(innerModel.dataSource));
}
use of org.sagacity.sqltoy.model.QueryExecutor in project sagacity-sqltoy by chenrenfei.
the class SqlToyDaoSupport method updateByQuery.
/**
* @TODO 针对单表对象查询进行更新操作(update和delete 操作filters过滤是无效的,必须是精准的条件参数)
* @param entityClass
* @param entityUpdate
* @update 2021-12-23 支持update table set field=field+1等计算模式
* @return
*/
protected Long updateByQuery(Class entityClass, EntityUpdate entityUpdate) {
if (null == entityClass || null == entityUpdate || StringUtil.isBlank(entityUpdate.getInnerModel().where) || StringUtil.isBlank(entityUpdate.getInnerModel().values) || entityUpdate.getInnerModel().updateValues.isEmpty()) {
throw new IllegalArgumentException("updateByQuery: entityClass、where条件、条件值value、变更值setValues不能为空!");
}
EntityUpdateExtend innerModel = entityUpdate.getInnerModel();
boolean isName = SqlConfigParseUtils.hasNamedParam(innerModel.where);
Object[] values = innerModel.values;
String[] paramNames = null;
String where = innerModel.where;
int valueSize = (values == null) ? 0 : values.length;
// 重新通过对象反射获取参数条件的值
if (isName) {
if (values.length > 1) {
throw new IllegalArgumentException("updateByQuery: where条件采用:paramName形式传参,values只能传递单个VO或Map对象!");
}
paramNames = SqlConfigParseUtils.getSqlParamsName(where, false);
values = BeanUtil.reflectBeanToAry(values[0], paramNames);
// 重新设置值数组的长度
valueSize = values.length;
} else {
if (DialectUtils.getParamsCount(where) != valueSize) {
throw new IllegalArgumentException("updateByQuery: where语句中的?数量跟对应values 数组长度不一致,请检查!");
}
}
EntityMeta entityMeta = getEntityMeta(entityClass);
// 处理where 中写的java 字段名称为数据库表字段名称
where = SqlUtil.convertFieldsToColumns(entityMeta, where);
StringBuilder sql = new StringBuilder();
sql.append("update ").append(entityMeta.getSchemaTable(null, null)).append(" set ");
Entry<String, Object> entry;
// 对统一更新字段做处理
IUnifyFieldsHandler unifyHandler = getSqlToyContext().getUnifyFieldsHandler();
if (unifyHandler != null) {
Map<String, Object> updateFields = unifyHandler.updateUnifyFields();
if (updateFields != null && !updateFields.isEmpty()) {
Iterator<Entry<String, Object>> updateIter = updateFields.entrySet().iterator();
while (updateIter.hasNext()) {
entry = updateIter.next();
// 是数据库表的字段
if (entityMeta.getColumnName(entry.getKey()) != null) {
// 是否已经主动update
if (innerModel.updateValues.containsKey(entry.getKey())) {
// 判断是否存在强制更新
if (unifyHandler.forceUpdateFields() != null && unifyHandler.forceUpdateFields().contains(entry.getKey())) {
innerModel.updateValues.put(entry.getKey(), entry.getValue());
}
} else {
innerModel.updateValues.put(entry.getKey(), entry.getValue());
}
}
}
}
}
Object[] realValues = new Object[innerModel.updateValues.size() + valueSize];
if (valueSize > 0) {
System.arraycopy(values, 0, realValues, innerModel.updateValues.size(), valueSize);
}
Integer[] paramsTypes = new Integer[realValues.length];
for (int i = 0; i < paramsTypes.length; i++) {
paramsTypes[i] = java.sql.Types.OTHER;
}
String[] realNames = null;
if (isName) {
realNames = new String[realValues.length];
System.arraycopy(paramNames, 0, realNames, innerModel.updateValues.size(), valueSize);
}
int index = 0;
String columnName;
FieldMeta fieldMeta;
Iterator<Entry<String, Object>> iter = innerModel.updateValues.entrySet().iterator();
String[] fields;
String fieldSetValue;
// 设置一个扩展标志,避免set field=field+? 场景构造成field=field+:fieldExtParam跟where
// field=:field名称冲突
final String extSign = "ExtParam";
while (iter.hasNext()) {
entry = iter.next();
// 考虑 field=filed+? 模式,分割成2部分
fields = entry.getKey().split("=");
fieldMeta = entityMeta.getFieldMeta(fields[0].trim());
// entry.getKey() 直接是数据库字段名称
if (fieldMeta == null) {
// 先通过数据字段名称获得类的属性名称再获取fieldMeta
fieldMeta = entityMeta.getFieldMeta(entityMeta.getColumnFieldMap().get(fields[0].trim().toLowerCase()));
}
columnName = fieldMeta.getColumnName();
// 设置字段类型
if (fields.length == 1) {
paramsTypes[index] = fieldMeta.getType();
}
// 保留字处理
columnName = ReservedWordsUtil.convertWord(columnName, null);
if (isName) {
if (fields.length > 1) {
if (fields[1].contains("?")) {
// 拼接扩展字符,避免where后面有同样的参数名称
realNames[index] = fieldMeta.getFieldName().concat(extSign);
} else {
realNames[index] = SqlConfigParseUtils.getSqlParamsName(fields[1], true)[0];
}
} else {
realNames[index] = fieldMeta.getFieldName();
}
}
realValues[index] = entry.getValue();
if (index > 0) {
sql.append(",");
}
if (fields.length == 1) {
sql.append(columnName).append("=").append(isName ? (":" + fieldMeta.getFieldName()) : "?");
} else {
// field=filed+? 类似模式
fieldSetValue = fields[1];
sql.append(columnName).append("=");
if (isName && fieldSetValue.contains("?")) {
fieldSetValue = fieldSetValue.replace("?", ":" + fieldMeta.getFieldName().concat(extSign));
}
fieldSetValue = SqlUtil.convertFieldsToColumns(entityMeta, fieldSetValue);
sql.append(fieldSetValue);
}
index++;
}
sql.append(" where ").append(where);
String sqlStr = sql.toString();
SqlToyConfig sqlToyConfig = sqlToyContext.getSqlToyConfig(sqlStr, SqlType.update, getDialect(innerModel.dataSource));
QueryExecutor queryExecutor = new QueryExecutor(sqlStr).names(realNames).values(realValues);
setEntitySharding(queryExecutor, entityMeta);
return dialectFactory.executeSql(sqlToyContext, sqlToyConfig, queryExecutor, paramsTypes, null, getDataSource(innerModel.dataSource, sqlToyConfig));
}
use of org.sagacity.sqltoy.model.QueryExecutor in project sagacity-sqltoy by chenrenfei.
the class DialectFactory method executeStore.
/**
* @todo 存储过程调用
* @param sqlToyContext
* @param sqlToyConfig
* @param inParamsValue
* @param outParamsType
* @param resultType
* @param dataSource
* @return
*/
public StoreResult executeStore(final SqlToyContext sqlToyContext, final SqlToyConfig sqlToyConfig, final Object[] inParamsValue, final Integer[] outParamsType, final Class resultType, final DataSource dataSource) {
try {
Long startTime = System.currentTimeMillis();
SqlExecuteStat.start(sqlToyConfig.getId(), "executeStore", sqlToyConfig.isShowSql());
StoreResult result = (StoreResult) DataSourceUtils.processDataSource(sqlToyContext, dataSource, new DataSourceCallbackHandler() {
@Override
public void doConnection(Connection conn, Integer dbType, String dialect) throws Exception {
String dialectSql = sqlToyConfig.getSql(dialect);
int inCount = (inParamsValue == null) ? 0 : inParamsValue.length;
int outCount = (outParamsType == null) ? 0 : outParamsType.length;
// sql中问号数量
int paramCnt = StringUtil.matchCnt(dialectSql, ARG_PATTERN);
// 处理参数注入
if (paramCnt != inCount + outCount) {
throw new IllegalArgumentException("存储过程语句中的输入和输出参数跟实际调用传递的数量不等!");
}
SqlToyResult sqlToyResult = new SqlToyResult(dialectSql, inParamsValue);
// 判断是否是{?=call xxStore()} 模式(oracle 不支持此模式)
boolean isFirstResult = StringUtil.matches(dialectSql, STORE_PATTERN);
// 将call xxxStore(?,?) 后的条件参数判断是否为null,如果是null则改为call xxxStore(null,?,null)
// 避免设置类型错误
SqlConfigParseUtils.replaceNull(sqlToyResult, isFirstResult ? 1 : 0);
// 针对不同数据库执行存储过程调用
SqlExecuteStat.showSql("存储过程执行", sqlToyResult.getSql(), sqlToyResult.getParamsValue());
StoreResult queryResult = getDialectSqlWrapper(dbType).executeStore(sqlToyContext, sqlToyConfig, sqlToyResult.getSql(), sqlToyResult.getParamsValue(), outParamsType, conn, dbType, dialect, -1);
// 进行数据必要的数据处理(一般存储过程不会结合旋转sql进行数据旋转操作)
// {此区域代码正常情况下不会使用
QueryExecutor queryExecutor = new QueryExecutor(null, sqlToyConfig.getParamsName(), inParamsValue);
List pivotCategorySet = ResultUtils.getPivotCategory(sqlToyContext, sqlToyConfig, queryExecutor, conn, dbType, dialect);
boolean changedCols = ResultUtils.calculate(sqlToyContext.getDesensitizeProvider(), sqlToyConfig, queryResult, pivotCategorySet, null);
// 映射成对象
if (resultType != null) {
queryResult.setRows(ResultUtils.wrapQueryResult(sqlToyContext, queryResult.getRows(), queryResult.getLabelNames(), resultType, changedCols, true, false, null, null));
}
SqlExecuteStat.debug("执行结果", "存储过程影响记录:{} 条!", queryResult.getRecordCount());
this.setResult(queryResult);
}
});
result.setExecuteTime(System.currentTimeMillis() - startTime);
return result;
} catch (Exception e) {
SqlExecuteStat.error(e);
throw new DataAccessException(e);
} finally {
SqlExecuteStat.destroy();
}
}
Aggregations