Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.ssssssss.magicapi.modules.SQLModule Maven / Gradle / Ivy
package org.ssssssss.magicapi.modules;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.ArgumentPreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.ssssssss.magicapi.adapter.ColumnMapperAdapter;
import org.ssssssss.magicapi.adapter.DialectAdapter;
import org.ssssssss.magicapi.cache.SqlCache;
import org.ssssssss.magicapi.config.MagicDynamicDataSource;
import org.ssssssss.magicapi.config.MagicDynamicDataSource.DataSourceNode;
import org.ssssssss.magicapi.config.MagicModule;
import org.ssssssss.magicapi.context.RequestContext;
import org.ssssssss.magicapi.dialect.Dialect;
import org.ssssssss.magicapi.interceptor.SQLInterceptor;
import org.ssssssss.magicapi.model.Page;
import org.ssssssss.magicapi.model.RequestEntity;
import org.ssssssss.magicapi.modules.table.NamedTable;
import org.ssssssss.magicapi.provider.PageProvider;
import org.ssssssss.magicapi.provider.ResultProvider;
import org.ssssssss.script.MagicScriptContext;
import org.ssssssss.script.annotation.Comment;
import org.ssssssss.script.annotation.UnableCall;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* 数据库查询模块
*/
public class SQLModule extends HashMap implements MagicModule {
private MagicDynamicDataSource dynamicDataSource;
private DataSourceNode dataSourceNode;
private PageProvider pageProvider;
private ResultProvider resultProvider;
private ColumnMapperAdapter columnMapperAdapter;
private DialectAdapter dialectAdapter;
private RowMapper> columnMapRowMapper;
private Function rowMapColumnMapper;
private SqlCache sqlCache;
private String cacheName;
private List sqlInterceptors;
private long ttl;
private String logicDeleteColumn;
private String logicDeleteValue;
public SQLModule() {
}
public SQLModule(MagicDynamicDataSource dynamicDataSource) {
this.dynamicDataSource = dynamicDataSource;
this.dataSourceNode = dynamicDataSource.getDataSource();
}
@UnableCall
public void setPageProvider(PageProvider pageProvider) {
this.pageProvider = pageProvider;
}
@UnableCall
public void setResultProvider(ResultProvider resultProvider) {
this.resultProvider = resultProvider;
}
@UnableCall
public void setColumnMapperProvider(ColumnMapperAdapter columnMapperAdapter) {
this.columnMapperAdapter = columnMapperAdapter;
}
@UnableCall
public void setDialectAdapter(DialectAdapter dialectAdapter) {
this.dialectAdapter = dialectAdapter;
}
@UnableCall
public void setColumnMapRowMapper(RowMapper> columnMapRowMapper) {
this.columnMapRowMapper = columnMapRowMapper;
}
@UnableCall
public void setRowMapColumnMapper(Function rowMapColumnMapper) {
this.rowMapColumnMapper = rowMapColumnMapper;
}
private void setDynamicDataSource(MagicDynamicDataSource dynamicDataSource) {
this.dynamicDataSource = dynamicDataSource;
}
@UnableCall
public void setSqlInterceptors(List sqlInterceptors) {
this.sqlInterceptors = sqlInterceptors;
}
private void setDataSourceNode(DataSourceNode dataSourceNode) {
this.dataSourceNode = dataSourceNode;
}
protected String getCacheName() {
return cacheName;
}
private void setCacheName(String cacheName) {
this.cacheName = cacheName;
}
protected long getTtl() {
return ttl;
}
private void setTtl(long ttl) {
this.ttl = ttl;
}
public String getLogicDeleteColumn() {
return logicDeleteColumn;
}
public void setLogicDeleteColumn(String logicDeleteColumn) {
this.logicDeleteColumn = logicDeleteColumn;
}
public String getLogicDeleteValue() {
return logicDeleteValue;
}
public void setLogicDeleteValue(String logicDeleteValue) {
this.logicDeleteValue = logicDeleteValue;
}
protected SqlCache getSqlCache() {
return sqlCache;
}
@UnableCall
public void setSqlCache(SqlCache sqlCache) {
this.sqlCache = sqlCache;
}
@UnableCall
private SQLModule cloneSQLModule() {
SQLModule sqlModule = new SQLModule();
sqlModule.setDynamicDataSource(this.dynamicDataSource);
sqlModule.setDataSourceNode(this.dataSourceNode);
sqlModule.setPageProvider(this.pageProvider);
sqlModule.setColumnMapperProvider(this.columnMapperAdapter);
sqlModule.setColumnMapRowMapper(this.columnMapRowMapper);
sqlModule.setRowMapColumnMapper(this.rowMapColumnMapper);
sqlModule.setSqlCache(this.sqlCache);
sqlModule.setTtl(this.ttl);
sqlModule.setResultProvider(this.resultProvider);
sqlModule.setDialectAdapter(this.dialectAdapter);
sqlModule.setSqlInterceptors(this.sqlInterceptors);
sqlModule.setLogicDeleteValue(this.logicDeleteValue);
sqlModule.setLogicDeleteColumn(this.logicDeleteColumn);
return sqlModule;
}
/**
* 开启事务,在一个回调中进行操作
*
* @param function 回调函数
*/
@Comment("开启事务,并在回调中处理")
public Object transaction(@Comment("回调函数,如:()=>{....}") Function, ?> function) {
Transaction transaction = transaction(); //创建事务
try {
Object val = function.apply(null);
transaction.commit(); //提交事务
return val;
} catch (Throwable throwable) {
transaction.rollback(); //回滚事务
throw throwable;
}
}
/**
* 开启事务,手动提交和回滚
*/
@Comment("开启事务,返回事务对象")
public Transaction transaction() {
return new Transaction(this.dataSourceNode.getDataSourceTransactionManager());
}
/**
* 使用缓存
*
* @param cacheName 缓存名
* @param ttl 过期时间
*/
@Comment("使用缓存")
public SQLModule cache(@Comment("缓存名") String cacheName, @Comment("过期时间") long ttl) {
if (cacheName == null) {
return this;
}
SQLModule sqlModule = cloneSQLModule();
sqlModule.setCacheName(cacheName);
sqlModule.setTtl(ttl);
return sqlModule;
}
/**
* 使用缓存(采用默认缓存时间)
*
* @param cacheName 缓冲名
*/
@Comment("使用缓存,过期时间采用默认配置")
public SQLModule cache(@Comment("缓存名") String cacheName) {
return cache(cacheName, 0);
}
@Comment("采用驼峰列名")
public SQLModule camel() {
return columnCase("camel");
}
@Comment("采用帕斯卡列名")
public SQLModule pascal() {
return columnCase("pascal");
}
@Comment("采用全小写列名")
public SQLModule lower() {
return columnCase("lower");
}
@Comment("采用全大写列名")
public SQLModule upper() {
return columnCase("upper");
}
@Comment("列名保持原样")
public SQLModule normal() {
return columnCase("default");
}
@Comment("指定列名转换")
public SQLModule columnCase(String name) {
SQLModule sqlModule = cloneSQLModule();
sqlModule.setColumnMapRowMapper(this.columnMapperAdapter.getColumnMapRowMapper(name));
sqlModule.setRowMapColumnMapper(this.columnMapperAdapter.getRowMapColumnMapper(name));
return sqlModule;
}
/**
* 数据源切换
*/
@Override
public SQLModule get(Object key) {
SQLModule sqlModule = cloneSQLModule();
if (key == null) {
sqlModule.setDataSourceNode(dynamicDataSource.getDataSource());
} else {
sqlModule.setDataSourceNode(dynamicDataSource.getDataSource(key.toString()));
}
return sqlModule;
}
/**
* 查询List
*/
@Comment("查询SQL,返回List类型结果")
public List> select(@Comment("`SQL`语句") String sql) {
return select(new BoundSql(sql, this));
}
@UnableCall
public List> select(BoundSql boundSql) {
return boundSql.getCacheValue(this.sqlInterceptors, () -> dataSourceNode.getJdbcTemplate().query(boundSql.getSql(), this.columnMapRowMapper, boundSql.getParameters()));
}
/**
* 执行update
*/
@Comment("执行update操作,返回受影响行数")
public int update(@Comment("`SQL`语句") String sql) {
return update(new BoundSql(sql));
}
@UnableCall
public int update(BoundSql boundSql) {
sqlInterceptors.forEach(sqlInterceptor -> sqlInterceptor.preHandle(boundSql, RequestContext.getRequestEntity()));
int value = dataSourceNode.getJdbcTemplate().update(boundSql.getSql(), boundSql.getParameters());
if (this.cacheName != null) {
this.sqlCache.delete(this.cacheName);
}
return value;
}
/**
* 插入并返回主键
*/
@Comment("执行insert操作,返回插入主键")
public long insert(@Comment("`SQL`语句") String sql) {
MagicKeyHolder magicKeyHolder = new MagicKeyHolder();
insert(new BoundSql(sql), magicKeyHolder);
return magicKeyHolder.getLongKey();
}
/**
* 插入并返回主键
*/
@Comment("执行insert操作,返回插入主键")
public Object insert(@Comment("`SQL`语句") String sql, @Comment("主键列") String primary) {
return insert(new BoundSql(sql), primary);
}
void insert(BoundSql boundSql, MagicKeyHolder keyHolder) {
sqlInterceptors.forEach(sqlInterceptor -> sqlInterceptor.preHandle(boundSql, RequestContext.getRequestEntity()));
dataSourceNode.getJdbcTemplate().update(con -> {
PreparedStatement ps = keyHolder.createPrepareStatement(con, boundSql.getSql());
new ArgumentPreparedStatementSetter(boundSql.getParameters()).setValues(ps);
return ps;
}, keyHolder);
if (this.cacheName != null) {
this.sqlCache.delete(this.cacheName);
}
}
/**
* 插入并返回主键
*/
@Comment("批量执行insert操作,返回插入主键数组")
public int[] batchInsert(@Comment("`SQL`语句") String sql, @Comment("参数") List list) {
return dataSourceNode.getJdbcTemplate().batchUpdate(sql, list);
}
/**
* 插入并返回主键
*/
@Comment("批量执行insert操作,返回插入主键数组")
public int[] batchInsert(@Comment("`SQL`语句") String[] sqls) {
return dataSourceNode.getJdbcTemplate().batchUpdate(sqls);
}
@UnableCall
public Object insert(BoundSql boundSql, String primary) {
MagicKeyHolder keyHolder = new MagicKeyHolder(primary);
insert(boundSql, keyHolder);
return keyHolder.getObjectKey();
}
/**
* 分页查询
*/
@Comment("执行分页查询,分页条件自动获取")
public Object page(@Comment("`SQL`语句") String sql) {
return page(new BoundSql(sql, this));
}
/**
* 分页查询(手动传入limit和offset参数)
*/
@Comment("执行分页查询,分页条件手动传入")
public Object page(@Comment("`SQL`语句") String sql, @Comment("限制条数") long limit, @Comment("跳过条数") long offset) {
BoundSql boundSql = new BoundSql(sql, this);
return page(boundSql, new Page(limit, offset));
}
@UnableCall
public Object page(BoundSql boundSql) {
Page page = pageProvider.getPage(MagicScriptContext.get());
return page(boundSql, page);
}
private Object page(BoundSql boundSql, Page page) {
Dialect dialect = dataSourceNode.getDialect(dialectAdapter);
BoundSql countBoundSql = boundSql.copy(dialect.getCountSql(boundSql.getSql()));
int count = countBoundSql.getCacheValue(this.sqlInterceptors, () -> dataSourceNode.getJdbcTemplate().query(countBoundSql.getSql(), new SingleRowResultSetExtractor<>(Integer.class), countBoundSql.getParameters()));
List> list = null;
if (count > 0) {
BoundSql pageBoundSql = buildPageBoundSql(dialect, boundSql, page.getOffset(), page.getLimit());
list = pageBoundSql.getCacheValue(this.sqlInterceptors, () -> dataSourceNode.getJdbcTemplate().query(pageBoundSql.getSql(), this.columnMapRowMapper, pageBoundSql.getParameters()));
}
RequestEntity requestEntity = RequestContext.getRequestEntity();
return resultProvider.buildPageResult(requestEntity, page, count, list);
}
/**
* 查询int值
*/
@Comment("查询int值,适合单行单列int的结果")
public Integer selectInt(@Comment("`SQL`语句") String sql) {
return selectInt(new BoundSql(sql, this));
}
@UnableCall
public Integer selectInt(BoundSql boundSql) {
return boundSql.getCacheValue(this.sqlInterceptors, () -> dataSourceNode.getJdbcTemplate().query(boundSql.getSql(), new SingleRowResultSetExtractor<>(Integer.class), boundSql.getParameters()));
}
/**
* 查询Map
*/
@Comment("查询单条结果,查不到返回null")
public Map selectOne(@Comment("`SQL`语句") String sql) {
return selectOne(new BoundSql(sql, this));
}
@UnableCall
public Map selectOne(BoundSql boundSql) {
return boundSql.getCacheValue(this.sqlInterceptors, () -> {
Dialect dialect = dataSourceNode.getDialect(dialectAdapter);
BoundSql pageBoundSql = buildPageBoundSql(dialect, boundSql, 0, 1);
return dataSourceNode.getJdbcTemplate().query(pageBoundSql.getSql(), new SingleRowResultSetExtractor<>(this.columnMapRowMapper), pageBoundSql.getParameters());
});
}
/**
* 查询单行单列的值
*/
@Comment("查询单行单列的值")
public Object selectValue(@Comment("`SQL`语句") String sql) {
BoundSql boundSql = new BoundSql(sql, this);
return boundSql.getCacheValue(this.sqlInterceptors, () -> {
Dialect dialect = dataSourceNode.getDialect(dialectAdapter);
BoundSql pageBoundSql = buildPageBoundSql(dialect, boundSql, 0, 1);
return dataSourceNode.getJdbcTemplate().query(pageBoundSql.getSql(), new SingleRowResultSetExtractor<>(Object.class), pageBoundSql.getParameters());
});
}
@Comment("指定table,进行单表操作")
public NamedTable table(String tableName) {
return new NamedTable(tableName, this, rowMapColumnMapper);
}
private BoundSql buildPageBoundSql(Dialect dialect, BoundSql boundSql, long offset, long limit) {
String pageSql = dialect.getPageSql(boundSql.getSql(), boundSql, offset, limit);
return boundSql.copy(pageSql);
}
@UnableCall
@Override
public String getModuleName() {
return "db";
}
static class MagicKeyHolder extends GeneratedKeyHolder {
private final boolean useGeneratedKeys;
private final String primary;
public MagicKeyHolder() {
this(null);
}
public MagicKeyHolder(String primary) {
this.primary = primary;
this.useGeneratedKeys = StringUtils.isBlank(primary);
}
PreparedStatement createPrepareStatement(Connection connection, String sql) throws SQLException {
if (useGeneratedKeys) {
return connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
}
return connection.prepareStatement(sql, new String[]{primary});
}
public long getLongKey() throws InvalidDataAccessApiUsageException, DataRetrievalFailureException {
Number key = super.getKey();
if (key == null) {
return -1;
}
return key.longValue();
}
public Object getObjectKey() {
if (useGeneratedKeys) {
return getLongKey();
}
List> keyList = getKeyList();
if (keyList.isEmpty()) {
return null;
}
Iterator keyIterator = keyList.get(0).values().iterator();
return keyIterator.hasNext() ? keyIterator.next() : null;
}
}
}