diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 02ed8d60f..89122fb90 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -39,6 +39,7 @@ module org.redkale { uses org.redkale.mq.MessageAgentProvider; uses org.redkale.source.CacheSourceProvider; uses org.redkale.source.DataSourceProvider; + uses org.redkale.source.DataNativeSqlParserProvider; uses org.redkale.util.ResourceAnnotationProvider; } diff --git a/src/main/java/org/redkale/boot/Application.java b/src/main/java/org/redkale/boot/Application.java index 3c8150761..e09511473 100644 --- a/src/main/java/org/redkale/boot/Application.java +++ b/src/main/java/org/redkale/boot/Application.java @@ -157,6 +157,9 @@ public final class Application { private final ReentrantLock dataSourceLock = new ReentrantLock(); + //原生sql解析器 + private DataNativeSqlParser nativeSqlParser; + //NodeServer 资源, 顺序必须是sncps, others, watchs final List servers = new CopyOnWriteArrayList<>(); @@ -580,6 +583,23 @@ public final class Application { this.excludelibs = excludelib0; this.clusterAgent = cluster; this.messageAgents = mqs; + { //加载原生sql解析器 + Iterator it = ServiceLoader.load(DataNativeSqlParserProvider.class, classLoader).iterator(); + RedkaleClassLoader.putServiceLoader(DataNativeSqlParserProvider.class); + List providers = new ArrayList<>(); + while (it.hasNext()) { + DataNativeSqlParserProvider provider = it.next(); + if (provider != null && provider.acceptsConf(null)) { + RedkaleClassLoader.putReflectionPublicConstructors(provider.getClass(), provider.getClass().getName()); + providers.add(provider); + } + } + for (DataNativeSqlParserProvider provider : InstanceProvider.sort(providers)) { + this.nativeSqlParser = provider.createInstance(); + this.resourceFactory.register(DataNativeSqlParser.class, this.nativeSqlParser); + break; + } + } if (compileMode || this.classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader) { this.serverClassLoader = this.classLoader; } else { diff --git a/src/main/java/org/redkale/source/AbstractDataSqlSource.java b/src/main/java/org/redkale/source/AbstractDataSqlSource.java index 820c612fc..c27964cdc 100644 --- a/src/main/java/org/redkale/source/AbstractDataSqlSource.java +++ b/src/main/java/org/redkale/source/AbstractDataSqlSource.java @@ -65,6 +65,9 @@ public abstract class AbstractDataSqlSource extends AbstractDataSource implement @Resource(name = RESNAME_APP_EXECUTOR, required = false) protected ExecutorService workExecutor; + @Resource(required = false) + protected DataNativeSqlParser nativeSqlParser; + protected BiFunction sqlFormatter; protected BiConsumer errorCompleteConsumer = (r, t) -> { @@ -639,6 +642,13 @@ public abstract class AbstractDataSqlSource extends AbstractDataSource implement return getSQLAttrValue(info, attr, val); } + protected DataNativeSqlParser.NativeSqlInfo nativeParse(String nativeSql, Map params) { + if (nativeSqlParser == null) { + throw new SourceException("not found DataNativeSqlParser instance"); + } + return nativeSqlParser.parse(nativeSql, params == null ? Collections.emptyMap() : params); + } + @Override public void destroy(AnyValue config) { super.destroy(config); @@ -3276,4 +3286,5 @@ public abstract class AbstractDataSqlSource extends AbstractDataSource implement entitys.add(entity); } } + } diff --git a/src/main/java/org/redkale/source/DataJdbcSource.java b/src/main/java/org/redkale/source/DataJdbcSource.java index 39921ae82..ba10cdad1 100644 --- a/src/main/java/org/redkale/source/DataJdbcSource.java +++ b/src/main/java/org/redkale/source/DataJdbcSource.java @@ -18,6 +18,7 @@ import org.redkale.annotation.*; import org.redkale.annotation.ResourceListener; import org.redkale.annotation.ResourceType; import org.redkale.service.Local; +import org.redkale.source.DataNativeSqlParser.NativeSqlInfo; import org.redkale.util.*; /** @@ -2481,19 +2482,6 @@ public class DataJdbcSource extends AbstractDataSqlSource { return rs; } - /** - * 直接本地执行SQL语句进行增删改操作,远程模式不可用
- * 通常用于复杂的更新操作
- * - * @param sql SQL语句 - * - * @return 结果数组 - */ - @Override - public int nativeUpdate(String sql) { - return nativeUpdates(new String[]{sql})[0]; - } - /** * 直接本地执行SQL语句进行增删改操作,远程模式不可用
* 通常用于复杂的更新操作
@@ -2515,7 +2503,7 @@ public class DataJdbcSource extends AbstractDataSqlSource { final int[] rs = new int[sqls.length]; int i = -1; for (String sql : sqls) { - rs[++i] = stmt.execute(sql) ? 1 : 0; + rs[++i] = stmt.executeUpdate(sql); } conn.offerUpdateStatement(stmt); conn.commit(); @@ -2534,6 +2522,57 @@ public class DataJdbcSource extends AbstractDataSqlSource { } } + /** + * 直接本地执行SQL语句进行增删改操作,远程模式不可用
+ * 通常用于复杂的更新操作
+ * + * @param sql SQL语句 + * + * @return 结果数组 + */ + @Override + public int nativeUpdate(String sql) { + return nativeUpdates(new String[]{sql})[0]; + } + + @Override + public int nativeUpdate(String sql, Map params) { + NativeSqlInfo sinfo = super.nativeParse(sql, params); + final long s = System.currentTimeMillis(); + SourceConnection conn = writePool.pollConnection(); + try { + conn.setAutoCommit(false); + int rs; + if (sinfo.isEmptyNamed()) { + final Statement stmt = conn.createUpdateStatement(); + rs = stmt.executeUpdate(sinfo.nativeSql); + conn.offerUpdateStatement(stmt); + } else { + final PreparedStatement prestmt = conn.prepareQueryStatement(sinfo.nativeSql); + Map paramValues = sinfo.getParamValues(); + int index = 0; + for (String n : sinfo.getParamNames()) { + prestmt.setObject(++index, paramValues.get(n)); + } + rs = prestmt.executeUpdate(); + conn.offerUpdateStatement(prestmt); + } + conn.commit(); + slowLog(s, sinfo.nativeSql); + return rs; + } catch (SQLException e) { + try { + conn.rollback(); + } catch (SQLException se) { + } + throw new SourceException(e); + } finally { + if (conn != null) { + writePool.offerConnection(conn); + } + } + } + /** * 直接本地执行SQL语句进行查询,远程模式不可用
* 通常用于复杂的关联查询
@@ -2571,14 +2610,49 @@ public class DataJdbcSource extends AbstractDataSqlSource { } } - @Override - public int nativeUpdate(String sql, Map params) { - throw new UnsupportedOperationException("Not supported yet."); - } - @Override public V nativeQuery(String sql, BiConsumer consumer, Function handler, Map params) { - throw new UnsupportedOperationException("Not supported yet."); + NativeSqlInfo sinfo = super.nativeParse(sql, params); + final long s = System.currentTimeMillis(); + final SourceConnection conn = readPool.pollConnection(); + try { + if (logger.isLoggable(Level.FINEST)) { + logger.finest("executeQuery sql=" + sinfo.nativeSql); + } + V rs; + if (sinfo.isEmptyNamed()) { + final Statement stmt = conn.createQueryStatement(); + if (consumer != null) { + consumer.accept(conn, stmt); + } + ResultSet set = stmt.executeQuery(sql); + rs = handler.apply(createDataResultSet(null, set)); + set.close(); + conn.offerQueryStatement(stmt); + } else { + final PreparedStatement prestmt = conn.prepareQueryStatement(sinfo.nativeSql); + Map paramValues = sinfo.getParamValues(); + int index = 0; + for (String n : sinfo.getParamNames()) { + prestmt.setObject(++index, paramValues.get(n)); + } + if (consumer != null) { + consumer.accept(conn, prestmt); + } + ResultSet set = prestmt.executeQuery(sql); + rs = handler.apply(createDataResultSet(null, set)); + set.close(); + conn.offerQueryStatement(prestmt); + } + slowLog(s, sql); + return rs; + } catch (Exception ex) { + throw new SourceException(ex); + } finally { + if (conn != null) { + readPool.offerConnection(conn); + } + } } @Deprecated diff --git a/src/main/java/org/redkale/source/DataNativeSqlParser.java b/src/main/java/org/redkale/source/DataNativeSqlParser.java new file mode 100644 index 000000000..80e6212c8 --- /dev/null +++ b/src/main/java/org/redkale/source/DataNativeSqlParser.java @@ -0,0 +1,74 @@ +/* + * + */ +package org.redkale.source; + +import java.util.*; +import org.redkale.convert.ConvertDisabled; +import org.redkale.convert.json.JsonConvert; + +/** + * + * 原生的sql解析器 + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface DataNativeSqlParser { + + NativeSqlInfo parse(String nativeSql, Map params); + + public static class NativeSqlInfo { + + //根据参数值集合重新生成的可执行的sql + protected String nativeSql; + + //需要预编译的参数名 + protected List paramNames; + + //参数值集合 + protected Map paramValues; + + /** + * 是否带有参数 + * + * @return 是否带有参数 + */ + @ConvertDisabled + public boolean isEmptyNamed() { + return paramNames == null || paramNames.isEmpty(); + } + + public String getNativeSql() { + return nativeSql; + } + + public void setNativeSql(String nativeSql) { + this.nativeSql = nativeSql; + } + + public List getParamNames() { + return paramNames; + } + + public void setParamNames(List paramNames) { + this.paramNames = paramNames; + } + + public Map getParamValues() { + return paramValues; + } + + public void setParamValues(Map paramValues) { + this.paramValues = paramValues; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/main/java/org/redkale/source/DataNativeSqlParserProvider.java b/src/main/java/org/redkale/source/DataNativeSqlParserProvider.java new file mode 100644 index 000000000..4a48a702d --- /dev/null +++ b/src/main/java/org/redkale/source/DataNativeSqlParserProvider.java @@ -0,0 +1,20 @@ +/* + * + */ +package org.redkale.source; + +import org.redkale.util.InstanceProvider; + +/** + * + * 自定义的DataNativeSqlParser加载器, 如果标记@Priority加载器的优先级需要大于1000, 1000以下预留给官方加载器 + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + * @since 2.8.0 + */ +public interface DataNativeSqlParserProvider extends InstanceProvider { + +} diff --git a/src/main/java/org/redkale/source/DataSqlSource.java b/src/main/java/org/redkale/source/DataSqlSource.java index c0a666e6a..0fef1b55f 100644 --- a/src/main/java/org/redkale/source/DataSqlSource.java +++ b/src/main/java/org/redkale/source/DataSqlSource.java @@ -21,16 +21,57 @@ import org.redkale.util.Copier; */ public interface DataSqlSource extends DataSource { + /** + * 执行多条原生无参数的sql + * + * @param sql 无参数的sql语句 + * + * @return 执行条数 + */ public int[] nativeUpdates(String... sqls); + /** + * 执行原生无参数的sql + * + * @param sql 无参数的sql语句 + * + * @return 执行条数 + */ public int nativeUpdate(String sql); + /** + * 执行原生带参数的sql + * + * @param sql 带参数的sql语句 + * @param params 参数值集合 + * + * @return 执行条数 + */ public int nativeUpdate(String sql, Map params); - //BiConsumer 参数1: connection, 参数2: statement + /** + * 通过原生的sql查询结果 + * + * @param 泛型 + * @param sql 无参数的sql语句 + * @param consumer BiConsumer 参数1: connection, 参数2: statement + * @param handler DataResultSet的回调函数 + * + * @return 结果对象 + */ public V nativeQuery(String sql, BiConsumer consumer, Function handler); - //BiConsumer 参数1: connection, 参数2: statement + /** + * 通过原生带参数的sql查询结果 + * + * @param 泛型 + * @param sql 带参数的sql语句 + * @param consumer BiConsumer 参数1: connection, 参数2: statement + * @param handler DataResultSet的回调函数 + * @param params 参数值集合 + * + * @return 结果对象 + */ public V nativeQuery(String sql, BiConsumer consumer, Function handler, Map params); //----------------------------- 无参数 -----------------------------