SQLModule.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. package org.ssssssss.magicapi.modules;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.springframework.dao.DataRetrievalFailureException;
  4. import org.springframework.dao.InvalidDataAccessApiUsageException;
  5. import org.springframework.jdbc.core.ArgumentPreparedStatementSetter;
  6. import org.springframework.jdbc.core.RowMapper;
  7. import org.springframework.jdbc.support.GeneratedKeyHolder;
  8. import org.ssssssss.magicapi.adapter.ColumnMapperAdapter;
  9. import org.ssssssss.magicapi.adapter.DialectAdapter;
  10. import org.ssssssss.magicapi.cache.SqlCache;
  11. import org.ssssssss.magicapi.config.MagicDynamicDataSource;
  12. import org.ssssssss.magicapi.config.MagicDynamicDataSource.DataSourceNode;
  13. import org.ssssssss.magicapi.config.MagicModule;
  14. import org.ssssssss.magicapi.context.RequestContext;
  15. import org.ssssssss.magicapi.dialect.Dialect;
  16. import org.ssssssss.magicapi.interceptor.SQLInterceptor;
  17. import org.ssssssss.magicapi.model.Page;
  18. import org.ssssssss.magicapi.model.RequestEntity;
  19. import org.ssssssss.magicapi.modules.table.NamedTable;
  20. import org.ssssssss.magicapi.provider.PageProvider;
  21. import org.ssssssss.magicapi.provider.ResultProvider;
  22. import org.ssssssss.script.MagicScriptContext;
  23. import org.ssssssss.script.annotation.Comment;
  24. import org.ssssssss.script.annotation.UnableCall;
  25. import java.sql.Connection;
  26. import java.sql.PreparedStatement;
  27. import java.sql.SQLException;
  28. import java.sql.Statement;
  29. import java.util.HashMap;
  30. import java.util.Iterator;
  31. import java.util.List;
  32. import java.util.Map;
  33. import java.util.function.Function;
  34. /**
  35. * 数据库查询模块
  36. */
  37. public class SQLModule extends HashMap<String, SQLModule> implements MagicModule {
  38. private MagicDynamicDataSource dynamicDataSource;
  39. private DataSourceNode dataSourceNode;
  40. private PageProvider pageProvider;
  41. private ResultProvider resultProvider;
  42. private ColumnMapperAdapter columnMapperAdapter;
  43. private DialectAdapter dialectAdapter;
  44. private RowMapper<Map<String, Object>> columnMapRowMapper;
  45. private Function<String, String> rowMapColumnMapper;
  46. private SqlCache sqlCache;
  47. private String cacheName;
  48. private List<SQLInterceptor> sqlInterceptors;
  49. private long ttl;
  50. public SQLModule() {
  51. }
  52. public SQLModule(MagicDynamicDataSource dynamicDataSource) {
  53. this.dynamicDataSource = dynamicDataSource;
  54. this.dataSourceNode = dynamicDataSource.getDataSource();
  55. }
  56. @UnableCall
  57. public void setPageProvider(PageProvider pageProvider) {
  58. this.pageProvider = pageProvider;
  59. }
  60. @UnableCall
  61. public void setResultProvider(ResultProvider resultProvider) {
  62. this.resultProvider = resultProvider;
  63. }
  64. @UnableCall
  65. public void setColumnMapperProvider(ColumnMapperAdapter columnMapperAdapter) {
  66. this.columnMapperAdapter = columnMapperAdapter;
  67. }
  68. @UnableCall
  69. public void setDialectAdapter(DialectAdapter dialectAdapter) {
  70. this.dialectAdapter = dialectAdapter;
  71. }
  72. @UnableCall
  73. public void setColumnMapRowMapper(RowMapper<Map<String, Object>> columnMapRowMapper) {
  74. this.columnMapRowMapper = columnMapRowMapper;
  75. }
  76. @UnableCall
  77. public void setRowMapColumnMapper(Function<String, String> rowMapColumnMapper) {
  78. this.rowMapColumnMapper = rowMapColumnMapper;
  79. }
  80. private void setDynamicDataSource(MagicDynamicDataSource dynamicDataSource) {
  81. this.dynamicDataSource = dynamicDataSource;
  82. }
  83. @UnableCall
  84. public void setSqlInterceptors(List<SQLInterceptor> sqlInterceptors) {
  85. this.sqlInterceptors = sqlInterceptors;
  86. }
  87. private void setDataSourceNode(DataSourceNode dataSourceNode) {
  88. this.dataSourceNode = dataSourceNode;
  89. }
  90. protected String getCacheName() {
  91. return cacheName;
  92. }
  93. private void setCacheName(String cacheName) {
  94. this.cacheName = cacheName;
  95. }
  96. protected long getTtl() {
  97. return ttl;
  98. }
  99. private void setTtl(long ttl) {
  100. this.ttl = ttl;
  101. }
  102. protected SqlCache getSqlCache() {
  103. return sqlCache;
  104. }
  105. @UnableCall
  106. public void setSqlCache(SqlCache sqlCache) {
  107. this.sqlCache = sqlCache;
  108. }
  109. @UnableCall
  110. private SQLModule cloneSQLModule() {
  111. SQLModule sqlModule = new SQLModule();
  112. sqlModule.setDynamicDataSource(this.dynamicDataSource);
  113. sqlModule.setDataSourceNode(this.dataSourceNode);
  114. sqlModule.setPageProvider(this.pageProvider);
  115. sqlModule.setColumnMapperProvider(this.columnMapperAdapter);
  116. sqlModule.setColumnMapRowMapper(this.columnMapRowMapper);
  117. sqlModule.setRowMapColumnMapper(this.rowMapColumnMapper);
  118. sqlModule.setSqlCache(this.sqlCache);
  119. sqlModule.setTtl(this.ttl);
  120. sqlModule.setResultProvider(this.resultProvider);
  121. sqlModule.setDialectAdapter(this.dialectAdapter);
  122. sqlModule.setSqlInterceptors(this.sqlInterceptors);
  123. return sqlModule;
  124. }
  125. /**
  126. * 开启事务,在一个回调中进行操作
  127. *
  128. * @param function 回调函数
  129. */
  130. @Comment("开启事务,并在回调中处理")
  131. public Object transaction(@Comment("回调函数,如:()=>{....}") Function<?, ?> function) {
  132. Transaction transaction = transaction(); //创建事务
  133. try {
  134. Object val = function.apply(null);
  135. transaction.commit(); //提交事务
  136. return val;
  137. } catch (Throwable throwable) {
  138. transaction.rollback(); //回滚事务
  139. throw throwable;
  140. }
  141. }
  142. /**
  143. * 开启事务,手动提交和回滚
  144. */
  145. @Comment("开启事务,返回事务对象")
  146. public Transaction transaction() {
  147. return new Transaction(this.dataSourceNode.getDataSourceTransactionManager());
  148. }
  149. /**
  150. * 使用缓存
  151. *
  152. * @param cacheName 缓存名
  153. * @param ttl 过期时间
  154. */
  155. @Comment("使用缓存")
  156. public SQLModule cache(@Comment("缓存名") String cacheName, @Comment("过期时间") long ttl) {
  157. if (cacheName == null) {
  158. return this;
  159. }
  160. SQLModule sqlModule = cloneSQLModule();
  161. sqlModule.setCacheName(cacheName);
  162. sqlModule.setTtl(ttl);
  163. return sqlModule;
  164. }
  165. /**
  166. * 使用缓存(采用默认缓存时间)
  167. *
  168. * @param cacheName 缓冲名
  169. */
  170. @Comment("使用缓存,过期时间采用默认配置")
  171. public SQLModule cache(@Comment("缓存名") String cacheName) {
  172. return cache(cacheName, 0);
  173. }
  174. @Comment("采用驼峰列名")
  175. public SQLModule camel() {
  176. return columnCase("camel");
  177. }
  178. @Comment("采用帕斯卡列名")
  179. public SQLModule pascal() {
  180. return columnCase("pascal");
  181. }
  182. @Comment("采用全小写列名")
  183. public SQLModule lower() {
  184. return columnCase("lower");
  185. }
  186. @Comment("采用全大写列名")
  187. public SQLModule upper() {
  188. return columnCase("upper");
  189. }
  190. @Comment("列名保持原样")
  191. public SQLModule normal() {
  192. return columnCase("default");
  193. }
  194. @Comment("指定列名转换")
  195. public SQLModule columnCase(String name) {
  196. SQLModule sqlModule = cloneSQLModule();
  197. sqlModule.setColumnMapRowMapper(this.columnMapperAdapter.getColumnMapRowMapper(name));
  198. sqlModule.setRowMapColumnMapper(this.columnMapperAdapter.getRowMapColumnMapper(name));
  199. return sqlModule;
  200. }
  201. /**
  202. * 数据源切换
  203. */
  204. @Override
  205. public SQLModule get(Object key) {
  206. SQLModule sqlModule = cloneSQLModule();
  207. if (key == null) {
  208. sqlModule.setDataSourceNode(dynamicDataSource.getDataSource());
  209. } else {
  210. sqlModule.setDataSourceNode(dynamicDataSource.getDataSource(key.toString()));
  211. }
  212. return sqlModule;
  213. }
  214. /**
  215. * 查询List
  216. */
  217. @Comment("查询SQL,返回List类型结果")
  218. public List<Map<String, Object>> select(@Comment("`SQL`语句") String sql) {
  219. return select(new BoundSql(sql, this));
  220. }
  221. @UnableCall
  222. public List<Map<String, Object>> select(BoundSql boundSql) {
  223. return boundSql.getCacheValue(this.sqlInterceptors, () -> dataSourceNode.getJdbcTemplate().query(boundSql.getSql(), this.columnMapRowMapper, boundSql.getParameters()));
  224. }
  225. /**
  226. * 执行update
  227. */
  228. @Comment("执行update操作,返回受影响行数")
  229. public int update(@Comment("`SQL`语句") String sql) {
  230. return update(new BoundSql(sql));
  231. }
  232. @UnableCall
  233. public int update(BoundSql boundSql) {
  234. sqlInterceptors.forEach(sqlInterceptor -> sqlInterceptor.preHandle(boundSql));
  235. int value = dataSourceNode.getJdbcTemplate().update(boundSql.getSql(), boundSql.getParameters());
  236. if (this.cacheName != null) {
  237. this.sqlCache.delete(this.cacheName);
  238. }
  239. return value;
  240. }
  241. /**
  242. * 插入并返回主键
  243. */
  244. @Comment("执行insert操作,返回插入主键")
  245. public long insert(@Comment("`SQL`语句") String sql) {
  246. MagicKeyHolder magicKeyHolder = new MagicKeyHolder();
  247. insert(new BoundSql(sql), magicKeyHolder);
  248. return magicKeyHolder.getLongKey();
  249. }
  250. /**
  251. * 插入并返回主键
  252. */
  253. @Comment("执行insert操作,返回插入主键")
  254. public Object insert(@Comment("`SQL`语句") String sql, @Comment("主键列") String primary) {
  255. return insert(new BoundSql(sql), primary);
  256. }
  257. void insert(BoundSql boundSql, MagicKeyHolder keyHolder) {
  258. sqlInterceptors.forEach(sqlInterceptor -> sqlInterceptor.preHandle(boundSql));
  259. dataSourceNode.getJdbcTemplate().update(con -> {
  260. PreparedStatement ps = keyHolder.createPrepareStatement(con, boundSql.getSql());
  261. new ArgumentPreparedStatementSetter(boundSql.getParameters()).setValues(ps);
  262. return ps;
  263. }, keyHolder);
  264. if (this.cacheName != null) {
  265. this.sqlCache.delete(this.cacheName);
  266. }
  267. }
  268. @UnableCall
  269. public Object insert(BoundSql boundSql, String primary) {
  270. MagicKeyHolder keyHolder = new MagicKeyHolder(primary);
  271. insert(boundSql, keyHolder);
  272. return keyHolder.getObjectKey();
  273. }
  274. /**
  275. * 分页查询
  276. */
  277. @Comment("执行分页查询,分页条件自动获取")
  278. public Object page(@Comment("`SQL`语句") String sql) {
  279. return page(new BoundSql(sql, this));
  280. }
  281. /**
  282. * 分页查询(手动传入limit和offset参数)
  283. */
  284. @Comment("执行分页查询,分页条件手动传入")
  285. public Object page(@Comment("`SQL`语句") String sql, @Comment("限制条数") long limit, @Comment("跳过条数") long offset) {
  286. BoundSql boundSql = new BoundSql(sql, this);
  287. return page(boundSql, new Page(limit, offset));
  288. }
  289. @UnableCall
  290. public Object page(BoundSql boundSql) {
  291. Page page = pageProvider.getPage(MagicScriptContext.get());
  292. return page(boundSql, page);
  293. }
  294. private Object page(BoundSql boundSql, Page page) {
  295. Dialect dialect = dataSourceNode.getDialect(dialectAdapter);
  296. BoundSql countBoundSql = boundSql.copy(dialect.getCountSql(boundSql.getSql()));
  297. int count = countBoundSql.getCacheValue(this.sqlInterceptors, () -> dataSourceNode.getJdbcTemplate().queryForObject(countBoundSql.getSql(), Integer.class, countBoundSql.getParameters()));
  298. List<Map<String, Object>> list = null;
  299. if (count > 0) {
  300. String pageSql = dialect.getPageSql(boundSql.getSql(), boundSql, page.getOffset(), page.getLimit());
  301. BoundSql pageBoundSql = boundSql.copy(pageSql);
  302. list = pageBoundSql.getCacheValue(this.sqlInterceptors, () -> dataSourceNode.getJdbcTemplate().query(pageBoundSql.getSql(), this.columnMapRowMapper, pageBoundSql.getParameters()));
  303. }
  304. RequestEntity requestEntity = RequestContext.getRequestEntity();
  305. return resultProvider.buildPageResult(requestEntity, page, count, list);
  306. }
  307. /**
  308. * 查询int值
  309. */
  310. @Comment("查询int值,适合单行单列int的结果")
  311. public Integer selectInt(@Comment("`SQL`语句") String sql) {
  312. BoundSql boundSql = new BoundSql(sql, this);
  313. return boundSql.getCacheValue(this.sqlInterceptors, () -> dataSourceNode.getJdbcTemplate().queryForObject(boundSql.getSql(), boundSql.getParameters(), Integer.class));
  314. }
  315. /**
  316. * 查询Map
  317. */
  318. @Comment("查询单条结果,查不到返回null")
  319. public Map<String, Object> selectOne(@Comment("`SQL`语句") String sql) {
  320. return selectOne(new BoundSql(sql, this));
  321. }
  322. @UnableCall
  323. public Map<String, Object> selectOne(BoundSql boundSql) {
  324. return boundSql.getCacheValue(this.sqlInterceptors, () -> {
  325. List<Map<String, Object>> list = dataSourceNode.getJdbcTemplate().query(boundSql.getSql(), this.columnMapRowMapper, boundSql.getParameters());
  326. return list.size() > 0 ? list.get(0) : null;
  327. });
  328. }
  329. /**
  330. * 查询单行单列的值
  331. */
  332. @Comment("查询单行单列的值")
  333. public Object selectValue(@Comment("`SQL`语句") String sql) {
  334. BoundSql boundSql = new BoundSql(sql, this);
  335. return boundSql.getCacheValue(this.sqlInterceptors, () -> dataSourceNode.getJdbcTemplate().queryForObject(boundSql.getSql(), boundSql.getParameters(), Object.class));
  336. }
  337. @Comment("指定table,进行单表操作")
  338. public NamedTable table(String tableName) {
  339. return new NamedTable(tableName, this, rowMapColumnMapper);
  340. }
  341. @UnableCall
  342. @Override
  343. public String getModuleName() {
  344. return "db";
  345. }
  346. class MagicKeyHolder extends GeneratedKeyHolder {
  347. private final boolean useGeneratedKeys;
  348. private final String primary;
  349. public MagicKeyHolder() {
  350. this(null);
  351. }
  352. public MagicKeyHolder(String primary) {
  353. this.primary = primary;
  354. this.useGeneratedKeys = StringUtils.isBlank(primary);
  355. }
  356. PreparedStatement createPrepareStatement(Connection connection, String sql) throws SQLException {
  357. if (useGeneratedKeys) {
  358. return connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
  359. }
  360. return connection.prepareStatement(sql, new String[]{primary});
  361. }
  362. public long getLongKey() throws InvalidDataAccessApiUsageException, DataRetrievalFailureException {
  363. Number key = super.getKey();
  364. if (key == null) {
  365. return -1;
  366. }
  367. return key.longValue();
  368. }
  369. public Object getObjectKey() {
  370. if (useGeneratedKeys) {
  371. return getLongKey();
  372. }
  373. List<Map<String, Object>> keyList = getKeyList();
  374. if (keyList.isEmpty()) {
  375. return null;
  376. }
  377. Iterator<Object> keyIterator = keyList.get(0).values().iterator();
  378. return keyIterator.hasNext() ? keyIterator.next() : null;
  379. }
  380. }
  381. }