package com.yanzuoguang.dao.impl; import com.yanzuoguang.dao.DaoConst; import com.yanzuoguang.dao.QueryPara; import com.yanzuoguang.dao.TableAnnotation; import com.yanzuoguang.db.DbExecute; import com.yanzuoguang.db.impl.DbRow; import com.yanzuoguang.util.base.ObjectHelper; import com.yanzuoguang.util.cache.MemoryCache; import com.yanzuoguang.util.helper.ArrayHelper; import com.yanzuoguang.util.helper.StringFormatHandle; import com.yanzuoguang.util.helper.StringHelper; import com.yanzuoguang.util.vo.*; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.*; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * SQL语句基本操作类,包括SQL语句的解析,参数的组装,查询缓存的处理 * * @author 颜佐光 */ public abstract class BaseDaoSql implements ApplicationContextAware { /** * SQL语句支持的最大长度 */ public static int MAX_LEVEL = 10; /** * 数据库执行类 */ private DbExecute db; /** * 定义列表记录缓存对象 */ protected MemoryCache cacheList = new MemoryCache(0); /** * 当前Dao的表结构SQL语句信息 */ protected TableSqlCache table = null; /** * 缓存的表结构和SQL语句 */ protected final static MemoryCache<TableSqlCache> cache = new MemoryCache<>(); /** * 构造函数 */ public BaseDaoSql() { this.initTable(); this.init(); } /** * 自己构造 * * @param db * @param table */ public BaseDaoSql(DbExecute db, TableSqlCache table) { this.db = db; this.table = table; this.init(); } /** * Set the ApplicationContext that this object runs in. * Normally this call will be used to initialize the object. * <p>Invoked after population of normal bean properties but before an init callback such * as {@link InitializingBean#afterPropertiesSet()} * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader}, * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and * {@link MessageSourceAware}, if applicable. * * @param applicationContext the ApplicationContext object to be used by this object * @throws ApplicationContextException in case of context initialization errors * @throws BeansException if thrown by application context methods * @see BeanInitializationException */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.db = applicationContext.getBean(DbExecute.class); } public void setDb(DbExecute db) { this.db = db; } /** * 获取数据库执行类 * * @return */ protected DbExecute getDb() { return db; } public TableSqlCache getTable() { return table; } /** * 初始化当前类对应的SQL语句对象 */ private void initTable() { String cls = this.getClass().getName(); // 外检测,防止锁影响性能 this.table = cache.get(cls); // 判断是否已经取到对象 if (this.table == null) { this.table = new TableSqlCache(); cache.put(cls, this.table); } } /** * 注册SQL语句 */ protected abstract void init(); /** * 注册表结构,会根据实体以及表名自动创建Create、update、remove、Load等SQL语句 * * @param clsModel 操作的实体,主键放在第一位,其他字段放到后面;需要注意的是必需和表结构对应起来,会有隐性BUG,比如说在实体中增加了字段,会导致增加修改失败 * @return 当前的表结构 */ protected TableSqlCache register(Class<?> clsModel) { TableAnnotation annotation = clsModel.getAnnotation(TableAnnotation.class); if (annotation == null) { throw new RuntimeException("该页面未绑定表"); } return this.register(annotation.value(), clsModel); } /** * 注册表结构,会根据实体以及表名自动创建Create、update、remove、Load等SQL语句 * * @param tableName 表名,数据库中的表名 * @param clsModel 操作的实体,主键放在第一位,其他字段放到后面;需要注意的是必需和表结构对应起来,会有隐性BUG,比如说在实体中增加了字段,会导致增加修改失败 * @return 当前的表结构 */ protected TableSqlCache register(String tableName, Class<?> clsModel) { // 生成表结构 TableStruct table = new TableStruct(tableName, clsModel); // 根据表结构生成基本的SQL语句 table.init(this.table); return this.table; } /** * 获取SQL语句 * * @param name 需要获取的SQL语句的名称 * @return 对应名称的SQL语句 */ public SqlData getSql(String name) { return getSql(name, true); } /** * 获取SQL语句 * * @param name 需要获取的SQL语句的名称 * @return 对应名称的SQL语句 */ public SqlData getSql(String name, boolean isThrow) { if (this.table == null) { throw new RuntimeException("类" + this.getClass().getName() + "未发现表结构"); } SqlData sql = this.table.getNameCache().get(name); if (isThrow && sql == null) { throw new RuntimeException("类" + this.getClass().getName() + "未发现SQL语句" + name); } return sql; } /** * 当更新数据时 * * @param model 更新时的数据 */ protected void onUpdateSql(Object model) { // 删除所有查询的缓存 cacheList.clear(); } /** * 执行更新语句 * * @param sqlData 需要执行的语句 * @param model 执行的实体 * @return 影响的行数 */ protected int updateSql(SqlData sqlData, Object model) { List<Object> paras = new ArrayList<Object>(); String sql = this.getQueryPara(paras, sqlData, model); int ret = this.getDb().update(this.getClass(), sqlData.getName(), sql, paras.toArray()); this.onUpdateSql(model); return ret; } /** * 更新SQL语句 * * @param sqlName 参数对应的名称 * @param model 参数对应的实体 * @return 修改成功,返回修改条数,否则为0 */ public int updateSql(String sqlName, Object model) { SqlData sqlData = this.getSql(sqlName); int ret = updateSql(sqlData, model); return ret; } /** * 是否需要复制一个新的 * * @param sqlData * @param queryPara * @param copy */ protected SqlData getSqlQueryPara(SqlData sqlData, QueryPara queryPara, boolean copy) { SqlData copyTo = sqlData; if (queryPara != null && queryPara.isLoadRemove()) { if (copyTo.getField(DaoConst.REMOVE_FLAG_INPUT) != null) { if (copy) { copyTo = sqlData.copy(); } copyTo.removeField(DaoConst.REMOVE_FLAG_INPUT); } } return copyTo; } /** * 根据SQL语句信息查询数据 * * @param sqlData SQL语句信息 * @param model 前台参数 * @return 查询的结果 */ protected List<MapRow> queryData(SqlData sqlData, Object model) { return this.queryData(MapRow.class, sqlData, model); } /** * 根据SQL语句信息查询数据 * * @param cls 数据结果类型 * @param sqlData SQL语句信息 * @param model 前台参数 * @param <T> 返回数据类型 * @return 查询的结果 */ protected <T extends Object> List<T> queryData(Class<T> cls, SqlData sqlData, Object model) { List<Object> paras = new ArrayList<Object>(); String sql = this.getQueryPara(paras, sqlData, model); List<T> list = this.queryWithCache(cls, sqlData.getName(), sql, paras.toArray()); return list; } /** * 查询不分页数据 * * @param cls 数据结果类型 * @param sqlData SQL数据 * @param model 前台参数 * @param <T> 返回数据类型 */ protected <T extends Object> void queryData(Class<T> cls, DbRow<T> handle, SqlData sqlData, Object model) { List<Object> paras = new ArrayList<>(); String sql = this.getQueryPara(paras, sqlData, model); // 查询数据 this.getDb().query(this.getClass(), cls, handle, sqlData.getName(), sql, paras.toArray()); } /** * 根据SQL名称获取第一个单元格 * * @param sqlName 需要执行的SQL语句的名称 * @param model 需要转化的实体 * @return 处理参数 */ public Object queryCell(String sqlName, Object model) { return this.queryCell(this.getSql(sqlName), model); } /** * 根据SQL语句信息查询第一个单元格 * * @param sqlData SQL语句信息 * @param model 前台参数 * @return 查询的结果 */ protected Object queryCell(SqlData sqlData, Object model) { return this.queryCell(sqlData, model, null); } /** * 根据SQL语句信息查询第一个单元格 * * @param sqlData SQL语句信息 * @param model 前台参数 * @return 查询的结果 */ protected Object queryCell(SqlData sqlData, Object model, QueryPara queryPara) { sqlData = getSqlQueryPara(sqlData, queryPara, true); List<Object> paras = new ArrayList<>(); String sql = this.getQueryPara(paras, sqlData, model); Object cell = this.queryCellWithCache(sqlData.getName(), sql, paras.toArray()); return cell; } /** * 查询不分页数据 * * @param sqlName SQL语句名称 * @param model 前台参数 * @return 查询的结果 */ public List<MapRow> query(String sqlName, Object model) { return this.query(MapRow.class, sqlName, model); } /** * 查询不分页数据 * * @param cls 数据结果类型 * @param sqlName SQL语句名称 * @param model 前台参数 * @param <T> 返回数据类型 * @return 查询的结果 */ public <T extends Object> List<T> query(Class<T> cls, String sqlName, Object model) { return this.query(cls, sqlName, model, null); } /** * 查询不分页数据 * * @param cls 数据结果类型 * @param sqlName SQL语句名称 * @param model 前台参数 * @param <T> 返回数据类型 * @return 查询的结果 */ public <T extends Object> List<T> query(Class<T> cls, String sqlName, Object model, QueryPara queryPara) { SqlData sqlData = this.getSql(sqlName); sqlData = getSqlQueryPara(sqlData, queryPara, true); return queryData(cls, sqlData, model); } /** * 查询不分页数据 * * @param cls 数据结果类型 * @param handle 需要处理的数据 * @param sqlName SQL语句名称 * @param model 前台参数 * @return 查询的结果 */ public <T extends Object> void query(Class<T> cls, DbRow<T> handle, String sqlName, Object model) { this.query(cls, handle, sqlName, model, null); } /** * 查询不分页数据 * * @param cls 数据结果类型 * @param handle 需要处理的数据 * @param sqlName SQL语句名称 * @param model 前台参数 * @return 查询的结果 */ public <T extends Object> void query(Class<T> cls, DbRow<T> handle, String sqlName, Object model, QueryPara queryPara) { SqlData sqlData = this.getSql(sqlName); // 获取查询参数处理后的SQL语句 sqlData = getSqlQueryPara(sqlData, queryPara, true); queryData(cls, handle, sqlData, model); } /** * 查询第一条数据 * * @param sqlName SQL语句名称 * @param model 前台参数 * @return 查询的结果 */ public MapRow queryFirst(String sqlName, Object model) { return this.queryFirst(MapRow.class, sqlName, model); } /** * 查询第一条数据 * * @param cls 数据结果类型 * @param sqlName SQL语句名称 * @param model 前台参数 * @param <T> 返回数据类型 * @return 查询的结果 */ public <T extends Object> T queryFirst(Class<T> cls, String sqlName, Object model) { return this.queryFirst(cls, sqlName, model, null); } /** * 查询第一条数据 * * @param cls 数据结果类型 * @param sqlName SQL语句名称 * @param model 前台参数 * @param <T> 返回数据类型 * @return 查询的结果 */ public <T extends Object> T queryFirst(Class<T> cls, String sqlName, Object model, QueryPara queryPara) { PageSizeReq pageSize = new PageSizeReqVo(); pageSize.setPageIndex(1); pageSize.setPageSize(1); List<T> list = this.queryPageData(cls, pageSize, sqlName, model, queryPara); T retVal = list.size() > 0 ? list.get(0) : null; return retVal; } /** * 查询分页数据,仅仅只是查询分页中的数据,不查询分页信息。如:包含的总数据数量 * * @param pageSize 分页参数 * @param sqlName SQL语句名称 * @param model 前台参数 * @return 查询的结果 */ public List<MapRow> queryPageData(PageSizeReqVo pageSize, String sqlName, Object model) { return this.queryPageData(MapRow.class, pageSize, sqlName, model); } /** * 查询分页数据,仅仅只是查询分页中的数据,不查询分页信息。如:包含的总数据数量 * * @param cls 数据结果类型 * @param pageSize 分页参数 * @param sqlName SQL语句名称 * @param model 前台参数 * @param <T> 返回数据类型 * @return 查询的结果 */ public <T extends Object> List<T> queryPageData(Class<T> cls, PageSizeReq pageSize, String sqlName, Object model) { return this.queryPageData(cls, pageSize, sqlName, model, null); } /** * 查询分页数据,仅仅只是查询分页中的数据,不查询分页信息。如:包含的总数据数量 * * @param cls 数据结果类型 * @param pageSize 分页参数 * @param sqlName SQL语句名称 * @param model 前台参数 * @param <T> 返回数据类型 * @return 查询的结果 */ public <T extends Object> List<T> queryPageData(Class<T> cls, PageSizeReq pageSize, String sqlName, Object model, QueryPara queryPara) { SqlData from = this.getSql(sqlName); // 对SQL语句进行分页处理 SqlData to = from.copy(); // 获取sql语句 to = getSqlQueryPara(to, queryPara, false); to.setSql(from.getSql()); to.addCode("{LIMIT}", " LIMIT " + pageSize.getPageStart() + "," + pageSize.getPageSize()); return queryData(cls, to, model); } /** * 查询分页数据,仅仅只是查询分页中的数据,不查询分页信息。如:包含的总数据数量 * * @param pageSize 分页参数 * @param sqlName SQL语句名称 * @param model 前台参数 * @return 查询的结果 */ public PageSizeData<MapRow> queryPage(PageSizeReqVo pageSize, String sqlName, Object model) { return this.queryPage(MapRow.class, pageSize, sqlName, model); } /** * 查询分页数据,仅仅只是查询分页中的数据。如:包含的总数据数量 * * @param cls 数据结果类型 * @param pageSize 分页参数 * @param sqlName SQL语句名称 * @param model 前台参数 * @param <T> 返回数据类型 * @return 查询的结果 */ public <T extends Object> PageSizeData<T> queryPage(Class<T> cls, PageSizeReqVo pageSize, String sqlName, Object model) { return queryPage(cls, pageSize, sqlName, model, null); } /** * 查询分页数据,仅仅只是查询分页中的数据。如:包含的总数据数量 * * @param cls 数据结果类型 * @param pageSize 分页参数 * @param sqlName SQL语句名称 * @param model 前台参数 * @param <T> 返回数据类型 * @return 查询的结果 */ public <T extends Object> PageSizeData<T> queryPage(Class<T> cls, PageSizeReqVo pageSize, String sqlName, Object model, QueryPara queryPara) { // 获取需要执行的SQL语句 SqlData from = this.getSql(sqlName); // 设置基本参数值 PageSizeData<T> data = new PageSizeData<T>(); data.setPageIndex(pageSize.getPageIndex()); data.setPageSize(pageSize.getPageSize()); // 对SQL语句进行分页处理 SqlData to = from.copy(); to = getSqlQueryPara(to, queryPara, false); to.addCode("{LIMIT}", " LIMIT " + pageSize.getPageStart() + "," + pageSize.getPageSize()); // 按照分页查询数据 List<Object> paras = new ArrayList<Object>(); String sql = this.getQueryPara(paras, to, model); // 查询实体数据 List<T> list = this.queryWithCache(cls, sqlName, sql, paras.toArray()); data.setList(list); // 查询分页总条数的SQL语句 String sqlTo = sql; // 获取分页查询的SQL语句 SqlData fromPageSize = getSql(sqlName + TableSqlCache.PAGE_SIZE_TAG, false); if (fromPageSize != null) { sqlTo = getQueryPara(new ArrayList<>(), fromPageSize, model); } sqlTo = sqlTo.trim(); // 查询总数据量 String sqlSize = "SELECT COUNT(1) FROM (" + // 去掉最后一个order by sqlTo.replaceAll("(?i)(ORDER\\s+BY\\s+[^)]+){0,1}(limit\\s+\\d+,\\d+\\s*){0,1}$", "") // 去掉第一个 SELECT a.* .replaceAll("(^SELECT)\\s+a\\.\\*", "$1 1 AS __id") + ") t"; data.setPageTotal(StringHelper.toInt(queryCellWithCache(String.format("%s.Size", sqlName), sqlSize, paras.toArray()))); return data; } /** * 获取SQL语句的参数 * * @param paras SQL语句 * @param sqlData SQL语句的参数 * @param model 参数的实体 * @return SQL条件 */ protected String getQueryPara(List<Object> paras, SqlData sqlData, Object model) { // 将SQL语句进行代码片段追加 StringBuilder sb = new StringBuilder(sqlData.getSql()); for (String code : DaoConst.LAST_AUTO_ADD) { if (sb.indexOf(code) == -1) { sb.append(code); } } // 代码片段缓存 Map<String, List<String>> codeMap = new HashMap<>(DaoConst.COLLECTION_INIT_SIZE); // 处理字段以及代码片段 String sql = sb.toString(); // 对查询条件进行初始化 if (model instanceof InitDaoQuery) { ((InitDaoQuery) model).initCond(); } sql = handleCodeRelease(sql, sqlData, model, codeMap); sql = handleCodeReplace(sqlData, sql, codeMap); // 通过正则表达式处理参数 @name 并替换SQL语句成 ? sql = handlePara(sql, paras, model); return sql; } /** * 处理代码片段替换 * * @param sql 代码片段 * @param codeMap 替换内容 * @return Sql语句值 */ protected String handleCodeReplace(SqlData sqlData, String sql, Map<String, List<String>> codeMap) { // 最大处理层数量,默认最小1层 int level = Math.max(1, MAX_LEVEL); for (int i = 0; i < level; i++) { // 判断是否寻找到标签 final boolean[] find = {false}; sql = StringHelper.getFormat(sql, StringHelper.EMPTY, new StringFormatHandle() { @Override public void addPos(StringBuilder sb, String group, String fieldFull, String field, String command) { // 设置寻找到标签 find[0] = true; // 寻找到的代码片段 不包含分括号 String name = group.trim().toLowerCase(); List<String> codes = codeMap.containsKey(name) ? codeMap.get(name) : new ArrayList<>(); for (String code : codes) { sb.append(" "); sb.append(code); } sb.append(" "); } }); // 当没有寻找到时,则进行其他处理 if (!find[0]) { break; } } sql = sql.replaceAll("\\s+", " "); return sql; } /** * 生成代码片段缓存 * * @param sql sql语句 * @param sqlData sql语句实体 * @param model 实体参数 * @param codeMap 缓存对象 * @return */ private String handleCodeRelease(String sql, SqlData sqlData, Object model, Map<String, List<String>> codeMap) { // 循环处理字段 for (SqlDataField field : sqlData.getSqlDataFields()) { sql = field.getCond().getSql(sql, sqlData, field, model, codeMap); } return sql; } /** * 通过正则表达式处理参数 @name 并替换SQL语句成 ? * * @param sql 需要处理的SQL语句 * @param paras 需要添加的参数 * @param model 需要获取的参数实体 * @return 处理后的SQL语句 */ private String handlePara(String sql, List<Object> paras, Object model) { String regex = "@([a-zA-Z0-9_]+)"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(sql); // 寻找到的代码片段 不包含分括号 while (m.find()) { // SQL参数名称 @name\s String name = m.group(); // 对应的前台输入字段 name String field = m.group(1); // 根据输入字段从参数中取值 Object val = ObjectHelper.get(model, field); if (val instanceof SqlCodeParameter) { sql = getSqlCodeParameter(paras, sql, name, (SqlCodeParameter) val); } else { // 判断是否为数组 boolean isArray = ArrayHelper.isArrayOrList(val); if (isArray) { sql = getListSql(paras, sql, name, val); } else { // 当参数不为数组时,则直接增加 sql = sql.replaceFirst(name, "?"); val = this.getParaValue(val); paras.add(val); } } } return sql; } /** * 获取处理后的参数值 * * @param val 获取参数值 * @return 处理后的参数值 */ private Object getParaValue(Object val) { if (val instanceof Boolean) { val = (Boolean) val ? 1 : 0; } else if (val instanceof Double || val instanceof Float) { val = StringHelper.toDouble(val); } val = StringHelper.toString(val); return val; } /** * 获取列表的SQL语句 * * @param paras 参数 * @param sql SQL语句 * @param name 名称 * @param val 值 * @return 获取包含列表的SQL语句的值 */ private String getListSql(List<Object> paras, String sql, String name, Object val) { List list = ArrayHelper.getList(val); int length = list.size(); // 进行循环 StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { Object item = list.get(i); // 判断列表是否为常规对象 if (item == null || item instanceof Number || item.getClass().isEnum() || item instanceof String || item instanceof Date) { addArrayIn(paras, sb, i, item); } else if (item instanceof CaseSqlModel) { addArrayCase(paras, sb, i, (CaseSqlModel) item); } else { addArrayTable(paras, sb, i, item); } } // 生成最终的SQL语句 sql = sql.replaceFirst(name, sb.toString()); return sql; } /** * 获取代码片段 * * @param paras * @param sql * @param name * @param val * @return */ protected String getSqlCodeParameter(List<Object> paras, String sql, String name, SqlCodeParameter val) { StringBuilder sb = new StringBuilder(); for (Object item : val.getLatitude()) { String codeTo = StringHelper.getCodeString(val.getLatitudeCode(), item); sb.append(codeTo); } sql = sql.replaceFirst(name, sb.toString()); return sql; } /** * 添加数组型参数 * * @param paras 参数列表 * @param sb 字符串数组 * @param i 序号 * @param from 参数值 */ private void addArrayIn(List<Object> paras, StringBuilder sb, int i, Object from) { // 添加连接字符串 if (i > 0) { sb.append(","); } // 添加参数SQL语句 sb.append("?"); Object to = this.getParaValue(from); paras.add(to); } /** * 添加 CASE型字段 * * @param paras 参数列表 * @param sb 字符串数组 * @param i 序号 * @param from 参数值 */ private void addArrayCase(List<Object> paras, StringBuilder sb, int i, CaseSqlModel from) { // 添加连接字符串 if (i > 0) { sb.append(","); } sb.append(from.getFrom()); switch (from.getGroupType()) { case CaseSqlModel.GROUP_TYPE_SUM: sb.append("SUM"); break; case CaseSqlModel.GROUP_TYPE_COUNT: sb.append("COUNT"); break; case CaseSqlModel.GROUP_TYPE_MAX: sb.append("MAX"); break; case CaseSqlModel.GROUP_TYPE_MIN: sb.append("MIN"); break; case CaseSqlModel.GROUP_TYPE_AVG: sb.append("AVG"); break; default: throw new RuntimeException("统计类型[" + from.getGroupType() + "]不支持"); } sb.append("( CASE WHEN "); sb.append(from.getCaseField()); sb.append(" "); if (from.getCaseValue() != null) { sb.append("=?"); paras.add(from.getCaseValue()); } sb.append(from.getAndWhere()); sb.append(" THEN "); if (!StringHelper.isEmpty(from.getValueField())) { sb.append(from.getValueField()); } else if (!StringHelper.isEmpty(from.getValue())) { sb.append("?"); paras.add(from.getValue()); } sb.append(" ELSE 0 END )"); sb.append(from.getTo()); sb.append(" AS "); sb.append(from.getToName()); } /** * 添加表格型参数,将列表转换成表格 * * @param paras 参数列表 * @param sb 字符串数组 * @param i 序号 * @param from 参数值 */ private void addArrayTable(List<Object> paras, StringBuilder sb, int i, Object from) { // 添加连接字符串 if (i > 0) { sb.append(" UNION ALL "); } // 将对象转换为 Map 对象 Map<String, Object> to = new HashMap<>(DaoConst.COLLECTION_INIT_SIZE); if (from instanceof Map) { to = (Map) from; } else { ObjectHelper.writeWithFromClass(to, from); } // 生成SQL语句 int column = 0; sb.append(" SELECT "); // 处理列 for (Map.Entry<String, Object> oItemKey : to.entrySet()) { if (column > 0) { sb.append(","); } String itemKey = oItemKey.getKey(); sb.append("? AS " + itemKey); // 处理参数 Object itemValue = oItemKey.getValue(); itemValue = this.getParaValue(itemValue); paras.add(itemValue); column++; } } /** * 根据缓存查询第一个单元格 * * @param sqlName 需要执行的SQL语句名称 * @param sql 需要执行的SQL语句 * @param paras SQL语句的参数 * @return 查询的结果 */ protected Object queryCellWithCache(String sqlName, String sql, Object... paras) { // 生成缓存的主键 String cacheKey = getCacheKey(Object.class, sql, paras); // 获取缓存 Object cache = this.cacheList.get(cacheKey); // 返回缓存 if (cache != null) { return cache; } // 查询数据 Object ret = this.getDb().queryCell(this.getClass(), sqlName, sql, paras); // 写入缓存 this.cacheList.put(cacheKey, ret); return ret; } /** * 执行查询SQL语句,并将数据缓存起来 * * @param cls 返回的类型 * @param sqlName 需要执行的SQL语句名称 * @param sql 需要执行的SQL语句 * @param paras 执行的SQL语句的参数 * @param <T> 返回的泛型 * @return 需要返回的数据 */ protected <T> List<T> queryWithCache(Class<T> cls, String sqlName, String sql, Object... paras) { // 生成缓存的主键 String cacheKey = getCacheKey(cls, sql, paras); // 获取缓存 Object cache = this.cacheList.get(cacheKey); // 返回缓存 if (cache != null) { return (List<T>) cache; } // 查询数据 List<T> ret = this.getDb().query(this.getClass(), cls, sqlName, sql, paras); // 写入缓存 this.cacheList.put(cacheKey, ret); return ret; } /** * 获取缓存的键值对 * * @param cls 结果类型 * @param sql SQL语句 * @param paras SQL语句参数 * @return 返回的结果 */ protected String getCacheKey(Class<?> cls, String sql, Object... paras) { StringBuilder sb = new StringBuilder(); sb.append(cls.getName()); sb.append(":"); sb.append(sql); for (Object para : paras) { sb.append(":"); sb.append(para); } return StringHelper.md5(sb.toString()); } }