DatabaseQuery.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. package org.ssssssss.magicapi.functions;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.springframework.jdbc.core.ArgumentPreparedStatementSetter;
  4. import org.springframework.jdbc.core.RowMapper;
  5. import org.springframework.jdbc.datasource.DataSourceUtils;
  6. import org.springframework.jdbc.support.GeneratedKeyHolder;
  7. import org.springframework.jdbc.support.KeyHolder;
  8. import org.ssssssss.magicapi.cache.SqlCache;
  9. import org.ssssssss.magicapi.config.MagicDynamicDataSource;
  10. import org.ssssssss.magicapi.config.DynamicDataSource.DataSourceNode;
  11. import org.ssssssss.magicapi.config.MagicModule;
  12. import org.ssssssss.magicapi.dialect.Dialect;
  13. import org.ssssssss.magicapi.dialect.DialectUtils;
  14. import org.ssssssss.magicapi.exception.MagicAPIException;
  15. import org.ssssssss.magicapi.model.Page;
  16. import org.ssssssss.magicapi.provider.PageProvider;
  17. import org.ssssssss.magicapi.provider.ResultProvider;
  18. import org.ssssssss.script.MagicScriptContext;
  19. import org.ssssssss.script.annotation.UnableCall;
  20. import org.ssssssss.script.functions.StreamExtension;
  21. import org.ssssssss.script.parsing.GenericTokenParser;
  22. import org.ssssssss.script.parsing.Parser;
  23. import org.ssssssss.script.parsing.TokenStream;
  24. import org.ssssssss.script.parsing.Tokenizer;
  25. import java.sql.Connection;
  26. import java.sql.PreparedStatement;
  27. import java.sql.Statement;
  28. import java.util.*;
  29. import java.util.concurrent.atomic.AtomicBoolean;
  30. import java.util.function.Function;
  31. /**
  32. * 数据库查询模块
  33. */
  34. public class DatabaseQuery extends HashMap<String, DatabaseQuery> implements MagicModule {
  35. @UnableCall
  36. private MagicDynamicDataSource dynamicDataSource;
  37. @UnableCall
  38. private DataSourceNode dataSourceNode;
  39. @UnableCall
  40. private PageProvider pageProvider;
  41. @UnableCall
  42. private ResultProvider resultProvider;
  43. @UnableCall
  44. private RowMapper<Map<String, Object>> rowMapper;
  45. @UnableCall
  46. private SqlCache sqlCache;
  47. @UnableCall
  48. private String cacheName;
  49. @UnableCall
  50. private long ttl;
  51. public DatabaseQuery() {
  52. }
  53. public DatabaseQuery(MagicDynamicDataSource dynamicDataSource) {
  54. this.dynamicDataSource = dynamicDataSource;
  55. this.dataSourceNode = dynamicDataSource.getDataSource();
  56. }
  57. @UnableCall
  58. public void setPageProvider(PageProvider pageProvider) {
  59. this.pageProvider = pageProvider;
  60. }
  61. @UnableCall
  62. public void setResultProvider(ResultProvider resultProvider) {
  63. this.resultProvider = resultProvider;
  64. }
  65. @UnableCall
  66. public void setRowMapper(RowMapper<Map<String, Object>> rowMapper) {
  67. this.rowMapper = rowMapper;
  68. }
  69. @UnableCall
  70. public void setDynamicDataSource(MagicDynamicDataSource dynamicDataSource) {
  71. this.dynamicDataSource = dynamicDataSource;
  72. }
  73. @UnableCall
  74. public void setSqlCache(SqlCache sqlCache) {
  75. this.sqlCache = sqlCache;
  76. }
  77. @UnableCall
  78. public void setDataSourceNode(DataSourceNode dataSourceNode) {
  79. this.dataSourceNode = dataSourceNode;
  80. }
  81. @UnableCall
  82. public void setCacheName(String cacheName) {
  83. this.cacheName = cacheName;
  84. }
  85. @UnableCall
  86. public void setTtl(long ttl) {
  87. this.ttl = ttl;
  88. }
  89. @UnableCall
  90. public DatabaseQuery cloneQuery() {
  91. DatabaseQuery query = new DatabaseQuery();
  92. query.setDynamicDataSource(this.dynamicDataSource);
  93. query.setDataSourceNode(this.dataSourceNode);
  94. query.setPageProvider(this.pageProvider);
  95. query.setRowMapper(this.rowMapper);
  96. query.setSqlCache(this.sqlCache);
  97. query.setTtl(this.ttl);
  98. query.setResultProvider(this.resultProvider);
  99. return query;
  100. }
  101. /**
  102. * 开启事务,在一个回调中进行操作
  103. * @param function 回调函数
  104. * @return
  105. */
  106. public Object transaction(Function<?, ?> function) {
  107. Transaction transaction = transaction(); //创建事务
  108. try {
  109. Object val = function.apply(null);
  110. transaction.commit(); //提交事务
  111. return val;
  112. } catch (Throwable throwable) {
  113. transaction.rollback(); //回滚事务
  114. throw throwable;
  115. }
  116. }
  117. /**
  118. * 开启事务,手动提交和回滚
  119. * @return
  120. */
  121. public Transaction transaction() {
  122. return new Transaction(this.dataSourceNode.getDataSourceTransactionManager());
  123. }
  124. /**
  125. * 添加至缓存
  126. * @param value 缓存名
  127. */
  128. @UnableCall
  129. private <T> T putCacheValue(T value, BoundSql boundSql) {
  130. if (this.cacheName != null) {
  131. this.sqlCache.put(this.cacheName, boundSql.getCacheKey(this.sqlCache), value, this.ttl);
  132. }
  133. return value;
  134. }
  135. /**
  136. * 使用缓存
  137. * @param cacheName 缓存名
  138. * @param ttl 过期时间
  139. * @return
  140. */
  141. public DatabaseQuery cache(String cacheName, long ttl) {
  142. if (cacheName == null) {
  143. return this;
  144. }
  145. DatabaseQuery query = cloneQuery();
  146. query.setCacheName(cacheName);
  147. query.setTtl(ttl);
  148. return query;
  149. }
  150. /**
  151. * 使用缓存(采用默认缓存时间)
  152. * @param cacheName 缓冲名
  153. * @return
  154. */
  155. public DatabaseQuery cache(String cacheName) {
  156. return cache(cacheName, 0);
  157. }
  158. /**
  159. * 数据源切换
  160. */
  161. @Override
  162. public DatabaseQuery get(Object key) {
  163. DatabaseQuery query = cloneQuery();
  164. if (key == null) {
  165. query.setDataSourceNode(dynamicDataSource.getDataSource());
  166. } else {
  167. query.setDataSourceNode(dynamicDataSource.getDataSource(key.toString()));
  168. }
  169. return query;
  170. }
  171. /**
  172. * 查询List
  173. */
  174. public List<Map<String, Object>> select(String sql) {
  175. BoundSql boundSql = new BoundSql(sql);
  176. return (List<Map<String, Object>>) boundSql.getCacheValue(this.sqlCache, this.cacheName)
  177. .orElseGet(() -> putCacheValue(dataSourceNode.getJdbcTemplate().query(boundSql.getSql(), this.rowMapper, boundSql.getParameters()), boundSql));
  178. }
  179. /**
  180. * 执行update
  181. */
  182. public int update(String sql) {
  183. BoundSql boundSql = new BoundSql(sql);
  184. int value = dataSourceNode.getJdbcTemplate().update(boundSql.getSql(), boundSql.getParameters());
  185. if (this.cacheName != null) {
  186. this.sqlCache.delete(this.cacheName);
  187. }
  188. return value;
  189. }
  190. // public int save(String tableName,Map<String,Object> params){
  191. // return save(tableName,params,"id");
  192. // }
  193. /**
  194. * 如果已存在就修改,否则增加
  195. */
  196. // public int save(String tableName,Map<String,Object> data,String primaryKey){
  197. // Object[] params = new Object[]{data.get(primaryKey)};
  198. // Integer count = dataSourceNode.getJdbcTemplate().queryForObject("select count(1) from "+tableName+" where "+primaryKey+" = ?", params, Integer.class);
  199. // if(count > 0){
  200. // return jdbcUpdate(tableName,data,primaryKey);
  201. // }
  202. // return 0;
  203. // Object primaryKeyValue = data.get(primaryKey);
  204. // if(null == primaryKeyValue){
  205. // return jdbcInsert(tableName,data,primaryKey);
  206. // }
  207. // return jdbcUpdate(tableName,data,primaryKey);
  208. // }
  209. // public int jdbcUpdate(String tableName,Map<String,Object> data,String primaryKey){
  210. // StringBuffer sb = new StringBuffer();
  211. // sb.append("update ");
  212. // sb.append(tableName);
  213. // sb.append(" set ");
  214. // List<Object> params = new ArrayList<>();
  215. // for(Map.Entry<String, Object> entry : data.entrySet()){
  216. // String key = entry.getKey();
  217. // if(!key.equals(primaryKey)){
  218. // sb.append(key + "=" + "?,");
  219. // params.add(entry.getValue());
  220. // }
  221. // }
  222. // sb.append(" where ");
  223. // sb.append(primaryKey);
  224. // sb.append("=?");
  225. // params.add(data.get(primaryKey));
  226. // return dataSourceNode.getJdbcTemplate().update(sb.toString().replace("?, ","? "),params.toArray());
  227. // }
  228. //
  229. // public int jdbcInsert(String tableName,Map<String,Object> data,String primaryKey){
  230. // List<Object> params = new ArrayList<>();
  231. // params.add("");
  232. // List<String> fields = new ArrayList<>();
  233. // List<String> valuePlaceholders = new ArrayList<>();
  234. // StringBuffer sb = new StringBuffer();
  235. // sb.append("insert into ");
  236. // sb.append(tableName);
  237. // for(Map.Entry<String, Object> entry : data.entrySet()){
  238. // String key = entry.getKey();
  239. // if(!key.equals(primaryKey)){
  240. // fields.add(key);
  241. // valuePlaceholders.add("?");
  242. // params.add(entry.getValue());
  243. // }
  244. // }
  245. // sb.append("("+ primaryKey + "," + StringUtils.join(fields,",") +")");
  246. // sb.append(" values(?,"+StringUtils.join(valuePlaceholders,",")+")");
  247. // String id = UUID.randomUUID().toString().replace("-","");
  248. // params.set(0,id);
  249. // return dataSourceNode.getJdbcTemplate().update(sb.toString(),params.toArray());
  250. // }
  251. /**
  252. * 插入并返回主键
  253. */
  254. public long insert(String sql){
  255. BoundSql boundSql = new BoundSql(sql);
  256. KeyHolder keyHolder = new GeneratedKeyHolder();
  257. dataSourceNode.getJdbcTemplate().update(con -> {
  258. PreparedStatement ps = con.prepareStatement(boundSql.getSql(), Statement.RETURN_GENERATED_KEYS);
  259. new ArgumentPreparedStatementSetter(boundSql.getParameters()).setValues(ps);
  260. return ps;
  261. }, keyHolder);
  262. if (this.cacheName != null) {
  263. this.sqlCache.delete(this.cacheName);
  264. }
  265. Number key = keyHolder.getKey();
  266. if(key == null){
  267. return -1;
  268. }
  269. return key.longValue();
  270. }
  271. /**
  272. * 分页查询
  273. */
  274. public Object page(String sql) {
  275. Page page = pageProvider.getPage(MagicScriptContext.get());
  276. return page(sql, page.getLimit(), page.getOffset());
  277. }
  278. /**
  279. * 分页查询(手动传入limit和offset参数)
  280. */
  281. public Object page(String sql, long limit, long offset) {
  282. BoundSql boundSql = new BoundSql(sql);
  283. Connection connection = null;
  284. Dialect dialect;
  285. try {
  286. connection = dataSourceNode.getJdbcTemplate().getDataSource().getConnection();
  287. dialect = DialectUtils.getDialectFromUrl(connection.getMetaData().getURL());
  288. } catch (Exception e) {
  289. throw new MagicAPIException("自动获取数据库方言失败", e);
  290. } finally {
  291. DataSourceUtils.releaseConnection(connection, dataSourceNode.getJdbcTemplate().getDataSource());
  292. }
  293. if (dialect == null) {
  294. throw new MagicAPIException("自动获取数据库方言失败");
  295. }
  296. int count = (int) boundSql.getCacheValue(this.sqlCache, this.cacheName)
  297. .orElseGet(() -> putCacheValue(dataSourceNode.getJdbcTemplate().queryForObject(dialect.getCountSql(boundSql.getSql()), Integer.class, boundSql.getParameters()), boundSql));
  298. List<Object> list = null;
  299. if (count > 0) {
  300. String pageSql = dialect.getPageSql(boundSql.getSql(), boundSql, offset, limit);
  301. list = (List<Object>) boundSql.removeCacheKey().getCacheValue(this.sqlCache, this.cacheName)
  302. .orElseGet(() -> putCacheValue(dataSourceNode.getJdbcTemplate().query(pageSql, this.rowMapper, boundSql.getParameters()), boundSql));
  303. }
  304. return resultProvider.buildPageResult(count, list);
  305. }
  306. /**
  307. * 查询int值
  308. */
  309. public Integer selectInt(String sql) {
  310. BoundSql boundSql = new BoundSql(sql);
  311. return (Integer) boundSql.getCacheValue(this.sqlCache, this.cacheName)
  312. .orElseGet(() -> putCacheValue(dataSourceNode.getJdbcTemplate().queryForObject(boundSql.getSql(), boundSql.getParameters(), Integer.class), boundSql));
  313. }
  314. /**
  315. * 查询Map
  316. */
  317. public Map<String, Object> selectOne(String sql) {
  318. BoundSql boundSql = new BoundSql(sql);
  319. return (Map<String, Object>) boundSql.getCacheValue(this.sqlCache, this.cacheName)
  320. .orElseGet(() -> {
  321. List<Map<String, Object>> list = dataSourceNode.getJdbcTemplate().query(boundSql.getSql(), this.rowMapper, boundSql.getParameters());
  322. return list != null && list.size() > 0 ? list.get(0) : null;
  323. });
  324. }
  325. /**
  326. * 查询单行单列的值
  327. */
  328. public Object selectValue(String sql) {
  329. BoundSql boundSql = new BoundSql(sql);
  330. return boundSql.getCacheValue(this.sqlCache, this.cacheName)
  331. .orElseGet(() -> putCacheValue(dataSourceNode.getJdbcTemplate().queryForObject(boundSql.getSql(), boundSql.getParameters(), Object.class), boundSql));
  332. }
  333. private static Tokenizer tokenizer = new Tokenizer();
  334. private static GenericTokenParser concatTokenParser = new GenericTokenParser("${", "}", false);
  335. private static GenericTokenParser replaceTokenParser = new GenericTokenParser("#{", "}", true);
  336. private static GenericTokenParser ifTokenParser = new GenericTokenParser("?{", "}", true);
  337. private static GenericTokenParser ifParamTokenParser = new GenericTokenParser("?{", ",", true);
  338. @UnableCall
  339. @Override
  340. public String getModuleName() {
  341. return "db";
  342. }
  343. public static class BoundSql {
  344. private String sql;
  345. private List<Object> parameters = new ArrayList<>();
  346. private String cacheKey;
  347. BoundSql(String sql) {
  348. MagicScriptContext context = MagicScriptContext.get();
  349. // 处理?{}参数
  350. this.sql = ifTokenParser.parse(sql.trim(), text -> {
  351. AtomicBoolean ifTrue = new AtomicBoolean(false);
  352. String val = ifParamTokenParser.parse("?{" + text, param -> {
  353. Object result = Parser.parseExpression(new TokenStream(tokenizer.tokenize(param))).evaluate(context);
  354. //如果是String则判断是否是空,否则和判断值是否为true
  355. if (result != null) {
  356. if (result instanceof String) {
  357. ifTrue.set(!result.toString().isEmpty());
  358. } else {
  359. ifTrue.set(!Objects.equals(false, result));
  360. }
  361. }
  362. return null;
  363. });
  364. if (ifTrue.get()) {
  365. return val;
  366. }
  367. return "";
  368. });
  369. // 处理${}参数
  370. this.sql = concatTokenParser.parse(this.sql, text -> String.valueOf(Parser.parseExpression(new TokenStream(tokenizer.tokenize(text))).evaluate(context)));
  371. // 处理#{}参数
  372. this.sql = replaceTokenParser.parse(this.sql, text -> {
  373. Object value = Parser.parseExpression(new TokenStream(tokenizer.tokenize(text))).evaluate(context);
  374. try {
  375. //对集合自动展开
  376. List<Object> objects = StreamExtension.arrayLikeToList(value);
  377. StringBuilder sb = new StringBuilder();
  378. for (int i = 0, size = objects.size(); i < size; i++) {
  379. sb.append("?");
  380. if (i + 1 < size) {
  381. sb.append(",");
  382. }
  383. parameters.add(objects.get(i));
  384. }
  385. return sb.toString();
  386. } catch (Exception e) {
  387. parameters.add(value);
  388. return "?";
  389. }
  390. });
  391. }
  392. /**
  393. * 添加SQL参数
  394. */
  395. public void addParameter(Object value) {
  396. parameters.add(value);
  397. }
  398. /**
  399. * 获取要执行的SQL
  400. */
  401. public String getSql() {
  402. return sql;
  403. }
  404. /**
  405. * 获取要执行的参数
  406. */
  407. public Object[] getParameters() {
  408. return parameters.toArray();
  409. }
  410. /**
  411. * 清空缓存key
  412. */
  413. public BoundSql removeCacheKey() {
  414. this.cacheKey = null;
  415. return this;
  416. }
  417. /**
  418. * 获取缓存key
  419. */
  420. public String getCacheKey(SqlCache sqlCache) {
  421. if (cacheKey == null) {
  422. cacheKey = sqlCache.buildSqlCacheKey(this);
  423. }
  424. return cacheKey;
  425. }
  426. /**
  427. * 获取缓存值
  428. */
  429. public <T> Optional<T> getCacheValue(SqlCache sqlCache, String cacheName) {
  430. return Optional.ofNullable(cacheName == null ? null : sqlCache.get(cacheName, getCacheKey(sqlCache)));
  431. }
  432. }
  433. }