use of org.sagacity.sqltoy.config.model.SqlToyConfig in project sagacity-sqltoy by chenrenfei.
the class TranslateConfigParse method parseTranslateConfig.
/**
* @todo 解析translate配置文件
* @param sqlToyContext
* @param translateMap 最终缓存配置,构建一个空map,在解析过程中填充
* @param checker 更新检测配置
* @param translateConfig 缓存配置文件
* @param charset
* @return
* @throws Exception
*/
public static DefaultConfig parseTranslateConfig(final SqlToyContext sqlToyContext, final IgnoreKeyCaseMap<String, TranslateConfigModel> translateMap, final List<CheckerConfigModel> checker, String translateConfig, String charset) throws Exception {
// 判断缓存翻译的配置文件是否存在
if (FileUtil.getFileInputStream(translateConfig) == null) {
logger.warn("缓存翻译配置文件:{}无法加载,请检查配路径正确性,如不使用缓存翻译可忽略此提示!", translateConfig);
return null;
}
return (DefaultConfig) XMLUtil.readXML(translateConfig, charset, false, new XMLCallbackHandler() {
@Override
public Object process(Document doc, Element root) throws Exception {
DefaultConfig defaultConfig = new DefaultConfig();
NodeList nodeList = root.getElementsByTagName("cache-translates");
if (nodeList.getLength() == 0) {
return defaultConfig;
}
// 解析缓存翻译配置
Element node = (Element) nodeList.item(0);
XMLUtil.setAttributes(node, defaultConfig);
NodeList elts;
Element elt;
NodeList sqlNode;
String sql;
String sqlId;
boolean isShowSql;
int index = 1;
for (String translateType : TRANSLATE_TYPES) {
elts = node.getElementsByTagName(translateType.concat(TRANSLATE_SUFFIX));
if (elts.getLength() > 0) {
for (int i = 0; i < elts.getLength(); i++) {
elt = (Element) elts.item(i);
TranslateConfigModel translateCacheModel = new TranslateConfigModel();
// 设置默认值
translateCacheModel.setHeap(defaultConfig.getDefaultHeap());
translateCacheModel.setOffHeap(defaultConfig.getDefaultOffHeap());
translateCacheModel.setDiskSize(defaultConfig.getDefaultDiskSize());
translateCacheModel.setKeepAlive(defaultConfig.getDefaultKeepAlive());
XMLUtil.setAttributes(elt, translateCacheModel);
translateCacheModel.setType(translateType);
// 非sqlId模式定义
if (translateType.equals("sql")) {
if (StringUtil.isBlank(translateCacheModel.getSql())) {
sqlNode = elt.getElementsByTagName("sql");
if (sqlNode.getLength() > 0) {
sql = StringUtil.trim(sqlNode.item(0).getTextContent());
} else {
sql = StringUtil.trim(elt.getTextContent());
}
sqlId = "s_trans_cache_0" + index;
isShowSql = StringUtil.matches(sql, SqlToyConstants.NOT_PRINT_REGEX);
SqlToyConfig sqlToyConfig = new SqlToyConfig(sqlId, SqlUtil.clearMistyChars(SqlUtil.clearMark(sql), " "));
sqlToyConfig.setShowSql(!isShowSql);
sqlToyConfig.setParamsName(SqlConfigParseUtils.getSqlParamsName(sqlToyConfig.getSql(null), true));
sqlToyContext.putSqlToyConfig(sqlToyConfig);
translateCacheModel.setSql(sqlId);
index++;
}
}
// local模式是避免一些额外争议的产物,有部分开发者坚持缓存要应用自己管理
if (translateType.equals("local") && !elt.hasAttribute("keep-alive")) {
translateCacheModel.setKeepAlive(-1);
}
translateMap.put(translateCacheModel.getCache(), translateCacheModel);
logger.debug("已经加载缓存翻译:cache={},type={}", (translateCacheModel.getCache() == null) ? "[非增量]" : translateCacheModel.getCache(), translateType);
}
}
}
nodeList = root.getElementsByTagName("cache-update-checkers");
// 解析更新检测器
if (nodeList.getLength() == 0) {
return defaultConfig;
}
node = (Element) nodeList.item(0);
// 集群节点时间偏差(秒)
if (node.hasAttribute("cluster-time-deviation")) {
defaultConfig.setDeviationSeconds(Integer.parseInt(node.getAttribute("cluster-time-deviation")));
if (Math.abs(defaultConfig.getDeviationSeconds()) > 60) {
logger.debug("您设置的集群节点时间差异参数cluster-time-deviation={} 秒>60秒,将设置为60秒!", defaultConfig.getDeviationSeconds());
defaultConfig.setDeviationSeconds(-60);
} else {
defaultConfig.setDeviationSeconds(0 - Math.abs(defaultConfig.getDeviationSeconds()));
}
}
String nodeType;
index = 1;
// 缓存更新检测
for (String translateType : TRANSLATE_CHECKER_TYPES) {
nodeType = translateType.concat(CHECKER_SUFFIX);
elts = node.getElementsByTagName(nodeType);
if (elts.getLength() > 0) {
for (int i = 0; i < elts.getLength(); i++) {
elt = (Element) elts.item(i);
CheckerConfigModel checherConfigModel = new CheckerConfigModel();
XMLUtil.setAttributes(elt, checherConfigModel);
// 数据交互类型
checherConfigModel.setType(translateType.replace("-increment", ""));
// 增量方式更新
if (translateType.endsWith("-increment")) {
checherConfigModel.setIncrement(true);
// 增量方式必须要指定缓存名称
if (StringUtil.isBlank(checherConfigModel.getCache())) {
logger.error("translate update checker:{} must config with cache=\"xxx\"!", nodeType);
throw new IllegalArgumentException(nodeType + " must config with cache=\"xxx\"");
}
}
// sql模式且非sqlId模式定义
if (checherConfigModel.getType().equals("sql")) {
if (StringUtil.isBlank(checherConfigModel.getSql())) {
sqlId = (checherConfigModel.isIncrement() ? "s_trans_merge_chk_0" : "s_trans_chk_0") + index;
sqlNode = elt.getElementsByTagName("sql");
if (sqlNode.getLength() > 0) {
sql = StringUtil.trim(sqlNode.item(0).getTextContent());
} else {
sql = StringUtil.trim(elt.getTextContent());
}
isShowSql = StringUtil.matches(sql, SqlToyConstants.NOT_PRINT_REGEX);
SqlToyConfig sqlToyConfig = new SqlToyConfig(sqlId, SqlUtil.clearMistyChars(SqlUtil.clearMark(sql), " "));
sqlToyConfig.setShowSql(!isShowSql);
sqlToyConfig.setParamsName(SqlConfigParseUtils.getSqlParamsName(sqlToyConfig.getSql(null), true));
// 增加条件参数检查,避免开发者手误然后找不到原因!有出现:lastUpdateTime 和 lastUpdateTimee 的找半天发现不了问题的!
if (sqlToyConfig.getParamsName() != null && sqlToyConfig.getParamsName().length > 1) {
throw new IllegalArgumentException("请检查缓存更新检测sql语句中的参数名称,所有参数名称要保持一致为lastUpdateTime!当前有:" + sqlToyConfig.getParamsName().length + " 个不同条件参数名!");
}
sqlToyContext.putSqlToyConfig(sqlToyConfig);
checherConfigModel.setSql(sqlId);
index++;
}
}
// 剔除tab\回车等特殊字符
String frequency = SqlUtil.clearMistyChars(checherConfigModel.getCheckFrequency(), "");
List<TimeSection> timeSections = new ArrayList<TimeSection>();
// frequency的格式 frequency="0..12?15,12..18:30?10,18:30..24?60"
if (StringUtil.isNotBlank(frequency)) {
// 统一格式,去除全角字符,去除空白
frequency = StringUtil.toDBC(frequency).replaceAll("\\;", ",").trim();
// 可以是单个频率值,表示0到24小时采用统一的频率
if (NumberUtil.isInteger(frequency)) {
TimeSection section = new TimeSection();
section.setStart(0);
section.setEnd(2400);
section.setIntervalSeconds(Integer.parseInt(frequency));
timeSections.add(section);
} else {
// 归整分割符号统一为逗号,将时间格式由HH:mm 转为HHmm格式
String[] sectionsStr = frequency.split("\\,");
for (int j = 0; j < sectionsStr.length; j++) {
TimeSection section = new TimeSection();
// 问号切割获取时间区间和时间间隔
String[] sectionPhase = sectionsStr[j].split("\\?");
// 获取开始和结束时间点
String[] startEnd = sectionPhase[0].split("\\.{2}");
section.setIntervalSeconds(Integer.parseInt(sectionPhase[1].trim()));
section.setStart(getHourMinute(startEnd[0].trim()));
section.setEnd(getHourMinute(startEnd[1].trim()));
timeSections.add(section);
}
}
}
checherConfigModel.setTimeSections(timeSections);
checker.add(checherConfigModel);
logger.debug("已经加载针对缓存:{} 更新的检测器,type={}", checherConfigModel.getCache(), translateType);
}
}
}
return defaultConfig;
}
});
}
use of org.sagacity.sqltoy.config.model.SqlToyConfig in project sagacity-sqltoy by chenrenfei.
the class SqlToyDaoSupport method loadByQuery.
/**
* TODO 通过构造QueyExecutor 提供更加灵活的参数传递方式,包括DataSource 比如:
* <li>1、new QueryExecutor(sql,entity).dataSource(dataSource)</li>
* <li>2、new
* QueryExecutor(sql).names(paramNames).values(paramValues).resultType(resultType);
* </li>
*
* @param queryExecutor
* @return
*/
protected Object loadByQuery(final QueryExecutor queryExecutor) {
QueryExecutorExtend extend = queryExecutor.getInnerModel();
SqlToyConfig sqlToyConfig = sqlToyContext.getSqlToyConfig(queryExecutor, SqlType.search, getDialect(extend.dataSource));
QueryResult result = dialectFactory.findByQuery(sqlToyContext, queryExecutor, sqlToyConfig, null, this.getDataSource(extend.dataSource, sqlToyConfig));
List rows = result.getRows();
if (rows == null || rows.isEmpty()) {
return null;
}
if (rows.size() == 1) {
return rows.get(0);
}
throw new IllegalArgumentException("loadByQuery查询出:" + rows.size() + " 条记录,不符合load查询预期!");
}
use of org.sagacity.sqltoy.config.model.SqlToyConfig 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.config.model.SqlToyConfig in project sagacity-sqltoy by chenrenfei.
the class DialectFactory method findByQuery.
/**
* @todo 查询符合条件的数据集合
* @param sqlToyContext
* @param queryExecutor
* @param sqlToyConfig
* @param lockMode
* @param dataSource
* @return
*/
public QueryResult findByQuery(final SqlToyContext sqlToyContext, final QueryExecutor queryExecutor, final SqlToyConfig sqlToyConfig, final LockMode lockMode, final DataSource dataSource) {
final QueryExecutorExtend extend = queryExecutor.getInnerModel();
// 合法校验
if (StringUtil.isBlank(extend.sql)) {
throw new IllegalArgumentException("findByQuery operate sql is null!");
}
try {
Long startTime = System.currentTimeMillis();
// 规整查询参数名称和参数名称对应的值
QueryExecutorBuilder.initQueryExecutor(sqlToyContext, extend, sqlToyConfig, false);
SqlExecuteStat.start(sqlToyConfig.getId(), "findByQuery", sqlToyConfig.isShowSql());
QueryResult result = (QueryResult) DataSourceUtils.processDataSource(sqlToyContext, ShardingUtils.getShardingDataSource(sqlToyContext, sqlToyConfig, queryExecutor, dataSource), new DataSourceCallbackHandler() {
@Override
public void doConnection(Connection conn, Integer dbType, String dialect) throws Exception {
// 处理sql中的?为统一的:named形式,并进行sharding table替换
SqlToyConfig realSqlToyConfig = DialectUtils.getUnifyParamsNamedConfig(sqlToyContext, sqlToyConfig, queryExecutor, dialect, false);
// 通过参数处理最终的sql和参数值
SqlToyResult queryParam = SqlConfigParseUtils.processSql(realSqlToyConfig.getSql(dialect), extend.getParamsName(realSqlToyConfig), extend.getParamsValue(sqlToyContext, realSqlToyConfig), dialect);
QueryResult queryResult = getDialectSqlWrapper(dbType).findBySql(sqlToyContext, realSqlToyConfig, queryParam.getSql(), queryParam.getParamsValue(), extend.rowCallbackHandler, wrapDecryptHandler(sqlToyContext, extend.resultType), conn, lockMode, dbType, dialect, getFetchSize(extend.fetchSize), extend.maxRows);
if (queryResult.getRows() != null && !queryResult.getRows().isEmpty()) {
// 存在计算和旋转的数据不能映射到对象(数据类型不一致,如汇总平均以及数据旋转)
List pivotCategorySet = ResultUtils.getPivotCategory(sqlToyContext, realSqlToyConfig, queryExecutor, conn, dbType, dialect);
// 对查询结果进行计算处理:字段脱敏、格式化、数据旋转、同步环比、分组汇总等
boolean changedCols = ResultUtils.calculate(sqlToyContext.getDesensitizeProvider(), realSqlToyConfig, queryResult, pivotCategorySet, extend);
// 将结果映射对象单独出来为了解耦,性能影响其实可以忽略,上万条也是1毫秒级
if (extend.resultType != null) {
queryResult.setRows(ResultUtils.wrapQueryResult(sqlToyContext, queryResult.getRows(), queryResult.getLabelNames(), (Class) extend.resultType, changedCols, extend.humpMapLabel, extend.hiberarchy, extend.hiberarchyClasses, extend.fieldsMap));
}
}
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();
}
}
use of org.sagacity.sqltoy.config.model.SqlToyConfig in project sagacity-sqltoy by chenrenfei.
the class DialectFactory method updateFetch.
/**
* @todo 查询锁定记录,并进行修改
* @param sqlToyContext
* @param queryExecutor
* @param sqlToyConfig
* @param updateRowHandler
* @param dataSource
* @return
*/
public QueryResult updateFetch(final SqlToyContext sqlToyContext, final QueryExecutor queryExecutor, final SqlToyConfig sqlToyConfig, final UpdateRowHandler updateRowHandler, final DataSource dataSource) {
final QueryExecutorExtend extend = queryExecutor.getInnerModel();
try {
Long startTime = System.currentTimeMillis();
SqlExecuteStat.start(sqlToyConfig.getId(), "updateFetch", sqlToyConfig.isShowSql());
// 组织参数和参数校验,但忽视数据权限数据的传参和校验
QueryExecutorBuilder.initQueryExecutor(sqlToyContext, extend, sqlToyConfig, false);
QueryResult result = (QueryResult) DataSourceUtils.processDataSource(sqlToyContext, ShardingUtils.getShardingDataSource(sqlToyContext, sqlToyConfig, queryExecutor, dataSource), new DataSourceCallbackHandler() {
@Override
public void doConnection(Connection conn, Integer dbType, String dialect) throws Exception {
// 处理sql中的?为统一的:named形式
SqlToyConfig realSqlToyConfig = DialectUtils.getUnifyParamsNamedConfig(sqlToyContext, sqlToyConfig, queryExecutor, dialect, false);
SqlToyResult queryParam = SqlConfigParseUtils.processSql(realSqlToyConfig.getSql(dialect), extend.getParamsName(realSqlToyConfig), extend.getParamsValue(sqlToyContext, realSqlToyConfig), dialect);
QueryResult queryResult = getDialectSqlWrapper(dbType).updateFetch(sqlToyContext, realSqlToyConfig, queryParam.getSql(), queryParam.getParamsValue(), updateRowHandler, conn, dbType, dialect, (extend.lockMode == null) ? LockMode.UPGRADE : extend.lockMode, getFetchSize(extend.fetchSize), extend.maxRows);
if (extend.resultType != null) {
queryResult.setRows(ResultUtils.wrapQueryResult(sqlToyContext, queryResult.getRows(), queryResult.getLabelNames(), (Class) extend.resultType, false, extend.humpMapLabel, extend.hiberarchy, extend.hiberarchyClasses, extend.fieldsMap));
}
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