From 66238af2869febc598e92a4bb59e32a2656b026e Mon Sep 17 00:00:00 2001 From: cloudAndMonkey Date: Fri, 17 Feb 2023 17:33:37 +0800 Subject: [PATCH 1/3] apijson rediSQL demo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit APIJSON 增删改查 支持 rediSQL --- .../README.md | 48 + .../pom.xml | 196 +++ .../java/apijson/demo/DataBaseConfig.java | 22 + .../main/java/apijson/demo/DataBaseUtil.java | 54 + .../java/apijson/demo/DemoApplication.java | 103 ++ .../java/apijson/demo/DemoController.java | 99 ++ .../java/apijson/demo/DemoFunctionParser.java | 93 ++ .../java/apijson/demo/DemoObjectParser.java | 26 + .../main/java/apijson/demo/DemoParser.java | 35 + .../main/java/apijson/demo/DemoSQLConfig.java | 133 ++ .../java/apijson/demo/DemoSQLExecutor.java | 206 +++ .../java/apijson/demo/DynamicDataSource.java | 157 +++ .../java/apijson/demo/JedisBuildData.java | 193 +++ .../java/apijson/demo/JedisClusterUtil.java | 1010 +++++++++++++++ .../java/apijson/demo/SpringContextUtils.java | 60 + .../demo/resultSet/DataBuildResultSet.java | 1111 +++++++++++++++++ .../DataBuildResultSetMetaDataBase.java | 19 + .../redisql/client/NoDoneReply.java | 4 + .../redisql/client/ParseRediSQLReply.java | 42 + .../redisql/client/RediSQLClient.java | 196 +++ .../redisql/client/RediSQLCommand.java | 42 + .../src/main/resources/application.yml | 35 + 22 files changed, 3884 insertions(+) create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/pom.xml create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DataBaseConfig.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DataBaseUtil.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoApplication.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoController.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoFunctionParser.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoObjectParser.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoParser.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoSQLConfig.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoSQLExecutor.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DynamicDataSource.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/JedisBuildData.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/JedisClusterUtil.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/SpringContextUtils.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/resultSet/DataBuildResultSet.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/resultSet/DataBuildResultSetMetaDataBase.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/NoDoneReply.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/ParseRediSQLReply.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/RediSQLClient.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/RediSQLCommand.java create mode 100644 APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/resources/application.yml diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md new file mode 100644 index 00000000..82218340 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md @@ -0,0 +1,48 @@ +# APIJSONDemo + +## 支持多数据源-消息队列 + +示例:kafka + +原理说明: + +Access表名 = 消息队列 topic + +Access表配置说明: +![image](https://user-images.githubusercontent.com/12228225/210956299-204115a7-433c-4f18-af27-5120068dab2e.png) +Request表配置post权限 +![image](https://user-images.githubusercontent.com/12228225/210956378-be095589-0ced-4317-bb46-6b296538f26e.png) + +apijson发送mq消息: +单条
+{ + "@datasource": "kafka", + "Topic_User":{ + "message":"test-101" + }, + "tag": "Topic_User", + "@explain": false +}
+多条
+{ + "Topic_User[]": [ + { + "message":"test-100" + }, + { + "message":"test-101" + } + ], + "tag": "Topic_User[]", + "@datasource": "kafka", + "@explain": true +} + +客户端接收消息: + +offset = 47, key = null, value = test-101
+offset = 48, key = null, value = test-100
+offset = 49, key = null, value = test-101
+ + +用java代码方式,获取具体数据源,调用即可 diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/pom.xml b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/pom.xml new file mode 100644 index 00000000..06af836d --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/pom.xml @@ -0,0 +1,196 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.13 + + + apijson.demo + apijsondemo-multidatasource-rediSQL + 6.0.0 + + apijsondemo-multidatasource-rediSQL + Demo project for testing APIJSON server based on SpringBoot + + + UTF-8 + UTF-8 + 3.12.0 + 1.1.16 + 3.5.1 + 2.3.3 + 4.4 + 1.10 + 30.1.1-jre + 1.2.72 + 4.1.1 + 1.18.4 + 3.12.0 + 2.5 + 1.10 + 4.4 + 1.10 + 6.0.0 + 8.0.31 + 5.3.18 + 2.6.6 + 3.5.2 + 3.7.1 + 1.8 + + + + + + com.github.Tencent + APIJSON + ${apijson.version} + + + com.github.APIJSON + apijson-framework + ${apijson.version} + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework + spring-context-support + ${spring-context-support.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot-configuration-processor.version} + true + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + com.baomidou + dynamic-datasource-spring-boot-starter + ${dynamic-datasource-spring-boot-starter.version} + + + com.baomidou + mybatis-plus-boot-starter + ${mybatisplus.version} + + + com.baomidou + mybatis-plus-generator + + + + + com.baomidou + mybatis-plus-support + ${mybatis-plus-support.version} + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + mysql + mysql-connector-java + ${mysql.version} + + + com.google.guava + guava + ${guava.version} + + + org.projectlombok + lombok + ${lombok.version} + + + commons-io + commons-io + ${commons.io.version} + + + commons-codec + commons-codec + ${commons.codec.version} + + + commons-configuration + commons-configuration + ${commons.configuration.version} + + + redis.clients + jedis + ${jedis.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + apijson.demo.DemoApplication + + + + + repackage + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + + + + jitpack.io + https://jitpack.io + + true + + + + + spring-snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + https://repo.spring.io/milestone + + + + \ No newline at end of file diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DataBaseConfig.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DataBaseConfig.java new file mode 100644 index 00000000..6e261537 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DataBaseConfig.java @@ -0,0 +1,22 @@ +package apijson.demo; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class DataBaseConfig { + private String primary; + + @Value("${spring.datasource.dynamic.primary}") + public void setPrimary(String primary) { + this.primary = primary; + } + + public String getPrimary() { + return primary; + } + + public static DataBaseConfig getInstence() { + return SpringContextUtils.getBean(DataBaseConfig.class); + } +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DataBaseUtil.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DataBaseUtil.java new file mode 100644 index 00000000..a4c6bbf3 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DataBaseUtil.java @@ -0,0 +1,54 @@ +package apijson.demo; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public class DataBaseUtil { + + /** + * 根据url获取库名 + * @param url + * @return + */ + public static String getLibname(String url) { + Pattern p = Pattern.compile("jdbc:(?\\w+):.*((//)|@)(?.+):(?\\d+)(/|(;DatabaseName=)|:)(?\\w+)\\??.*"); + Matcher m = p.matcher(url); + if(m.find()) { + return m.group("dbName"); + } + return null; + } + + /*** + * primary: master + * strict: false + * @param datasource: 匹配不成功, 自动匹配默认数据库 + * @return + */ + public static javax.sql.DataSource getDataSource(String datasource) { + try { + return DynamicDataSource.getDetail(datasource).getDataSource(); // 数据源 + } catch (Exception e) { + throw new IllegalArgumentException("动态数据源配置错误 " + datasource); + } + } + + public static String getDruidUrl(String datasource) { + return DynamicDataSource.getDetail(datasource).getUrl(); // 数据库连接url + } + + public static String getDruidSchema(String datasource) { + return getLibname(DynamicDataSource.getDetail(datasource).getUrl()); // 数据库名; + } + + public static String getDruidDBAccount(String datasource) { + return DynamicDataSource.getDetail(datasource).getDbAccount(); // 数据库用户名 + } + + public static String getDruidDBPassword(String datasource) { + return DynamicDataSource.getDetail(datasource).getDbPassword(); // 数据库密码 + } +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoApplication.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoApplication.java new file mode 100644 index 00000000..ef58ecff --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoApplication.java @@ -0,0 +1,103 @@ +/*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.*/ + +package apijson.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import apijson.Log; +import apijson.framework.APIJSONApplication; +import apijson.framework.APIJSONCreator; +import apijson.framework.APIJSONParser; +import apijson.orm.AbstractFunctionParser; +import apijson.orm.AbstractVerifier; +import apijson.orm.FunctionParser; +import apijson.orm.Parser; +import apijson.orm.SQLConfig; +import apijson.orm.SQLExecutor; + +/** + * Demo SpringBoot Application 主应用程序启动类 右键这个类 > Run As > Java Application 具体见 + * SpringBoot 文档 + * https://www.springcloud.cc/spring-boot.html#using-boot-locating-the-main-class + * + * @author Lemon + */ +@Configuration +@SpringBootApplication +@EnableConfigurationProperties +public class DemoApplication implements WebServerFactoryCustomizer { + public static final String TAG = "DemoApplication"; + + public static void main(String[] args) throws Exception { + SpringApplication.run(DemoApplication.class, args); + Log.DEBUG = true; + APIJSONParser.IS_PRINT_BIG_LOG = false; + AbstractFunctionParser.ENABLE_SCRIPT_FUNCTION = true; + AbstractVerifier.IS_UPDATE_MUST_HAVE_ID_CONDITION = false; + APIJSONApplication.init(false); // 4.4.0 以上需要这句来保证以上 static 代码块中给 DEFAULT_APIJSON_CREATOR 赋值会生效 + } + + // SpringBoot 2.x 自定义端口方式 + @Override + public void customize(ConfigurableServletWebServerFactory server) { + server.setPort(8080); + } + + // 支持 APIAuto 中 JavaScript 代码跨域请求 + @Bean + public WebMvcConfigurer corsConfigurer() { + return new WebMvcConfigurer() { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**").allowedOriginPatterns("*").allowedMethods("*").allowCredentials(true) + .maxAge(3600); + } + }; + } + + static { + // 使用本项目的自定义处理类 + APIJSONApplication.DEFAULT_APIJSON_CREATOR = new APIJSONCreator() { + @Override + public Parser createParser() { + return new DemoParser(); + } + + @Override + public SQLConfig createSQLConfig() { + return new DemoSQLConfig(); + } + + @Override + public FunctionParser createFunctionParser() { + return new DemoFunctionParser(); + } + + @Override + public SQLExecutor createSQLExecutor() { + return new DemoSQLExecutor(); + } + }; + } + +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoController.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoController.java new file mode 100644 index 00000000..c91c58f3 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoController.java @@ -0,0 +1,99 @@ +/*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.*/ + +package apijson.demo; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.net.URLDecoder; +import java.util.Map; + +import javax.servlet.http.HttpSession; + +import apijson.RequestMethod; +import apijson.StringUtil; +import apijson.framework.APIJSONController; +import apijson.orm.Parser; + + +/**请求路由入口控制器,包括通用增删改查接口等,转交给 APIJSON 的 Parser 来处理 + * 具体见 SpringBoot 文档 + * https://www.springcloud.cc/spring-boot.html#boot-features-spring-mvc + * 以及 APIJSON 通用文档 3.设计规范 3.1 操作方法 + * https://github.com/Tencent/APIJSON/blob/master/Document.md#3.1 + *
建议全通过HTTP POST来请求: + *
1.减少代码 - 客户端无需写HTTP GET,PUT等各种方式的请求代码 + *
2.提高性能 - 无需URL encode和decode + *
3.调试方便 - 建议使用 APIAuto(http://apijson.cn/api) 或 Postman + * @author Lemon + */ +@RestController +@RequestMapping("") +public class DemoController extends APIJSONController { + + @Override + public Parser newParser(HttpSession session, RequestMethod method) { + return super.newParser(session, method).setNeedVerify(false); // TODO 这里关闭校验,方便新手快速测试,实际线上项目建议开启 + } + + /**增删改查统一接口,这个一个接口可替代 7 个万能通用接口,牺牲一些路由解析性能来提升一点开发效率 + * @param method + * @param request + * @param session + * @return + */ + @PostMapping(value = "{method}") // 如果和其它的接口 URL 冲突,可以加前缀,例如改为 crud/{method} 或 Controller 注解 @RequestMapping("crud") + @Override + public String crud(@PathVariable String method, @RequestBody String request, HttpSession session) { + return super.crud(method, request, session); + } + + /**增删改查统一接口,这个一个接口可替代 7 个万能通用接口,牺牲一些路由解析性能来提升一点开发效率 + * @param method + * @param tag + * @param params + * @param request + * @param session + * @return + */ + @PostMapping("{method}/{tag}") // 如果和其它的接口 URL 冲突,可以加前缀,例如改为 crud/{method}/{tag} 或 Controller 注解 @RequestMapping("crud") + @Override + public String crudByTag(@PathVariable String method, @PathVariable String tag, @RequestParam Map params, @RequestBody String request, HttpSession session) { + return super.crudByTag(method, tag, params, request, session); + } + + /**获取 + * 只为兼容HTTP GET请求,推荐用HTTP POST,可删除 + * @param request 只用String,避免encode后未decode + * @param session + * @return + * @see {@link RequestMethod#GET} + */ + @GetMapping("get/{request}") + public String openGet(@PathVariable String request, HttpSession session) { + try { + request = URLDecoder.decode(request, StringUtil.UTF_8); + } catch (Exception e) { + // Parser 会报错 + } + return get(request, session); + } + +} \ No newline at end of file diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoFunctionParser.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoFunctionParser.java new file mode 100644 index 00000000..92e729c7 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoFunctionParser.java @@ -0,0 +1,93 @@ +package apijson.demo; + +import javax.servlet.http.HttpSession; + +import com.alibaba.fastjson.JSONObject; + +import apijson.NotNull; +import apijson.RequestMethod; +import apijson.StringUtil; +import apijson.framework.APIJSONFunctionParser; +import apijson.framework.APIJSONVerifier; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class DemoFunctionParser extends APIJSONFunctionParser { + public DemoFunctionParser() { + this(null, null, 0, null, null); + } + + // 展示在远程函数内部可以用 this 拿到的东西 + public DemoFunctionParser(RequestMethod method, String tag, int version, JSONObject request, HttpSession session) { + super(method, tag, version, request, session); + } + + /*** + * 获取当前用户id + * + * @param current + * @return + */ + public String getCurrentUserId(@NotNull JSONObject current) { + if (this.getSession() == null) { + return "test"; // 启动时的自动测试 + } + return APIJSONVerifier.getVisitorId(getSession()); + } + + /** + * 一个最简单的远程函数示例,返回一个前面拼接了 Hello 的字符串 + * + * @param current + * @param name + * @return + * @throws Exception + */ + public String sayHello(@NotNull JSONObject current, @NotNull String name) throws Exception { + // 注意这里参数 name 是 key,不是 value + Object obj = current.get(name); + + if (this.getSession() == null) { + return "test"; // 启动时的自动测试 + } + + if (obj == null) { + throw new IllegalArgumentException(); + } + if (!(obj instanceof String)) { + throw new IllegalArgumentException(); + } + + // 之后可以用 this.getSession 拿到当前的 HttpSession + return "Hello, " + obj.toString(); + } + + /*** + * 密码加密 + * + * @param current + * @param id 添加id生成 + * @param password 密码字段名 + * @return + * @throws Exception + */ + public void pwdEncrypt(@NotNull JSONObject current, @NotNull String id, @NotNull String password) + throws Exception { + String c_password = current.getString(password); + current.put(password, c_password + "_" + System.currentTimeMillis()); + } + + public void childFunTest(@NotNull JSONObject current, @NotNull String addr) throws Exception { + String c_addr = current.getString(addr); + current.put(addr, c_addr + "_" + System.currentTimeMillis()); + } + + + public void removeKeys(@NotNull JSONObject current, String keys) { + String[] ks = StringUtil.split(keys, ";"); // 用分号 ; 分割 + // 根据 ks remove 掉 current 里的字段 + for (int i = 0; i < ks.length; i++) { + current.remove(ks[i]); + } + } +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoObjectParser.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoObjectParser.java new file mode 100644 index 00000000..627de64c --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoObjectParser.java @@ -0,0 +1,26 @@ +package apijson.demo; + +import java.util.List; + +import javax.servlet.http.HttpSession; + +import com.alibaba.fastjson.JSONObject; + +import apijson.NotNull; +import apijson.RequestMethod; +import apijson.framework.APIJSONObjectParser; +import apijson.orm.Join; +import apijson.orm.SQLConfig; + +public class DemoObjectParser extends APIJSONObjectParser { + + public DemoObjectParser(HttpSession session, @NotNull JSONObject request, String parentPath, SQLConfig arrayConfig + , boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception { + super(session, request, parentPath, arrayConfig, isSubquery, isTable, isArrayMainTable); + } + + @Override + public SQLConfig newSQLConfig(RequestMethod method, String table, String alias, JSONObject request, List joinList, boolean isProcedure) throws Exception { + return DemoSQLConfig.newSQLConfig(method, table, alias, request, joinList, isProcedure); + } +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoParser.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoParser.java new file mode 100644 index 00000000..e12333e6 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoParser.java @@ -0,0 +1,35 @@ +package apijson.demo; + +import com.alibaba.fastjson.JSONObject; + +import apijson.RequestMethod; +import apijson.framework.APIJSONObjectParser; +import apijson.framework.APIJSONParser; +import apijson.orm.SQLConfig; + +public class DemoParser extends APIJSONParser { + public DemoParser() { + super(); + } + + public DemoParser(RequestMethod method) { + super(method); + } + + public DemoParser(RequestMethod method, boolean needVerify) { + super(method, needVerify); + } + + // 可重写来设置最大查询数量 + // @Override + // public int getMaxQueryCount() { + // return 50; + // } + + @Override + public APIJSONObjectParser createObjectParser(JSONObject request, String parentPath, SQLConfig arrayConfig, boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception { + return new DemoObjectParser(getSession(), request, parentPath, arrayConfig, isSubquery, isTable, isArrayMainTable).setMethod(getMethod()).setParser(this); + } + + +} \ No newline at end of file diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoSQLConfig.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoSQLConfig.java new file mode 100644 index 00000000..6337d426 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoSQLConfig.java @@ -0,0 +1,133 @@ +/*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.*/ + +package apijson.demo; + +import java.util.UUID; + +import com.alibaba.fastjson.annotation.JSONField; + +import apijson.RequestMethod; +import apijson.framework.APIJSONSQLConfig; +import apijson.orm.AbstractSQLConfig; + + +/**SQL 配置 + * TiDB 用法和 MySQL 一致 + * 具体见详细的说明文档 C.开发说明 C-1-1.修改数据库链接 + * https://github.com/Tencent/APIJSON/blob/master/%E8%AF%A6%E7%BB%86%E7%9A%84%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3.md#c-1-1%E4%BF%AE%E6%94%B9%E6%95%B0%E6%8D%AE%E5%BA%93%E9%93%BE%E6%8E%A5 + * @author Lemon + */ +public class DemoSQLConfig extends APIJSONSQLConfig { + + public DemoSQLConfig() { + super(); + } + + public DemoSQLConfig(RequestMethod method, String table) { + super(method, table); + } + + static { +// DEFAULT_DATABASE = DATABASE_ELASTICSEARCH; // TODO 默认数据库类型,改成你自己的 +// DEFAULT_SCHEMA = "sys"; // TODO 默认数据库名/模式,改成你自己的,默认情况是 MySQL: sys, PostgreSQL: public, SQL Server: dbo, Oracle: + + // 表名和数据库不一致的,需要配置映射关系。只使用 APIJSONORM 时才需要; + // 如果用了 apijson-framework 且调用了 APIJSONApplication.init 则不需要 + // (间接调用 DemoVerifier.init 方法读取数据库 Access 表来替代手动输入配置)。 + // 但如果 Access 这张表的对外表名与数据库实际表名不一致,仍然需要这里注册。例如 + // TABLE_KEY_MAP.put(Access.class.getSimpleName(), "access"); + + SIMPLE_CALLBACK = new SimpleCallback() { + + @Override + public AbstractSQLConfig getSQLConfig(RequestMethod method, String database, String schema, + String datasource, String table) { + return new DemoSQLConfig(method, table); + } + + // 取消注释来实现数据库自增 id + @Override + public String newId(RequestMethod method, String database, String schema, String datasource, String table) { + if(table.equals("Access") || table.equals("Request") || table.equals("Function")){ + return null; + } + return UUID.randomUUID().toString(); // return null 则不生成 id,一般用于数据库自增 id + } + }; + } + + @JSONField(serialize = false) // 不在日志打印 账号/密码 等敏感信息,用了 UnitAuto 则一定要加 + @Override + public String getDBVersion() { + return DynamicDataSource.getDetail(this.getDatasource()).getDbVersion(); + } + + @JSONField(serialize = false) // 不在日志打印 账号/密码 等敏感信息,用了 UnitAuto 则一定要加 + @Override + public String getDatabase() { + if (super.getDatabase() != null) { + return super.getDatabase(); + } + try { + return DynamicDataSource.getDetail(this.getDatasource()).getDatabase(); + } catch (Exception e) { + throw new IllegalArgumentException("动态数据源配置错误 " + this.getDatasource()); + } + } + + @JSONField(serialize = false) // 不在日志打印 账号/密码 等敏感信息,用了 UnitAuto 则一定要加 + @Override + public String getSchema() { + if (super.getSchema() != null) { + return super.getSchema(); + } + try { + return DynamicDataSource.getDetail(this.getDatasource()).getSchema(); + } catch (Exception e) { + throw new IllegalArgumentException("动态数据源配置错误 " + this.getDatasource()); + } + } + + @JSONField(serialize = false) // 不在日志打印 账号/密码 等敏感信息,用了 UnitAuto 则一定要加 + @Override + public String getDBUri() { + try { + return DynamicDataSource.getDetail(this.getDatasource()).getUrl(); // 数据库连接url + } catch (Exception e) { + throw new IllegalArgumentException("动态数据源配置错误 " + this.getDatasource()); + } + } + + @JSONField(serialize = false) // 不在日志打印 账号/密码 等敏感信息,用了 UnitAuto 则一定要加 + @Override + public String getDBAccount() { + try { + return DynamicDataSource.getDetail(this.getDatasource()).getDbAccount(); + } catch (Exception e) { + throw new IllegalArgumentException("动态数据源配置错误 " + this.getDatasource()); + } + } + + @JSONField(serialize = false) // 不在日志打印 账号/密码 等敏感信息,用了 UnitAuto 则一定要加 + @Override + public String getDBPassword() { + try { + return DynamicDataSource.getDetail(this.getDatasource()).getDbPassword(); + } catch (Exception e) { + throw new IllegalArgumentException("动态数据源配置错误 " + this.getDatasource()); + } + } + +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoSQLExecutor.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoSQLExecutor.java new file mode 100644 index 00000000..66b17e00 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DemoSQLExecutor.java @@ -0,0 +1,206 @@ +/*Copyright ©2016 TommyLemon(https://github.com/TommyLemon/APIJSON) + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License.*/ + +package apijson.demo; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.List; + +import javax.sql.DataSource; +import com.redbeardlab.redisql.client.ParseRediSQLReply; +import apijson.Log; +import apijson.NotNull; +import apijson.StringUtil; +import apijson.demo.resultSet.DataBuildResultSet; +import apijson.framework.APIJSONSQLExecutor; +import apijson.orm.SQLConfig; +import lombok.extern.log4j.Log4j2; + +/** + * SQL 执行器,支持连接池及多数据源 具体见 https://github.com/Tencent/APIJSON/issues/151 + * + * @author Lemon + */ +@Log4j2 +public class DemoSQLExecutor extends APIJSONSQLExecutor { + public static final String TAG = "DemoSQLExecutor"; + + // 适配连接池,如果这里能拿到连接池的有效 Connection,则 SQLConfig 不需要配置 dbVersion, dbUri, dbAccount, + // dbPassword + @Override + public Connection getConnection(SQLConfig config) throws Exception { + String datasource = config.getDatasource(); + Log.d(TAG, "getConnection config.getDatasource() = " + datasource); + + String key = datasource + "-" + config.getDatabase(); + Connection conn = connectionMap.get(key); + if (conn == null || conn.isClosed()) { + DataSource dataSource = DataBaseUtil.getDataSource(datasource); + connectionMap.put(key, dataSource == null ? null : dataSource.getConnection()); + } + return super.getConnection(config); + } + + @Override + public ResultSet executeQuery(@NotNull SQLConfig config, String sql) throws Exception { + if (config.isRedis()) { + return redisExecuteQuery(config, sql); + } + return super.executeQuery(config, sql); + } + + @SuppressWarnings("unchecked") + public ResultSet redisExecuteQuery(@NotNull SQLConfig config, String sql) throws Exception { + List> rsData = new ArrayList<>(); + List headers = new ArrayList<>(); + // redis不支持explain 查询 + if (config.isExplain()) { + // 没有查询到数据 + return new DataBuildResultSet(null, headers, rsData); + } + + if (config.getColumn() != null) { + headers = config.getColumn(); + } + + if (config.getTable().startsWith(JedisBuildData.REDIS_TABLE_KEY)) { + if (config.getColumn() != null) { + headers = config.getColumn(); + } else { + // redisql不支持返回字段名, select * 请把字段填充进去 + throw new IllegalArgumentException("redis table 查询必须指定 column !"); + } + sql = StringUtil.isEmpty(sql) ? config.getSQL(false) : sql; + switch (config.getMethod()) { + case GET: + case HEAD: + List retObj = DynamicDataSource.getDetail(config.getDatasource()).getJedisClusterUtil().crudBySearch(JedisClusterUtil.DB, sql); + if (ParseRediSQLReply.done_reply(retObj)) { + return new DataBuildResultSet(null, headers, rsData); + } else { + for (Object obj : retObj) { + List rowList = (List) obj; + List retData = new ArrayList<>(); + for (Object objData : rowList) { + if (objData instanceof Number) { + retData.add(objData); + } else { + // 字段值不存在 + if (objData == null) { + retData.add(null); + } else { + retData.add(ParseRediSQLReply.get_string(objData)); + } + } + } + rsData.add(retData); + } + return new DataBuildResultSet(null, headers, rsData); + } + default: + return new DataBuildResultSet(null, headers, rsData); + } + } + return null; + } + @Override + public int executeUpdate(@NotNull SQLConfig config, String sql) throws Exception { + if (config.isRedis()) { + return redisExecuteUpdate(config, sql); + } + return super.executeUpdate(config, sql); + } + + private int redisExecuteUpdate(@NotNull SQLConfig config, String sql) throws Exception { + // 数据库类型, 数据源 区分 + // 也可以通过表前缀区分 + // 操作类型, 约定redis表名前缀, 避免对值进行解析 + if (config.getTable().startsWith(JedisBuildData.REDIS_TABLE_KEY)) { + sql = StringUtil.isEmpty(sql) ? config.getSQL(false) : sql; + switch (config.getMethod()) { + case POST: + return DynamicDataSource.getDetail(config.getDatasource()).getJedisClusterUtil().crudByUpdate(JedisClusterUtil.DB, sql); + case PUT: + case DELETE: + // 后面有需要,直接修改apijson sql 生成语句 + // AbstractSQLConfig + int index = sql.indexOf("REGEXP BINARY"); + if (index > 0) { + sql = sql.replace("REGEXP BINARY", "="); + } else { + index = sql.indexOf("REGEXP"); + if (index > 0) { + sql = sql.replace("REGEXP", "="); + } + } + return DynamicDataSource.getDetail(config.getDatasource()).getJedisClusterUtil().crudByUpdate(JedisClusterUtil.DB, sql); + default: + return 0; + } + } + return 0; + } + /*** + * 查询返回字段值进行二次处理 + */ +// @Override +// protected JSONObject onPutColumn(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd +// , final int tablePosition, @NotNull JSONObject table, final int columnIndex, Join join, Map childMap) throws Exception { +// if (table == null) { // 对应副表 viceSql 不能生成正常 SQL, 或者是 ! - Outer, ( - ANTI JOIN 的副表这种不需要缓存及返回的数据 +// Log.i(TAG, "onPutColumn table == null >> return table;"); +// return table; +// } +// +// if (isHideColumn(config, rs, rsmd, tablePosition, table, columnIndex, childMap)) { +// Log.i(TAG, "onPutColumn isHideColumn(config, rs, rsmd, tablePosition, table, columnIndex, childMap) >> return table;"); +// return table; +// } +// +// String label = getKey(config, rs, rsmd, tablePosition, table, columnIndex, childMap); +// Object value = getValue(config, rs, rsmd, tablePosition, table, columnIndex, label, childMap); +// +// // TODO +// if(StringUtils.equals(config.getTable(), "User") && StringUtils.equals(label, "addr_id")) { +// value = "1-1-1"; +// } +// // 主表必须 put 至少一个 null 进去,否则全部字段为 null 都不 put 会导致中断后续正常返回值 +// if (value != null || (join == null && table.isEmpty())) { +// table.put(label, value); +// } +// +// return table; +// } + + // 取消注释支持 !key 反选字段 和 字段名映射,需要先依赖插件 https://github.com/APIJSON/apijson-column + // @Override + // protected String getKey(SQLConfig config, ResultSet rs, ResultSetMetaData + // rsmd, int tablePosition, JSONObject table, + // int columnIndex, Map childMap) throws Exception { + // return ColumnUtil.compatOutputKey(super.getKey(config, rs, rsmd, + // tablePosition, table, columnIndex, childMap), config.getTable(), + // config.getMethod()); + // } + + // 不需要隐藏字段这个功能时,取消注释来提升性能 + // @Override + // protected boolean isHideColumn(SQLConfig config, ResultSet rs, + // ResultSetMetaData rsmd, int tablePosition, + // JSONObject table, int columnIndex, Map childMap) throws + // SQLException { + // return false; + // } + +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DynamicDataSource.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DynamicDataSource.java new file mode 100644 index 00000000..88d6ed57 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/DynamicDataSource.java @@ -0,0 +1,157 @@ +package apijson.demo; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.alibaba.druid.pool.DruidDataSource; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.ds.ItemDataSource; +import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils; + +import apijson.orm.SQLConfig; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/*** + * 不存在并发问题 缓存 jdbc 数据源,供apijson调用 1、应用启动添加数据源 2、页面动态添加数据源(数据库存储数据源信息) + * + * + */ +@Data +@Order(value = 10) +@Component +@Slf4j +public class DynamicDataSource implements ApplicationRunner { + // value: 数据源相关信息 + private static Map dataSourceMap = new HashMap<>(); + private static final String DB = "DB"; + // redis 数据源 + private JedisClusterUtil jedisClusterUtil; + private String database; // 表所在的数据库类型 + private String schema; // 表所在的数据库名 + private String datasourceName; // 数据源 + private String url; // jdbc url + private String dbAccount; // 数据库用户名 + private String dbPassword; // 数据库密码 + private String dbVersion; // 数据库版本号 + private String clusterName; // 集群名称 + private Properties props; // 属性值 + + @Autowired + private DataSource dataSource; // 数据源 + + public static void addDataSource(DynamicDataSource detail) { + dataSourceMap.put(detail.getDatasourceName(), detail); + } + + /*** + * 获取数据源详细信息 + * + * @return + */ + public static DynamicDataSource getDetail(String datasource) { + if (datasource == null) { + // 默认数据源 + datasource = DataBaseConfig.getInstence().getPrimary(); + } + // 不存在交给框架处理 + return dataSourceMap.get(datasource); + } + + @Override + public void run(ApplicationArguments args) throws Exception { + initJdbcDataSource(); // 初始化spring application.xml 数据库连接池 + + // redisCluster + initRedisCluster(); + } + + /*** + * 仅供测试使用 + */ + public void initRedisCluster() { + JedisClusterUtil jedisClusterUtil = new JedisClusterUtil(); + jedisClusterUtil.createJedisPool(); + jedisClusterUtil.setJedis(DB); + + DynamicDataSource dynDataSource = new DynamicDataSource(); + dynDataSource.setDatasourceName("redisCluster"); + dynDataSource.setDatabase(SQLConfig.DATABASE_REDIS); + dynDataSource.setSchema(""); // 不需要配置数据库名 + dynDataSource.setDbVersion("7.0.6"); // 后面做成动态的 + dynDataSource.setClusterName("redis-cluster"); + dynDataSource.setJedisClusterUtil(jedisClusterUtil); + dataSourceMap.put(dynDataSource.getDatasourceName(), dynDataSource); + } + + /*** + * 初始化数据库连接池 + */ + private void initJdbcDataSource() { + DynamicRoutingDataSource dataSourceList = (DynamicRoutingDataSource) this.dataSource; + for (String datasourceName : dataSourceList.getDataSources().keySet()) { + ItemDataSource dataSource = (ItemDataSource) dataSourceList.getDataSources().get(datasourceName); + DruidDataSource druid = (DruidDataSource) dataSource.getRealDataSource(); + String url = druid.getDataSourceStat().getUrl(); // 数据库连接url + String schema = DataBaseUtil.getLibname(url); // 数据库名; + String database = JdbcUtils.getDbType(url).getDb().toUpperCase(); // 数据库类型 + String dbAccount = druid.getUsername(); // 数据库用户名 + String dbPassword = druid.getPassword(); // 数据库密码 + String dbVersion = getDBVersion(dataSource); + + DynamicDataSource dynDataSource = new DynamicDataSource(); + dynDataSource.setDatasourceName(datasourceName); + dynDataSource.setDatabase(database); + dynDataSource.setDataSource(druid); + dynDataSource.setSchema(schema); + dynDataSource.setUrl(url); + dynDataSource.setDbAccount(dbAccount); + dynDataSource.setDbPassword(dbPassword); + dynDataSource.setDbVersion(dbVersion); + dataSourceMap.put(datasourceName, dynDataSource); + } + } + + public String getDBVersion(DataSource dataSource) { + Connection connection = null; + Statement statement = null; + ResultSet resultSet = null; + try { + connection = dataSource.getConnection(); + statement = connection.createStatement(); + resultSet = statement.executeQuery("select version() as version"); + while (resultSet.next()) { + return resultSet.getString("version"); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (resultSet != null) { + resultSet.close(); + } + if (statement != null) { + statement.close(); + } + if (connection != null) { + connection.close(); + } + } catch (SQLException throwables) { + } + } + return null; + } +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/JedisBuildData.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/JedisBuildData.java new file mode 100644 index 00000000..36973622 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/JedisBuildData.java @@ -0,0 +1,193 @@ +package apijson.demo; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import apijson.JSONObject; +import apijson.NotNull; +import apijson.orm.SQLConfig; +import org.apache.commons.lang.StringUtils; + +/*** + * 构建数据 + * + */ +public class JedisBuildData { + //redis data type + public static final String REDIS_TABLE_KEY = "REDIS_TABLE_"; // rediSql table + public static final String REDIS_STRING_KEY = "REDIS_STRING"; + public static final String REDIS_HASH_KEY = "REDIS_HASH"; + public static final String REDIS_LIST_KEY = "REDIS_LIST"; + public static final String REDIS_SET_KEY = "REDIS_SET"; + public static final String REDIS_ZSET_KEY = "REDIS_ZSET"; + //https://www.runoob.com/redis/redis-keys.html + public static final String REDIS_KEYS = "REDIS_KEYS"; + + //apijson 字段名 + //varchar + public static final String COLUMN_KEY = "key"; // Redis的key + //varchar + public static final String COLUMN_VALUE = "value"; // 对应数据类型的value值 + //double + public static final String COLUMN_SCORE = "score"; // 表示SortedSet的分值,其他数据类型为null + //bigint + public static final String COLUMN_EXPIRE_TIME = "expire_time"; // 跟Redis的ttl命令一致,表示数据离过期的剩余秒数 + //varchar + public static final String OPTION_METHOD = "option_method"; // 操作方法 + //当数据是string/set类型时,这个字段没有太大意义;当数据是list/zset时,该字段表示该数据类型的下标;当数据是hash类型时,该字段表示hash数据内的key值。 + public static final String COLUMN_INDEX = "index"; + + //操作方法 + //POST + //REDIS_STRING_KEY + public static final String OPTION_METHOD_SET = "set"; + //REDIS_LIST_KEY + public static final String OPTION_METHOD_LPUSH = "lpush"; + public static final String OPTION_METHOD_RPUSH = "rpush"; + public static final String OPTION_METHOD_LSET = "lset"; + public static final String OPTION_METHOD_LINSERT = "linsert"; + //REDIS_HASH_KEY + public static final String OPTION_METHOD_HSET = "hset"; + //apijson json批量插入来实现, apijson目前不支持sql批量插入 + public static final String OPTION_METHOD_HMSET = "hmset"; + + //REDIS_SET_KEY + public static final String OPTION_METHOD_SADD = "sadd"; + + //REDIS_ZSET_KEY + public static final String OPTION_METHOD_ZADD = "zadd"; + public static final String OPTION_METHOD_ZINTERSTORE = "zinterstore"; + public static final String OPTION_METHOD_ZUNIONSTORE = "zunionstore"; + + //REDIS_KEYS + public static final String OPTION_METHOD_EXPIRE = "expire"; + + + //PUT + //REDIS_STRING_KEY + public static final String OPTION_METHOD_APPEND = "append"; + + //REDIS_LIST_KEY + public static final String OPTION_METHOD_LTRIM = "ltrim"; + //REDIS_SET_KEY + public static final String OPTION_METHOD_SMOVE = "smove"; + + //DELETE + //REDIS_STRING_KEY + public static final String OPTION_METHOD_DEL = "del"; + + //REDIS_LIST_KEY + public static final String OPTION_METHOD_LREM = "lrem"; + + //REDIS_HASH_KEY + public static final String OPTION_METHOD_HDEL = "hdel"; + public static final String OPTION_METHOD_HINCRBY = "hincrby"; + + //REDIS_SET_KEY + public static final String OPTION_METHOD_SREM = "srem"; + //REDIS_ZSET_KEY + public static final String OPTION_METHOD_ZINCRBY = "zincrby"; + public static final String OPTION_METHOD_ZREM = "zrem"; + public static final String OPTION_METHOD_ZREMRANGEBYLEX = "zremrangeByLex"; + public static final String OPTION_METHOD_ZREMRANGEBYRANK = "zremrangeByRank"; + public static final String OPTION_METHOD_ZREMRANGEBYSCORE = "zremrangebyscore"; + + //GET + //REDIS_KEYS + public static final String OPTION_METHOD_EXISTS = "exists"; + public static final String OPTION_METHOD_KEYS = "keys"; + public static final String OPTION_METHOD_TIMETOLIVE = "timeToLive"; + public static final String OPTION_METHOD_TYPE = "type"; + public static final String OPTION_METHOD_STRLEN = "strlen"; + + //REDIS_STRING_KEY + public static final String OPTION_METHOD_GET = "get"; + public static final String OPTION_METHOD_INCR = "incr"; + public static final String OPTION_METHOD_DECR = "decr"; + public static final String OPTION_METHOD_INCRBY = "incrby"; + public static final String OPTION_METHOD_DECRBY = "decrby"; + public static final String OPTION_METHOD_SETEX = "setex"; + public static final String OPTION_METHOD_SETNX ="setnx"; + + //REDIS_LIST_KEY + public static final String OPTION_METHOD_LPOP = "lpop"; + public static final String OPTION_METHOD_RPOP = "rpop"; + public static final String OPTION_METHOD_LRANGE = "lrange"; + public static final String OPTION_METHOD_LINDEX = "lindex"; + public static final String OPTION_METHOD_LLEN = "llen"; + public static final String OPTION_METHOD_BLPOP = "blpop"; + public static final String OPTION_METHOD_BRPOP = "brpop"; + + //REDIS_HASH_KEY + public static final String OPTION_METHOD_HGET = "hget"; + public static final String OPTION_METHOD_HMGET = "hmget"; + public static final String OPTION_METHOD_HGETALL = "hgetall"; + public static final String OPTION_METHOD_HEXISTS = "hexists"; + public static final String OPTION_METHOD_HKEYS = "hkeys"; + public static final String OPTION_METHOD_HVALS = "hvals"; + + //REDIS_SET_KEY + public static final String OPTION_METHOD_SMEMBERS = "smembers"; + public static final String OPTION_METHOD_SISMEMBER = "sismember"; + public static final String OPTION_METHOD_SCARD = "scard"; + public static final String OPTION_METHOD_SRANDMEMBER = "srandmember"; + public static final String OPTION_METHOD_SPOP = "spop"; + public static final String OPTION_METHOD_SINTER = "sinter"; + public static final String OPTION_METHOD_SUNION = "sunion"; + public static final String OPTION_METHOD_SDIFF = "sdiff"; + + //REDIS_ZSET_KEY + public static final String OPTION_METHOD_ZCARD = "zcard"; + public static final String OPTION_METHOD_ZCOUNT = "zcount"; + public static final String OPTION_METHOD_ZLEXCOUNT = "zlexcount"; + public static final String OPTION_METHOD_ZRANGE = "zrange"; + public static final String OPTION_METHOD_ZRANGEBYSCORE = "zrangeByScore"; + public static final String OPTION_METHOD_ZRANGEBYLEX = "zrangeByLex"; + public static final String OPTION_METHOD_ZRANK = "zrank"; + public static final String OPTION_METHOD_ZREVRANGE = "zrevrange"; + public static final String OPTION_METHOD_ZREVRANGEBYSCORE = "zrevrangeByScore"; + public static final String OPTION_METHOD_ZREVRANK = "zrevrank"; + public static final String OPTION_METHOD_ZSCORE = "zscore"; + public static final String OPTION_METHOD_ZSCAN = "zscan"; + + + public static Map buidData(@NotNull SQLConfig config) { + Map dataMap = new HashMap<>(); + switch (config.getMethod()) { + case POST: + for (int i = 0; i < config.getColumn().size(); i++) { + String column = config.getColumn().get(i); + for (List list : config.getValues()) { + Object data = list.get(i); + dataMap.put(column, data); + } + } + return dataMap; + case PUT: + dataMap.putAll(config.getContent()); + dataMap.putAll(config.getWhere()); + return dataMap; + case DELETE: + return config.getWhere(); + default: + return dataMap; + } + } + + @SuppressWarnings("unchecked") + public static T getResponseData(String key,Map dataMap){ + return (T) dataMap.get(key); + } + + @SuppressWarnings("unchecked") + public T getStringData(Class clazz,String json){ + if (StringUtils.isBlank(json)){ + return null; + } + if (clazz.equals(String.class) || clazz.equals(Object.class)){ + return (T) json; + } + return JSONObject.parseObject(json, clazz); + } +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/JedisClusterUtil.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/JedisClusterUtil.java new file mode 100644 index 00000000..8f973a9f --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/JedisClusterUtil.java @@ -0,0 +1,1010 @@ +package apijson.demo; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.redbeardlab.redisql.client.ParseRediSQLReply; +import com.redbeardlab.redisql.client.RediSQLCommand; + +import lombok.extern.slf4j.Slf4j; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.JedisPoolConfig; +import redis.clients.jedis.ListPosition; +import redis.clients.jedis.ScanResult; +import redis.clients.jedis.Tuple; +import redis.clients.jedis.util.JedisClusterCRC16; + +/*** + * cluster模式 https://cloud.tencent.com/developer/article/1985822 + */ +@Slf4j +public class JedisClusterUtil { + private JedisCluster jedisCluster; + public static final String DB = "DB"; + ParseRediSQLReply parser = new ParseRediSQLReply(); + private Jedis jedis; + // 可用连接实例的最大数目,默认为8; + // 如果赋值为-1,则表示不限制,如果sentinelPool已经分配了maxActive个jedis实例,则此时sentinelPool的状态为exhausted(耗尽) + private static Integer MAX_TOTAL = 1024; + // 控制一个sentinelPool最多有多少个状态为idle(空闲)的jedis实例,默认值是8 + private static Integer MAX_IDLE = 200; + // 等待可用连接的最大时间,单位是毫秒,默认值为-1,表示永不超时。 + // 如果超过等待时间,则直接抛出JedisConnectionException + private static Integer MAX_WAIT_MILLIS = 10000; + // 客户端超时时间配置 + private static Integer TIMEOUT = 10000; + // 在borrow(用)一个jedis实例时,是否提前进行validate(验证)操作; + // 如果为true,则得到的jedis实例均是可用的 + private static Boolean TEST_ON_BORROW = true; + // 在空闲时检查有效性, 默认false + private static Boolean TEST_WHILE_IDLE = true; + // 是否进行有效性检查 + private static Boolean TEST_ON_RETURN = true; + private static String PASSWORD = ""; + + /** + * 创建连接池 + */ + public void createJedisPool() { + Set jedisClusterNode = new HashSet(); + jedisClusterNode.add(new HostAndPort("127.0.0.1", 6371)); + jedisClusterNode.add(new HostAndPort("127.0.0.1", 6372)); + jedisClusterNode.add(new HostAndPort("127.0.0.1", 6373)); + jedisClusterNode.add(new HostAndPort("127.0.0.1", 6374)); + jedisClusterNode.add(new HostAndPort("127.0.0.1", 6375)); + jedisClusterNode.add(new HostAndPort("127.0.0.1", 6376)); + JedisPoolConfig poolConfig = new JedisPoolConfig(); + /* + * 注意: 在高版本的jedis jar包,比如本版本2.9.0,JedisPoolConfig没有setMaxActive和setMaxWait属性了 + * 这是因为高版本中官方废弃了此方法,用以下两个属性替换。 maxActive ==> maxTotal maxWait==> maxWaitMillis + */ + poolConfig.setMaxTotal(MAX_TOTAL); + poolConfig.setMaxIdle(MAX_IDLE); + poolConfig.setMaxWaitMillis(MAX_WAIT_MILLIS); + poolConfig.setTestOnBorrow(TEST_ON_BORROW); + poolConfig.setTestWhileIdle(TEST_WHILE_IDLE); + poolConfig.setTestOnReturn(TEST_ON_RETURN); + int connectionTimeout = 3000; + int soTimeout = 3000; + int maxAttempts = 5; + // JedisCluster jc = new JedisCluster(jedisClusterNode, DEFAULT_TIMEOUT, + // DEFAULT_TIMEOUT, DEFAULT_REDIRECTIONS, "cluster", DEFAULT_CONFIG); + jedisCluster = new JedisCluster(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, PASSWORD, poolConfig); + log.info("节点信息:{}", jedisCluster.getClusterNodes().keySet()); + } + + public void closePool() { + if (jedisCluster != null) { + jedisCluster.close(); + } + } + + // 获取连接 + public void setJedis(String db) { + int slot = JedisClusterCRC16.getSlot(db); + jedis = jedisCluster.getConnectionFromSlot(slot); + } + + public Jedis getJedis(String key) { + int slot = JedisClusterCRC16.getSlot(key); + return jedisCluster.getConnectionFromSlot(slot); + + } + + private String ok_returns(RediSQLCommand.ModuleCommand cmd, String... args) { + try { + jedis.getClient().sendCommand(cmd, args); + return jedis.getClient().getBulkReply(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (jedis != null) { + jedis.close(); + } + } + return null; + } + + private List list_returns(RediSQLCommand.ModuleCommand cmd, String... args) { + try { + jedis.getClient().sendCommand(cmd, args); + return jedis.getClient().getObjectMultiBulkReply(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (jedis != null) { + jedis.close(); + } + } + return null; + } + + public void delDB(String key) { + try { + jedis.del(key); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (jedis != null) { + jedis.close(); + } + } + } + + public String create_db(String db) { + return ok_returns(RediSQLCommand.ModuleCommand.CREATE_DB, db); + } + + public String create_db(String db, String file_path) { + return ok_returns(RediSQLCommand.ModuleCommand.CREATE_DB, db, file_path); + } + + public List exec(String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.EXEC, db, query); + } + + public List exec_now(String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.EXEC_NOW, db, query); + } + + public List query(String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY, db, query); + } + + public List query_now(String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_NOW, db, query); + } + + public List query_into(String stream, String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_INTO, stream, db, query); + } + + public List query_into_now(String stream, String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_INTO_NOW, stream, db, query); + } + + public String create_statement(String db, String stmt_name, String stmt_query) { + return ok_returns(RediSQLCommand.ModuleCommand.CREATE_STATEMENT, db, stmt_name, stmt_query); + } + + public String create_statement_now(String db, String stmt_name, String stmt_query) { + return ok_returns(RediSQLCommand.ModuleCommand.CREATE_STATEMENT_NOW, db, stmt_name, stmt_query); + } + + public List exec_statement(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.EXEC_STATEMENT, args); + } + + public List exec_statement_now(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.EXEC_STATEMENT_NOW, args); + } + + public List query_statement(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_STATEMENT, args); + } + + public List query_statement_now(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_STATEMENT_NOW, args); + } + + public List query_statement_into(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_STATEMENT_INTO, args); + } + + public List query_statement_into_now(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_STATEMENT_INTO_NOW, args); + } + + public String delete_statement(String db, String stmt_name) { + return ok_returns(RediSQLCommand.ModuleCommand.DELETE_STATEMENT, db, stmt_name); + } + + public String delete_statement_now(String db, String stmt_name) { + return ok_returns(RediSQLCommand.ModuleCommand.DELETE_STATEMENT_NOW, db, stmt_name); + } + + public String update_statement(String db, String stmt_name, String stmt_query) { + return ok_returns(RediSQLCommand.ModuleCommand.UPDATE_STATEMENT, db, stmt_name, stmt_query); + } + + public String update_statement_now(String db, String stmt_name, String stmt_query) { + return ok_returns(RediSQLCommand.ModuleCommand.UPDATE_STATEMENT_NOW, db, stmt_name, stmt_query); + } + + public String copy(String db1, String db2) { + return ok_returns(RediSQLCommand.ModuleCommand.COPY, db1, db2); + } + + public String copy_now(String db1, String db2) { + return ok_returns(RediSQLCommand.ModuleCommand.COPY_NOW, db1, db2); + } + + public List statistics() { + return list_returns(RediSQLCommand.ModuleCommand.STATISTICS); + } + + public String version(String db1, String db2) { + return ok_returns(RediSQLCommand.ModuleCommand.VERSION); + } + + public List crudBySearch(String db, String sql) throws Exception { + return exec(db, sql); + } + + public int crudByUpdate(String db, String sql) throws Exception { + List retObj = exec(db, sql); + return ParseRediSQLReply.how_many_done(retObj).intValue(); + } + + /* ######################## key的操作 ################################ */ + + /** + * 根据pattern返回当前库中的key + * + * @param pattern + * @return + */ + public Set keys(String pattern) { + return jedisCluster.keys(pattern); + } + + /** + * 删除一个或多个key + * + * @param key 一个或多个key + */ + public long del(String... key) { + return jedisCluster.del(key); + } + + /** + * 判断某个key是否还存在 + * + * @param key key + * @return + */ + public Boolean exists(String key) { + return jedisCluster.exists(key); + } + + /** + * 设置某个key的过期时间,单位秒 + * + * @param key key + * @param seconds 过期时间秒 + */ + public void expire(String key, long seconds) { + jedisCluster.expire(key, seconds); + } + + /** + * 查看某个key还有几秒过期,-1表示永不过期 ,-2表示已过期 + * + * @param key key + * @return + */ + public long timeToLive(String key) { + return jedisCluster.ttl(key); + } + + /** + * 查看某个key对应的value的类型 + * + * @param key + * @return + */ + public String type(String key) { + return jedisCluster.type(key); + } + + /* ######################## string(字符串)的操作 #################### */ + + /** + * 获取某个key的value,类型要对,只能value是string的才能获取 + * + * @param key + * @return + */ + public String get(String key) { + return jedisCluster.get(key); + } + + /** + * 设置某个key的value + * + * @param key + * @param value + */ + public void set(String key, String value) { + jedisCluster.set(key, value); + } + + /** + * 字符串后追加内容 + * + * @param key key + * @param appendContent 要追加的内容 + */ + public void append(String key, String appendContent) { + jedisCluster.append(key, appendContent); + } + + /** + * 返回key的value的长度 + * + * @param key + * @return + */ + public long strlen(String key) { + return jedisCluster.strlen(key); + } + + /** + * value 加1 必 须是字符型数字 + * + * @param key + * @return 增加后的值 + */ + public long incr(String key) { + return jedisCluster.incr(key); + } + + /** + * value 减1 必须是字符型数字 + * + * @param key + * @return + */ + public long decr(String key) { + return jedisCluster.decr(key); + } + + /** + * value 加increment + * + * @param key key + * @param increment 加几 + * @return + */ + public long incrby(String key, int increment) { + return jedisCluster.incrBy(key, increment); + } + + /** + * value 减increment + * + * @param key + * @param increment + * @return + */ + public long decrby(String key, int increment) { + return jedisCluster.decrBy(key, increment); + } + + /** + * 给某个key设置过期时间和value,成功返回OK + * + * @param key key + * @param seconds 过期时间秒 + * @param value 设置的值 + * @return + */ + public String setex(String key, int seconds, String value) { + return jedisCluster.setex(key, seconds, value); + } + + /* ######################## list(列表)的操作 ####################### */ + // lpush rpush lpop rpop lrange lindex llen lset lrem + + /** + * 从左边向列表中添加值 + * + * @param key key + * @param str 要添加的值 + */ + public void lpush(String key, String str) { + jedisCluster.lpush(key, str); + } + + /** + * 从右边向列表中添加值 + * + * @param key key + * @param str 要添加的值 + */ + public void rpush(String key, String str) { + jedisCluster.rpush(key, str); + } + + /** + * 从左边取出一个列表中的值 + * + * @param key + * @return + */ + public String lpop(String key) { + return jedisCluster.lpop(key); + } + + /** + * 从右边取出一个列表中的值 + * + * @param key + * @return + */ + public String rpop(String key) { + return jedisCluster.rpop(key); + } + + /** + * 取出列表中指定范围内的值,0 到 -1 表示全部 + * + * @param key + * @param startIndex + * @param endIndex + * @return + */ + public List lrange(String key, int startIndex, int endIndex) { + return jedisCluster.lrange(key, startIndex, endIndex); + } + + /** + * 返回某列表指定索引位置的值 + * + * @param key 列表key + * @param index 索引位置 + * @return + */ + public String lindex(String key, int index) { + return jedisCluster.lindex(key, index); + } + + /** + * 返回某列表的长度 + * + * @param key + * @return + */ + public long llen(String key) { + return jedisCluster.llen(key); + } + + /** + * 给某列表指定位置设置为指定的值 + * + * @param key + * @param index + * @param str + */ + public void lset(String key, long index, String str) { + jedisCluster.lset(key, index, str); + } + + public void linsert(final String key, final ListPosition where, final String pivot, final String value) { + jedisCluster.linsert(key, where, pivot, value); + } + + /** + * 对列表进行剪裁,保留指定闭区间的元素(索引位置也会重排) + * + * @param key 列表key + * @param startIndex 开始索引位置 + * @param endIndex 结束索引位置 + */ + public void ltrim(String key, Integer startIndex, Integer endIndex) { + jedisCluster.ltrim(key, startIndex, endIndex); + } + + /** + * 从列表的左边阻塞弹出一个元素 + * + * @param key 列表的key + * @param timeout 阻塞超时时间,0表示若没有元素就永久阻塞 + * @return + */ + public List blpop(String key, Integer timeout) { + return jedisCluster.blpop(timeout, key); + } + + /** + * 从列表的右边阻塞弹出一个元素 + * + * @param key 列表的key + * @param timeout 阻塞超时时间,0表示若没有元素就永久阻塞 + * @return + */ + public List brpop(String key, Integer timeout) { + return jedisCluster.brpop(timeout, key); + } + + /** + * 移除列表元素 + * + * @param key + * @param index + * @param str + */ + public void lrem(String key, long count, String value) { + jedisCluster.lrem(key, count, value); + } + + /* ######################## hash(哈希表)的操作 ####################### */ + // hset hget hmset hmget hgetall hdel hkeys hvals hexists hincrby + + /** + * 给某个hash表设置一个键值对 + * + * @param key + * @param field + * @param value + */ + public void hset(String key, String field, String value) { + jedisCluster.hset(key, field, value); + } + + /** + * 取出某个hash表中某个field对应的value + * + * @param key key + * @param field field + * @return + */ + public String hget(String key, String field) { + return jedisCluster.hget(key, field); + } + + /** + * 某个hash表设置一个或多个键值对 + * + * @param key + * @param kvMap + */ + public void hmset(String key, Map kvMap) { + jedisCluster.hmset(key, kvMap); + } + + /** + * 取出某个hash表中任意多个key对应的value的集合 + * + * @param key + * @param fields + * @return + */ + public List hmget(String key, String... fields) { + return jedisCluster.hmget(key, fields); + } + + /** + * 取出某个hash表中所有的键值对 + * + * @param key + * @return + */ + public Map hgetall(String key) { + return jedisCluster.hgetAll(key); + } + + /** + * 判断某个hash表中的某个key是否存在 + * + * @param key + * @param field + * @return + */ + public Boolean hexists(String key, String field) { + return jedisCluster.hexists(key, field); + } + + /** + * 返回某个hash表中所有的key + * + * @param key + * @return + */ + public Set hkeys(String key) { + return jedisCluster.hkeys(key); + } + + /** + * 返回某个hash表中所有的value + * + * @param key + * @return + */ + public List hvals(String key) { + return jedisCluster.hvals(key); + } + + /** + * 删除某个hash表中的一个或多个键值对 + * + * @param key + * @param fields + */ + public void hdel(String key, String... fields) { + jedisCluster.hdel(key, fields); + } + + /** + * 给某个hash表中的某个field的value增加多少 + * + * @param key hash表的key + * @param field 表中的某个field + * @param increment 增加多少 + * @return + */ + public long hincrby(String key, String field, long increment) { + return jedisCluster.hincrBy(key, field, increment); + } + + /* ######################## set(集合)的操作 ########################### */ + + /** + * 往set集合中添加一个或多个元素 + * + * @param key key + * @param members 要添加的元素 + * @return 添加成功的元素个数 + */ + public long sadd(String key, String... members) { + return jedisCluster.sadd(key, members); + } + + /** + * 返回set集合中的所有元素,顺序与加入时的顺序一致 + * + * @param key key + * @return + */ + public Set smembers(String key) { + return jedisCluster.smembers(key); + } + + /** + * 判断集合中是否存在某个元素 + * + * @param key key + * @param member 某个元素 + * @return true存在,false不存在 + */ + public Boolean sismember(String key, String member) { + return jedisCluster.sismember(key, member); + } + + /** + * 返回set集合的长度 + * + * @param key key + * @return + */ + public long scard(String key) { + return jedisCluster.scard(key); + } + + /** + * 删除set集合中指定的一个或多个元素 + * + * @param key + * @param members 要删除的元素 + * @return 删除成功的元素个数 + */ + public long srem(String key, String... members) { + return jedisCluster.srem(key, members); + } + + /** + * 将key1中的元素key1Member移动到key2中 + * + * @param key1 来源集合key + * @param key2 目的地集合key + * @param key1Member key1中的元素 + * @return 1成功,0失败 + */ + public long smove(String key1, String key2, String key1Member) { + return jedisCluster.smove(key1, key2, key1Member); + } + + /** + * 随机查询返回集合中的指定个数的元素(若count为负数,返回的元素可能会重复) + * + * @param key key + * @param count 要查询返回的元素个数 + * @return 元素list集合 + */ + public List srandmember(String key, int count) { + return jedisCluster.srandmember(key, count); + } + + /** + * 从set集合中随机弹出指定个数个元素 + * + * @param key key + * @param count 要弹出的个数 + * @return 随机弹出的元素 + */ + public Set spop(String key, int count) { + return jedisCluster.spop(key, count); + } + + /** + * 求交集,返回多个set集合相交的部分 + * + * @param setKeys 多个set集合的key + * @return 相交的元素集合 + */ + public Set sinter(String... setKeys) { + return jedisCluster.sinter(setKeys); + } + + /** + * 求并集,求几个set集合的并集(因为set中不会有重复的元素,合并后的集合也不会有重复的元素) + * + * @param setKeys 多个set的key + * @return 合并后的集合 + */ + public Set sunion(String... setKeys) { + return jedisCluster.sunion(setKeys); + } + + /** + * 求差集,求几个集合之间的差集 + * + * @param setKeys 多个set的key + * @return 差集 + */ + public Set sdiff(String... setKeys) { + return jedisCluster.sdiff(setKeys); + } + + /* ######################## zset(有序集合)的操作 ####################### */ + + /** + * 添加一个元素到zset + * + * @param key key + * @param score 元素的分数 + * @param member 元素 + * @return 成功添加的元素个数 + */ + public long zadd(String key, double score, String member) { + return jedisCluster.zadd(key, score, member); + } + + public long zadd(String key, Map scoreMembers) { + return jedisCluster.zadd(key, scoreMembers); + } + + /** + * 获取有序集合的成员数 + * + * @param key key + * @return + */ + public long zcard(String key) { + return jedisCluster.zcard(key); + } + + /** + * 计算在有序集合中指定区间分数的成员数 + * + * @param key + * @param min + * @param max + * @return + */ + public long zcount(String key, double min, double max) { + return jedisCluster.zcount(key, min, max); + } + + /** + * 有序集合中对指定成员的分数加上增量 increment + * + * @param key + * @param increment + * @param member + * @return + */ + public Double zincrby(String key, double increment, String member) { + return jedisCluster.zincrby(key, increment, member); + } + + /** + * 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 destination 中 + * + * @param dstkey + * @param sets + * @return + */ + public long zinterstore(String dstkey, String... sets) { + return jedisCluster.zinterstore(dstkey, sets); + } + + /** + * 在有序集合中计算指定字典区间内成员数量 + * + * @param key + * @param min + * @param max + * @return + */ + public long zlexcount(String key, String min, String max) { + return jedisCluster.zlexcount(key, min, max); + } + + /** + * 通过索引区间返回有序集合指定区间内的成员 + * + * @param key + * @param min + * @param max + * @return + */ + public Set zrange(String key, long start, long stop) { + return jedisCluster.zrange(key, start, stop); + } + + /** + * 通过索引区间返回有序集合指定区间内的成员 + * + * @param key + * @param min + * @param max + * @return + */ + public Set zrangeByScore(String key, double min, double max) { + return jedisCluster.zrangeByScore(key, min, max); + } + + /*** + * 通过字典区间返回有序集合的成员 + * + * @param key + * @param min + * @param max + * @return + */ + public Set zrangeByLex(String key, String min, String max) { + return jedisCluster.zrangeByLex(key, min, max); + } + + /** + * 返回有序集合中指定成员的索引 + * + * @param key + * @param member + * @return + */ + public long zrank(String key, String member) { + return jedisCluster.zrank(key, member); + } + + /** + * + * @param key + * @param values + * @return + */ + public long zrem(String key, String... members) { + return jedisCluster.zrem(key, members); + } + + /** + * 移除有序集合中给定的字典区间的所有成员 + * + * @param key + * @param min + * @param max + * @return + */ + public long zremrangeByLex(String key, String min, String max) { + return jedisCluster.zremrangeByLex(key, min, max); + } + + /** + * 移除有序集合中给定的排名区间的所有成员 + * + * @param key + * @param start + * @param stop + * @return + */ + public long zremrangeByRank(String key, long start, long stop) { + return jedisCluster.zremrangeByRank(key, start, stop); + } + + /** + * 移除有序集合中给定的分数区间的所有成员 + * + * @param key + * @param min + * @param max + * @return + */ + public long zremrangebyscore(String key, double min, double max) { + return jedisCluster.zremrangeByScore(key, min, max); + } + + /** + * 返回有序集中指定区间内的成员,通过索引,分数从高到低 + * + * @param key + * @param start + * @param stop + * @return + */ + public Set zrevrange(String key, long start, long stop) { + return jedisCluster.zrevrange(key, start, stop); + } + + /** + * 返回有序集中指定分数区间内的成员,分数从高到低排序 + * + * @param key + * @param min + * @param max + * @return + */ + public Set zrevrangeByScore(String key, double min, double max) { + return jedisCluster.zrevrangeByScore(key, min, max); + } + + /** + * 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序 + * + * @param key + * @param member + * @return + */ + public long zrevrank(String key, String member) { + return jedisCluster.zrevrank(key, member); + } + + /** + * 返回有序集中,成员的分数值 + * + * @param key + * @param value + * @return + */ + public double zscore(String key, String value) { + return jedisCluster.zscore(key, value); + } + + /** + * 计算给定的一个或多个有序集的并集,并存储在新的 key 中 + * + * @param dstkey + * @param sets + * @return + */ + public long zunionstore(String dstkey, String... sets) { + return jedisCluster.zunionstore(dstkey, sets); + } + + /** + * 迭代有序集合中的元素(包括元素成员和元素分值) + * + * @param key + * @param cursor + * @return + */ + public ScanResult zscan(String key, String cursor) { + return jedisCluster.zscan(key, cursor); + } + + + /** + * 在指定的 key 不存在时,为 key 设置指定的值。 + * + * @param key + * @param value + * @return + */ + public Long setnx(String key,String value) { + return jedisCluster.setnx(key,value); + } +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/SpringContextUtils.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/SpringContextUtils.java new file mode 100644 index 00000000..7a8e8f4f --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/SpringContextUtils.java @@ -0,0 +1,60 @@ +package apijson.demo; + +import java.util.Map; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * Spring Context 工具类 + * + * @author + */ +@Component +public class SpringContextUtils implements ApplicationContextAware { + public static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + SpringContextUtils.applicationContext = applicationContext; + } + + public static Object getBean(String name) { + return applicationContext.getBean(name); + } + + public static T getBean(String name, Class requiredType) { + return applicationContext.getBean(name, requiredType); + } + + /** + * 通过class获取Bean. + * + * @param clazz + * @param + * @return + */ + public static T getBean(Class clazz) { + return applicationContext.getBean(clazz); + } + + public static boolean containsBean(String name) { + return applicationContext.containsBean(name); + } + + public static boolean isSingleton(String name) { + return applicationContext.isSingleton(name); + } + + public static Class getType(String name) { + return applicationContext.getType(name); + } + + public static Map getBeansOfType(Class type) { + return applicationContext.getBeansOfType(type); + } + +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/resultSet/DataBuildResultSet.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/resultSet/DataBuildResultSet.java new file mode 100644 index 00000000..e8709d92 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/resultSet/DataBuildResultSet.java @@ -0,0 +1,1111 @@ +package apijson.demo.resultSet; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.Date; +import java.sql.NClob; +import java.sql.Ref; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.RowId; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.List; +import java.util.Map; + +import com.alibaba.druid.util.jdbc.ResultSetMetaDataBase; + +/*** + * 数据生成ResultSet + * + */ +public class DataBuildResultSet implements ResultSet { + private int index = -1; + private List> rows; + private List current = null; + private List headers = null; + + private ResultSetMetaData metaData; + + public DataBuildResultSet(Statement statement, final List headers, final List> lines) { + this.rows = lines; + this.headers = headers; + metaData = new DataBuildResultSetMetaDataBase(headers); + } + + @Override + public boolean next() throws SQLException { + boolean b; + int size = this.rows.size(); + if (size == 0) { + b = false; + } else { + this.current = null; + this.index++; + if (this.index > size) { + this.index = size; + } else if (this.index < size) { + this.current = this.rows.get(this.index); + } + + b = this.current != null; + } + return b; + } + + @Override + public void close() throws SQLException { + this.rows = null; + this.current = null; + this.headers = null; + this.metaData = null; + } + + @Override + public boolean wasNull() throws SQLException { + return false; + } + + @Override + public String getString(int columnIndex) throws SQLException { + return (String) current.get(columnIndex - 1); + } + + @Override + public boolean getBoolean(int columnIndex) throws SQLException { + return (Boolean) current.get(columnIndex - 1); + } + + @Override + public byte getByte(int columnIndex) throws SQLException { + return 0; + } + + @Override + public short getShort(int columnIndex) throws SQLException { + return ((Short) current.get(columnIndex - 1)); + } + + @Override + public int getInt(int columnIndex) throws SQLException { + return ((Integer) current.get(columnIndex - 1)); + } + + @Override + public long getLong(int columnIndex) throws SQLException { + return (Long) current.get(columnIndex - 1); + } + + @Override + public float getFloat(int columnIndex) throws SQLException { + return (Float) current.get(columnIndex - 1); + } + + @Override + public double getDouble(int columnIndex) throws SQLException { + return (Double) current.get(columnIndex - 1); + } + + @Override + public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { + return null; + } + + @Override + public byte[] getBytes(int columnIndex) throws SQLException { + return new byte[0]; + } + + @Override + public Date getDate(int columnIndex) throws SQLException { + return (Date) current.get(columnIndex - 1); + } + + @Override + public Time getTime(int columnIndex) throws SQLException { + return (Time) current.get(columnIndex - 1); + } + + @Override + public Timestamp getTimestamp(int columnIndex) throws SQLException { + return (Timestamp) current.get(columnIndex - 1); + } + + @Override + public InputStream getAsciiStream(int columnIndex) throws SQLException { + return null; + } + + @Override + public InputStream getUnicodeStream(int columnIndex) throws SQLException { + return null; + } + + @Override + public InputStream getBinaryStream(int columnIndex) throws SQLException { + return null; + } + + @Override + public String getString(String columnLabel) throws SQLException { + return (String) current.get(headers.indexOf(columnLabel)); + } + + @Override + public boolean getBoolean(String columnLabel) throws SQLException { + return (Boolean) current.get(headers.indexOf(columnLabel)); + } + + @Override + public byte getByte(String columnLabel) throws SQLException { + return 0; + } + + @Override + public short getShort(String columnLabel) throws SQLException { + return ((Short) current.get(headers.indexOf(columnLabel))); + } + + @Override + public int getInt(String columnLabel) throws SQLException { + return (Integer) current.get(headers.indexOf(columnLabel)); + } + + @Override + public long getLong(String columnLabel) throws SQLException { + return (Long) current.get(headers.indexOf(columnLabel)); + } + + @Override + public float getFloat(String columnLabel) throws SQLException { + return (Float) current.get(headers.indexOf(columnLabel)); + } + + @Override + public double getDouble(String columnLabel) throws SQLException { + return (Double) current.get(headers.indexOf(columnLabel)); + } + + @Override + public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { + return null; + } + + @Override + public byte[] getBytes(String columnLabel) throws SQLException { + return new byte[0]; + } + + @Override + public Date getDate(String columnLabel) throws SQLException { + return (Date) current.get(headers.indexOf(columnLabel)); + } + + @Override + public Time getTime(String columnLabel) throws SQLException { + return (Time) current.get(headers.indexOf(columnLabel)); + } + + @Override + public Timestamp getTimestamp(String columnLabel) throws SQLException { + return (Timestamp) current.get(headers.indexOf(columnLabel)); + } + + @Override + public InputStream getAsciiStream(String columnLabel) throws SQLException { + return null; + } + + @Override + public InputStream getUnicodeStream(String columnLabel) throws SQLException { + return null; + } + + @Override + public InputStream getBinaryStream(String columnLabel) throws SQLException { + return null; + } + + @Override + public SQLWarning getWarnings() throws SQLException { + return null; + } + + @Override + public void clearWarnings() throws SQLException { + + } + + @Override + public String getCursorName() throws SQLException { + return null; + } + + @Override + public ResultSetMetaData getMetaData() throws SQLException { + return metaData; + } + + @Override + public Object getObject(int columnIndex) throws SQLException { + return current.get(columnIndex - 1); + + } + + @Override + public Object getObject(String columnLabel) throws SQLException { + return current.get(headers.indexOf(columnLabel)); + } + + @Override + public int findColumn(String columnLabel) throws SQLException { + return ((ResultSetMetaDataBase) metaData).findColumn(columnLabel); + } + + @Override + public Reader getCharacterStream(int columnIndex) throws SQLException { + return null; + } + + @Override + public Reader getCharacterStream(String columnLabel) throws SQLException { + return null; + } + + @Override + public BigDecimal getBigDecimal(int columnIndex) throws SQLException { + return null; + } + + @Override + public BigDecimal getBigDecimal(String columnLabel) throws SQLException { + return null; + } + + @Override + public boolean isBeforeFirst() throws SQLException { + return this.index == -1 && this.rows.size() != 0; + } + + @Override + public boolean isAfterLast() throws SQLException { + return this.index >= this.rows.size() && this.rows.size() != 0; + } + + @Override + public boolean isFirst() throws SQLException { + return this.index == 0; + } + + @Override + public boolean isLast() throws SQLException { + return this.rows.size() != 0 && (this.index == (this.rows.size() - 1)); + } + + @Override + public void beforeFirst() throws SQLException { + if (this.rows.size() == 0) { + return; + } + + this.index = -1; + this.current = null; + } + + @Override + public void afterLast() throws SQLException { + if (this.rows.size() != 0) { + this.index = this.rows.size(); + this.current = null; + } + } + + @Override + public boolean first() throws SQLException { + boolean b = true; + if (this.rows.isEmpty()) { + b = false; + } else { + this.index = 0; + this.current = this.rows.get(this.index); + } + + return b; + } + + @Override + public boolean last() throws SQLException { + boolean b = true; + int size = this.rows.size(); + if (size == 0) { + b = false; + } else { + this.index = size - 1; + this.current = this.rows.get(this.index); + } + + return b; + } + + @Override + public int getRow() throws SQLException { + return (this.index < 0) || isAfterLast() || this.rows.isEmpty() ? 0 : this.index + 1; + } + + @Override + public boolean absolute(int row) throws SQLException { + boolean b; + int size = this.rows.size(); + if (size == 0) { + b = false; + } else { + if (row == 0) { + beforeFirst(); + b = false; + } else if (row == 1) { + b = first(); + } else if (row == -1) { + b = last(); + } else if (row > size) { + afterLast(); + b = false; + } else { + if (row < 0) { + int newRowPosition = size + row + 1; + if (newRowPosition <= 0) { + beforeFirst(); + b = false; + } else { + b = absolute(newRowPosition); + } + } else { + row--; + this.index = row; + this.current = (row < 0) || (row >= size) ? null : this.rows.get(row); + + b = true; + } + } + } + + return b; + } + + @Override + public boolean relative(int rows) throws SQLException { + int size = this.rows.size(); + if (size == 0) { + return false; + } + + this.index += rows; + if (this.index < -1) { + this.index = -1; + } else if (this.index > size) { + this.index = size; + } + + this.current = (this.index < 0) || (this.index >= size) ? null : this.rows.get(this.index); + + return !isAfterLast() && !isBeforeFirst(); + } + + @Override + public boolean previous() throws SQLException { + int rowIndex = this.index; + boolean b; + + if ((rowIndex - 1) >= 0) { + rowIndex--; + this.index = rowIndex; + this.current = (rowIndex < 0) || (rowIndex >= this.rows.size()) ? null : (this.rows.get(rowIndex)); + + b = true; + } else if ((rowIndex - 1) == -1) { + rowIndex--; + this.index = rowIndex; + this.current = null; + + b = false; + } else { + b = false; + } + + return b; + } + + @Override + public void setFetchDirection(int direction) throws SQLException { + + } + + @Override + public int getFetchDirection() throws SQLException { + return 0; + } + + @Override + public void setFetchSize(int rows) throws SQLException { + + } + + @Override + public int getFetchSize() throws SQLException { + return 0; + } + + @Override + public int getType() throws SQLException { + return 0; + } + + @Override + public int getConcurrency() throws SQLException { + return 0; + } + + @Override + public boolean rowUpdated() throws SQLException { + return false; + } + + @Override + public boolean rowInserted() throws SQLException { + return false; + } + + @Override + public boolean rowDeleted() throws SQLException { + return false; + } + + @Override + public void updateNull(int columnIndex) throws SQLException { + + } + + @Override + public void updateBoolean(int columnIndex, boolean x) throws SQLException { + + } + + @Override + public void updateByte(int columnIndex, byte x) throws SQLException { + + } + + @Override + public void updateShort(int columnIndex, short x) throws SQLException { + + } + + @Override + public void updateInt(int columnIndex, int x) throws SQLException { + + } + + @Override + public void updateLong(int columnIndex, long x) throws SQLException { + + } + + @Override + public void updateFloat(int columnIndex, float x) throws SQLException { + + } + + @Override + public void updateDouble(int columnIndex, double x) throws SQLException { + + } + + @Override + public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { + + } + + @Override + public void updateString(int columnIndex, String x) throws SQLException { + + } + + @Override + public void updateBytes(int columnIndex, byte[] x) throws SQLException { + + } + + @Override + public void updateDate(int columnIndex, Date x) throws SQLException { + + } + + @Override + public void updateTime(int columnIndex, Time x) throws SQLException { + + } + + @Override + public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { + + } + + @Override + public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { + + } + + @Override + public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { + + } + + @Override + public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { + + } + + @Override + public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { + + } + + @Override + public void updateObject(int columnIndex, Object x) throws SQLException { + throw new RuntimeException("update is not support yet"); + } + + @Override + public void updateNull(String columnLabel) throws SQLException { + + } + + @Override + public void updateBoolean(String columnLabel, boolean x) throws SQLException { + + } + + @Override + public void updateByte(String columnLabel, byte x) throws SQLException { + + } + + @Override + public void updateShort(String columnLabel, short x) throws SQLException { + + } + + @Override + public void updateInt(String columnLabel, int x) throws SQLException { + + } + + @Override + public void updateLong(String columnLabel, long x) throws SQLException { + + } + + @Override + public void updateFloat(String columnLabel, float x) throws SQLException { + + } + + @Override + public void updateDouble(String columnLabel, double x) throws SQLException { + + } + + @Override + public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { + + } + + @Override + public void updateString(String columnLabel, String x) throws SQLException { + + } + + @Override + public void updateBytes(String columnLabel, byte[] x) throws SQLException { + + } + + @Override + public void updateDate(String columnLabel, Date x) throws SQLException { + + } + + @Override + public void updateTime(String columnLabel, Time x) throws SQLException { + + } + + @Override + public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { + + } + + @Override + public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { + + } + + @Override + public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException { + + } + + @Override + public void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException { + + } + + @Override + public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { + + } + + @Override + public void updateObject(String columnLabel, Object x) throws SQLException { + + } + + @Override + public void insertRow() throws SQLException { + + } + + @Override + public void updateRow() throws SQLException { + + } + + @Override + public void deleteRow() throws SQLException { + + } + + @Override + public void refreshRow() throws SQLException { + + } + + @Override + public void cancelRowUpdates() throws SQLException { + + } + + @Override + public void moveToInsertRow() throws SQLException { + + } + + @Override + public void moveToCurrentRow() throws SQLException { + + } + + @Override + public Statement getStatement() throws SQLException { + return null; + } + + @Override + public Object getObject(int columnIndex, Map> map) throws SQLException { + return null; + } + + @Override + public Ref getRef(int columnIndex) throws SQLException { + return null; + } + + @Override + public Blob getBlob(int columnIndex) throws SQLException { + return null; + } + + @Override + public Clob getClob(int columnIndex) throws SQLException { + return null; + } + + @Override + public Array getArray(int columnIndex) throws SQLException { + return null; + } + + @Override + public Object getObject(String columnLabel, Map> map) throws SQLException { + return null; + } + + @Override + public Ref getRef(String columnLabel) throws SQLException { + return null; + } + + @Override + public Blob getBlob(String columnLabel) throws SQLException { + return null; + } + + @Override + public Clob getClob(String columnLabel) throws SQLException { + return null; + } + + @Override + public Array getArray(String columnLabel) throws SQLException { + return null; + } + + @Override + public Date getDate(int columnIndex, Calendar cal) throws SQLException { + return null; + } + + @Override + public Date getDate(String columnLabel, Calendar cal) throws SQLException { + return null; + } + + @Override + public Time getTime(int columnIndex, Calendar cal) throws SQLException { + return null; + } + + @Override + public Time getTime(String columnLabel, Calendar cal) throws SQLException { + return null; + } + + @Override + public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { + return null; + } + + @Override + public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException { + return null; + } + + @Override + public URL getURL(int columnIndex) throws SQLException { + return null; + } + + @Override + public URL getURL(String columnLabel) throws SQLException { + return null; + } + + @Override + public void updateRef(int columnIndex, Ref x) throws SQLException { + + } + + @Override + public void updateRef(String columnLabel, Ref x) throws SQLException { + + } + + @Override + public void updateBlob(int columnIndex, Blob x) throws SQLException { + + } + + @Override + public void updateBlob(String columnLabel, Blob x) throws SQLException { + + } + + @Override + public void updateClob(int columnIndex, Clob x) throws SQLException { + + } + + @Override + public void updateClob(String columnLabel, Clob x) throws SQLException { + + } + + @Override + public void updateArray(int columnIndex, Array x) throws SQLException { + + } + + @Override + public void updateArray(String columnLabel, Array x) throws SQLException { + + } + + @Override + public RowId getRowId(int columnIndex) throws SQLException { + return null; + } + + @Override + public RowId getRowId(String columnLabel) throws SQLException { + return null; + } + + @Override + public void updateRowId(int columnIndex, RowId x) throws SQLException { + + } + + @Override + public void updateRowId(String columnLabel, RowId x) throws SQLException { + + } + + @Override + public int getHoldability() throws SQLException { + return 0; + } + + @Override + public boolean isClosed() throws SQLException { + return false; + } + + @Override + public void updateNString(int columnIndex, String nString) throws SQLException { + + } + + @Override + public void updateNString(String columnLabel, String nString) throws SQLException { + + } + + @Override + public void updateNClob(int columnIndex, NClob nClob) throws SQLException { + + } + + @Override + public void updateNClob(String columnLabel, NClob nClob) throws SQLException { + + } + + @Override + public NClob getNClob(int columnIndex) throws SQLException { + return null; + } + + @Override + public NClob getNClob(String columnLabel) throws SQLException { + return null; + } + + @Override + public SQLXML getSQLXML(int columnIndex) throws SQLException { + return null; + } + + @Override + public SQLXML getSQLXML(String columnLabel) throws SQLException { + return null; + } + + @Override + public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { + + } + + @Override + public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { + + } + + @Override + public String getNString(int columnIndex) throws SQLException { + return null; + } + + @Override + public String getNString(String columnLabel) throws SQLException { + return null; + } + + @Override + public Reader getNCharacterStream(int columnIndex) throws SQLException { + return null; + } + + @Override + public Reader getNCharacterStream(String columnLabel) throws SQLException { + return null; + } + + @Override + public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + + } + + @Override + public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { + + } + + @Override + public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { + + } + + @Override + public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { + + } + + @Override + public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + + } + + @Override + public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException { + + } + + @Override + public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException { + + } + + @Override + public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { + + } + + @Override + public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException { + + } + + @Override + public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException { + + } + + @Override + public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { + + } + + @Override + public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { + + } + + @Override + public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { + + } + + @Override + public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { + + } + + @Override + public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { + + } + + @Override + public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { + + } + + @Override + public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { + + } + + @Override + public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { + + } + + @Override + public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { + + } + + @Override + public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { + + } + + @Override + public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { + + } + + @Override + public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { + + } + + @Override + public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { + + } + + @Override + public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { + + } + + @Override + public void updateClob(int columnIndex, Reader reader) throws SQLException { + + } + + @Override + public void updateClob(String columnLabel, Reader reader) throws SQLException { + + } + + @Override + public void updateNClob(int columnIndex, Reader reader) throws SQLException { + + } + + @Override + public void updateNClob(String columnLabel, Reader reader) throws SQLException { + + } + + @Override + public T getObject(int columnIndex, Class type) throws SQLException { + return null; + } + + @Override + public T getObject(String columnLabel, Class type) throws SQLException { + return null; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/resultSet/DataBuildResultSetMetaDataBase.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/resultSet/DataBuildResultSetMetaDataBase.java new file mode 100644 index 00000000..cf5266ee --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/apijson/demo/resultSet/DataBuildResultSetMetaDataBase.java @@ -0,0 +1,19 @@ +package apijson.demo.resultSet; + +import com.alibaba.druid.util.jdbc.ResultSetMetaDataBase; + +import java.util.List; + +public class DataBuildResultSetMetaDataBase extends ResultSetMetaDataBase { + + public DataBuildResultSetMetaDataBase(List headers) { + ColumnMetaData columnMetaData; + for (String column : headers) { + columnMetaData = new ColumnMetaData(); + columnMetaData.setColumnLabel(column); + columnMetaData.setColumnName(column); + getColumns().add(columnMetaData); + } + } + +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/NoDoneReply.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/NoDoneReply.java new file mode 100644 index 00000000..e62ffdc5 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/NoDoneReply.java @@ -0,0 +1,4 @@ +package com.redbeardlab.redisql.client; + +public class NoDoneReply extends Throwable { +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/ParseRediSQLReply.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/ParseRediSQLReply.java new file mode 100644 index 00000000..505e56cb --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/ParseRediSQLReply.java @@ -0,0 +1,42 @@ +package com.redbeardlab.redisql.client; + +import java.util.List; + +public class ParseRediSQLReply { + public static boolean done_reply(List reply) { + if (reply.size() != 2) { return false; } + if ((reply.get(0) instanceof byte[]) && (new String((byte[])reply.get(0)).equals("DONE"))) { + return (reply.get(1) instanceof Long); + } + return false; + } + + public static Long how_many_done(List reply) { + if (reply == null || reply.size() == 0 ||done_reply(reply) == false) { + return 0L; + } + return (Long)reply.get(1); + } + + public static boolean is_integer(Object o) { + return (o instanceof Long); + } + + public static Long get_integer(Object o) { + return (Long) o; + } + + public static boolean is_string(Object o) { + return (o instanceof byte[]); + } + + public static String get_string(Object o) { + return new String((byte[])o); + } + + public static boolean is_list(Object o) { + return (o instanceof List); + } + + +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/RediSQLClient.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/RediSQLClient.java new file mode 100644 index 00000000..714f1257 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/RediSQLClient.java @@ -0,0 +1,196 @@ +package com.redbeardlab.redisql.client; + +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.JedisShardInfo; +import redis.clients.jedis.commands.ProtocolCommand; +import redis.clients.jedis.util.SafeEncoder; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocketFactory; +import java.lang.reflect.Array; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +public class RediSQLClient extends redis.clients.jedis.Jedis { + + public RediSQLClient() { super(); } + public RediSQLClient(final String host) { super(host); } + public RediSQLClient(final HostAndPort hp) { super(hp); } + + public RediSQLClient(String host, int port) { + super(host, port); + } + + public RediSQLClient(String host, int port, boolean ssl) { + super(host, port, ssl); + } + + public RediSQLClient(String host, int port, boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, HostnameVerifier hostnameVerifier) { + super(host, port, ssl, sslSocketFactory, sslParameters, hostnameVerifier); + } + + public RediSQLClient(String host, int port, int timeout) { + super(host, port, timeout); + } + + public RediSQLClient(String host, int port, int timeout, boolean ssl) { + super(host, port, timeout, ssl); + } + + public RediSQLClient(String host, int port, int timeout, boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, HostnameVerifier hostnameVerifier) { + super(host, port, timeout, ssl, sslSocketFactory, sslParameters, hostnameVerifier); + } + + public RediSQLClient(String host, int port, int connectionTimeout, int soTimeout) { + super(host, port, connectionTimeout, soTimeout); + } + + public RediSQLClient(String host, int port, int connectionTimeout, int soTimeout, boolean ssl) { + super(host, port, connectionTimeout, soTimeout, ssl); + } + + public RediSQLClient(String host, int port, int connectionTimeout, int soTimeout, boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, HostnameVerifier hostnameVerifier) { + super(host, port, connectionTimeout, soTimeout, ssl, sslSocketFactory, sslParameters, hostnameVerifier); + } + + public RediSQLClient(JedisShardInfo shardInfo) { + super(shardInfo); + } + + public RediSQLClient(URI uri) { + super(uri); + } + + public RediSQLClient(URI uri, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, HostnameVerifier hostnameVerifier) { + super(uri, sslSocketFactory, sslParameters, hostnameVerifier); + } + + public RediSQLClient(URI uri, int timeout) { + super(uri, timeout); + } + + public RediSQLClient(URI uri, int timeout, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, HostnameVerifier hostnameVerifier) { + super(uri, timeout, sslSocketFactory, sslParameters, hostnameVerifier); + } + + public RediSQLClient(URI uri, int connectionTimeout, int soTimeout) { + super(uri, connectionTimeout, soTimeout); + } + + public RediSQLClient(URI uri, int connectionTimeout, int soTimeout, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, HostnameVerifier hostnameVerifier) { + super(uri, connectionTimeout, soTimeout, sslSocketFactory, sslParameters, hostnameVerifier); + } + + + private String ok_returns(RediSQLCommand.ModuleCommand cmd, String... args) { + client.sendCommand(cmd, args); + return client.getBulkReply(); + } + + private List list_returns(RediSQLCommand.ModuleCommand cmd, String... args) { + client.sendCommand(cmd, args); + return client.getObjectMultiBulkReply(); + } + + public String create_db(String db) { + return ok_returns(RediSQLCommand.ModuleCommand.CREATE_DB, db); + } + + public String create_db(String db, String file_path) { + return ok_returns(RediSQLCommand.ModuleCommand.CREATE_DB, db, file_path); + } + + public List exec(String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.EXEC, db, query); + } + + public List exec_now(String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.EXEC_NOW, db, query); + } + + public List query(String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY, db, query); + } + + public List query_now(String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_NOW, db, query); + } + + public List query_into(String stream, String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_INTO, stream, db, query); + } + + public List query_into_now(String stream, String db, String query) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_INTO_NOW, stream, db, query); + } + + public String create_statement(String db, String stmt_name, String stmt_query) { + return ok_returns(RediSQLCommand.ModuleCommand.CREATE_STATEMENT, db, stmt_name, stmt_query); + } + + public String create_statement_now(String db, String stmt_name, String stmt_query) { + return ok_returns(RediSQLCommand.ModuleCommand.CREATE_STATEMENT_NOW, db, stmt_name, stmt_query); + } + + public List exec_statement(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.EXEC_STATEMENT, args); + } + + public List exec_statement_now(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.EXEC_STATEMENT_NOW, args); + } + + public List query_statement(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_STATEMENT, args); + } + + public List query_statement_now(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_STATEMENT_NOW, args); + } + + public List query_statement_into(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_STATEMENT_INTO, args); + } + + public List query_statement_into_now(String... args) { + return list_returns(RediSQLCommand.ModuleCommand.QUERY_STATEMENT_INTO_NOW, args); + } + + public String delete_statement(String db, String stmt_name) { + return ok_returns(RediSQLCommand.ModuleCommand.DELETE_STATEMENT, db, stmt_name); + } + + public String delete_statement_now(String db, String stmt_name) { + return ok_returns(RediSQLCommand.ModuleCommand.DELETE_STATEMENT_NOW, db, stmt_name); + } + + public String update_statement(String db, String stmt_name, String stmt_query) { + return ok_returns(RediSQLCommand.ModuleCommand.UPDATE_STATEMENT, db, stmt_name, stmt_query); + } + + public String update_statement_now(String db, String stmt_name, String stmt_query) { + return ok_returns(RediSQLCommand.ModuleCommand.UPDATE_STATEMENT_NOW, db, stmt_name, stmt_query); + } + + public String copy(String db1, String db2) { + return ok_returns(RediSQLCommand.ModuleCommand.COPY, db1, db2); + } + + public String copy_now(String db1, String db2) { + return ok_returns(RediSQLCommand.ModuleCommand.COPY_NOW, db1, db2); + } + + public List statistics() { + return list_returns(RediSQLCommand.ModuleCommand.STATISTICS); + } + + public String version(String db1, String db2) { + return ok_returns(RediSQLCommand.ModuleCommand.VERSION); + } + + + +} + diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/RediSQLCommand.java b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/RediSQLCommand.java new file mode 100644 index 00000000..8b7ff833 --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/java/com/redbeardlab/redisql/client/RediSQLCommand.java @@ -0,0 +1,42 @@ +package com.redbeardlab.redisql.client; + +import redis.clients.jedis.commands.ProtocolCommand; +import redis.clients.jedis.util.SafeEncoder; + +public class RediSQLCommand { + public enum ModuleCommand implements ProtocolCommand { + CREATE_DB("REDISQL.CREATE_DB"), + EXEC("REDISQL.EXEC"), + EXEC_NOW("REDISQL.EXEC.NOW"), + QUERY("REDISQL.QUERY"), + QUERY_NOW("REDISQL.QUERY.NOW"), + QUERY_INTO("REDISQL.QUERY.INTO"), + QUERY_INTO_NOW("REDISQL.QUERY.INTO.NOW"), + CREATE_STATEMENT("REDISQL.CREATE_STATEMENT"), + CREATE_STATEMENT_NOW("REDISQL.CREATE_STATEMENT.NOW"), + EXEC_STATEMENT("REDISQL.EXEC_STATEMENT"), + EXEC_STATEMENT_NOW("REDISQL.EXEC_STATEMENT.NOW"), + QUERY_STATEMENT("REDISQL.QUERY_STATEMENT"), + QUERY_STATEMENT_NOW("REDISQL.QUERY_STATEMENT.NOW"), + QUERY_STATEMENT_INTO("REDISQL.QUERY_STATEMENT.INTO"), + QUERY_STATEMENT_INTO_NOW("REDISQL.QUERY_STATEMENT.INTO.NOW"), + DELETE_STATEMENT("REDISQL.DELETE_STATEMENT"), + DELETE_STATEMENT_NOW("REDISQL.DELETE_STATEMENT.NOW"), + UPDATE_STATEMENT("REDISQL.UPDATE_STATEMENT"), + UPDATE_STATEMENT_NOW("REDISQL.UPDATE_STATEMENT.NOW"), + COPY("REDISQL.COPY"), + COPY_NOW("REDISQ.COPY.NOW"), + STATISTICS("REDISQL.STATISTICS"), + VERSION("REDISQL.VERSION"); + + private final byte[] raw; + + ModuleCommand(String command) { + raw = SafeEncoder.encode(command); + } + + public byte[] getRaw() { + return raw; + } + } +} diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/resources/application.yml b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/resources/application.yml new file mode 100644 index 00000000..7d5a68ee --- /dev/null +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/src/main/resources/application.yml @@ -0,0 +1,35 @@ +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + dynamic: + primary: master + strict: true + druid: + initial-size: 5 + min-idle: 5 + maxActive: 2000 + maxWait: 60000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + poolPreparedStatements: true + maxPoolPreparedStatementPerConnectionSize: 20 + filters: stat,slf4j + connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000 + datasource: + master: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/xxxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&useSSL=false + username: + password: + filter: + stat: + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: false + wall: + config: + multi-statement-allow: true From 7fa71c0ae3111173d817fbc872dad4700ab8a22e Mon Sep 17 00:00:00 2001 From: cloudAndMonkey Date: Fri, 17 Feb 2023 18:06:15 +0800 Subject: [PATCH 2/3] Update README.md --- .../README.md | 159 +++++++++++++++--- 1 file changed, 131 insertions(+), 28 deletions(-) diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md index 82218340..82db83dd 100644 --- a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md @@ -1,48 +1,151 @@ # APIJSONDemo -## 支持多数据源-消息队列 +## 支持多数据源-rediSQL -示例:kafka +redis table 表名规范: REDIS_TABLE_*
+开发人员可自行控制
+JedisBuildData
+public static final String REDIS_TABLE_KEY = "REDIS_TABLE_"; // rediSql table prefix
-原理说明: +Access、Request配置 访问操作权限
-Access表名 = 消息队列 topic +rediSQL安装使用
+https://github.com/RedBeardLab/rediSQL -Access表配置说明: -![image](https://user-images.githubusercontent.com/12228225/210956299-204115a7-433c-4f18-af27-5120068dab2e.png) -Request表配置post权限 -![image](https://user-images.githubusercontent.com/12228225/210956378-be095589-0ced-4317-bb46-6b296538f26e.png) +官方docker安装
+docker pull dalongrong/redisql +docker run -itd --name redisql -p 6399:6379 dalongrong/redisql -apijson发送mq消息: -单条
+rediSQL注意事项
+rediSQL免费版有后遥控制,每个小时会发送 redist info 统计信息
+image + +可以配host ,弄一个nginx 本地代理 解决,或者 项目自己重新打包
+ +rediSQL java:
+https://github.com/RedBeardLab/JRediSQL
+https://www.youtube.com/watch?v=YRusC-AIq_g + +rediSQL 创建数据库表命令
+``` +REDISQL.EXEC DB "CREATE TABLE REDIS_TABLE_A(id TEXT, A INT, B TEXT, C TEXT, userId TEXT);" + +REDISQL.EXEC DB "INSERT INTO REDIS_TABLE_A(id,A,B,C,userId) VALUES('1', 3, '1c', 'bar','1');" + + +REDISQL.EXEC DB "SELECT * FROM REDIS_TABLE_A;" + +REDISQL.EXEC DB "drop table REDIS_TABLE_A;" +``` + +测试用例
+``` { - "@datasource": "kafka", - "Topic_User":{ - "message":"test-101" + "@datasource": "redisCluster", + "REDIS_TABLE_A":{ + "A": 1, + "B": "B", + "C": "C" }, - "tag": "Topic_User", - "@explain": false -}
-多条
+ "tag": "REDIS_TABLE_A", + "@explain": true, + "format": true +} + { - "Topic_User[]": [ + "REDIS_TABLE_A[]": [ + { + "A": 5, + "B": "5B", + "C": "5C" + }, { - "message":"test-100" + "A": 6, + "B": "6B", + "C": "6C" }, { - "message":"test-101" + "A": 7, + "B": "7B", + "C": "7C" } ], - "tag": "Topic_User[]", - "@datasource": "kafka", - "@explain": true + "tag": "REDIS_TABLE_A[]", + "@datasource": "redisCluster", + "@explain": true, + "format": true +} + +{ + "@datasource": "redisCluster", + "REDIS_TABLE_A": { + "id": "f2621698-99fa-4698-9fb0-8c7b585da403", + "A": 1, + "B": "1B" + }, + "tag": "REDIS_TABLE_A", + "@explain": true, + "format": true +} + +Request 表配置 +{"REDIS_TABLE_A[]": [{"MUST": "A,B", "REFUSE": "id"}], "INSERT": {"@role": "OWNER,ADMIN","@combine": "A | B"}} + +{ + "@datasource": "redisCluster", + "REDIS_TABLE_A": { + "A": 1, + "B": "1B", + "C": "1-1-1C" + }, + "tag": "REDIS_TABLE_A", + "@explain": true, + "format": true } -客户端接收消息: +{ + "@datasource": "redisCluster", + "REDIS_TABLE_A:a": { + "@column":"a,b,c", + "b$": "7B%" + }, + "@explain": true, + "format": true +} -offset = 47, key = null, value = test-101
-offset = 48, key = null, value = test-100
-offset = 49, key = null, value = test-101
+{ + "@datasource": "redisCluster", + "REDIS_TABLE_A:a[]": { + "REDIS_TABLE_A": { + "@column":"a,b,c" + //"b$": "1%" + }, + "page":0, + "count":3, + "query": 2 + }, + "total@": "/REDIS_TABLE_A:a[]/total", + "@explain": true, + "format": true +} +{ + "@datasource": "redisCluster", + "REDIS_TABLE_A": { + "id": "f2621698-99fa-4698-9fb0-8c7b585da403" + }, + "tag": "REDIS_TABLE_A", + "@explain": true, + "format": true +} -用java代码方式,获取具体数据源,调用即可 +{ + "@datasource": "redisCluster", + "REDIS_TABLE_A:a": { + "id{}": ["1","eb3dd7c9-bab6-410c-b70a-cbbc3bd12896", "c83b3cfa-034e-4a9e-b2cf-83520db1ce05"] + }, + "tag": "REDIS_TABLE_A[]", + "@explain": true, + "format": true +} +``` From 4d506978ce61d9358fcfd1253120525b7cbed115 Mon Sep 17 00:00:00 2001 From: cloudAndMonkey Date: Fri, 17 Feb 2023 18:09:33 +0800 Subject: [PATCH 3/3] Update README.md --- .../APIJSONDemo-MultiDataSource-RediSQL/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md index 82db83dd..a11a3834 100644 --- a/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md +++ b/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-RediSQL/README.md @@ -26,6 +26,9 @@ rediSQL java:
https://github.com/RedBeardLab/JRediSQL
https://www.youtube.com/watch?v=YRusC-AIq_g +本示例 用 redis cluster rediSQL, 具体redis集群模式, 开发人员自行控制
+将 libredis_sql.so 导入redis.config
+--loadmodule /etc/redis/libredis_sql.so
rediSQL 创建数据库表命令
``` REDISQL.EXEC DB "CREATE TABLE REDIS_TABLE_A(id TEXT, A INT, B TEXT, C TEXT, userId TEXT);"