From e413f6d51d392913c88900029eb7c56592b7ddc1 Mon Sep 17 00:00:00 2001 From: Redkale Date: Thu, 17 Mar 2022 17:38:59 +0800 Subject: [PATCH] --- source.html | 180 +++++++++++++++++++++++++--------------------------- 1 file changed, 87 insertions(+), 93 deletions(-) diff --git a/source.html b/source.html index a80e5ff8b..53b651e15 100644 --- a/source.html +++ b/source.html @@ -35,9 +35,8 @@                  2、简化分表分库操作。
                 3、通过watch组件动态更改数据库连接参数。
                 4、读写分离的简易配置。
-                  5、进程间的缓存同步。
-                  6、提供异步接口。
-         数据库操作方面常见的是过滤查询操作,JPA规范中的JPQL虽然简化了SQL,但是对于动态产生的过滤条件,开发人员还是无法免去组装过滤条件的过程(无论JPQL还是CriteriaQuery), DataSource定义了FilterBean接口可以省略组装条件的过程,FilterNode提供了类似CriteriaQuery的功能,且这两种对象都可以序列化,给远程模式Service提供了基础,微服务架构提倡服务之间尽量降低耦合,因此DataSource仅支持简单的关联查询,复杂的表关联查询或统计应放在数据分析系统中。一个服务通常部署多个进程,若用JPA的缓存则进程之间的缓存无法同步,而DataSource采用SNCP协议即可方便地达到自动同步缓存功能。JPA无法在主数据库异常时动态切换到备份数据库,persistence.xml文件更改后已运行中的进程不会自动切换,需要开启watch组件通过watch动态更改正在运行进程中的配置。
+                  5、提供异步接口。
+         数据库操作方面常见的是过滤查询操作,JPA规范中的JPQL虽然简化了SQL,但是对于动态产生的过滤条件,开发人员还是无法免去组装过滤条件的过程(无论JPQL还是CriteriaQuery), DataSource定义了FilterBean接口可以省略组装条件的过程,FilterNode提供了类似CriteriaQuery的功能,且这两种对象都可以序列化,给远程模式Service提供了基础,微服务架构提倡服务之间尽量降低耦合,因此DataSource仅支持简单的关联查询,复杂的表关联查询或统计应放在数据分析系统中。一个服务通常部署多个进程,若用JPA的缓存则进程之间的缓存无法同步,而DataSource采用SNCP协议即可方便地达到自动同步缓存功能。JPA无法在主数据库异常时动态切换到备份数据库,source.properties文件更改后已运行中的进程不会自动切换,需要开启watch组件通过watch动态更改正在运行进程中的配置。
        为了降低学习成本,DataSource重用了JPA里的部分注解与配置文件,使用方法基本相同,与JPA用法的区别是注解只能标记于字段,不能标记在方法上。

@@ -75,7 +74,7 @@

        以上接口除了directXXX,其他都有等同的异步接口。insert、delete、update接口与JPA同名接口用法一样。DataSource提供了丰富的查询接口,且有独特的翻页查询功能。每以系列的方法主要重载三类: 单个字段过滤、FilterBean过滤和FilterNode过滤。
        返回类型为CompletableFuture的接口均为异步接口
-         开发者可以借鉴 Redkale-demo 中的 AutoClassCreator的代码根据数据表自动生成Entity代码。 +         开发者可以借鉴 Redkale-demo 中的 AutoClassCreator的代码根据数据表自动生成Entity代码。

    过滤条件

        FilterBean、FilterNode对象用于构造过滤条件。FilterBean可以转化为FilterNode。FilterBean主要用于接收外界构建的过滤条件,而FilterNode为了构建内部的过滤条件且降低过滤条件变化的耦合性,FilterNode中name值以#开头的视为虚拟字段,不会构建成过滤条件,仅供分布分库的DistributeTableStrategy策略使用。

@@ -84,13 +83,13 @@ privateintuserid;@FilterColumn(express=FilterExpress.LIKE) - privateStringusername; + privateStringuserName;privateRangeage; - publicUserBean(intuserid,Stringusername,Rangeage){ + publicUserBean(intuserid,StringuserName,Rangeage){this.userid=userid; - this.username=username; + this.userName=userName;this.age=age;} @@ -101,11 +100,11 @@ newUserBean(200001,"redkale",newIntRange(14,36))等价于 - FilterNode.create("userid",200001).and("username",FilterExpress.LIKE,"redkale").and("age",newRange.IntRange(14,36)) + FilterNode.create("userid",200001).and("userName",FilterExpress.LIKE,"redkale").and("age",newRange.IntRange(14,36)) - newUserBean(200001,"redkale",newIntRange(14,36))等价于"WHERE userid=200001 AND username LIKE '%redkale%' AND age BETWEEN 14 AND 36" - newUserBean(200001,"redkale",null)等价于"WHERE userid = 200001 AND username LIKE '%redkale%'" - newUserBean(0,"redkale",null)等价于"WHERE username LIKE '%redkale%'" + newUserBean(200001,"redkale",newIntRange(14,36))等价于"WHERE userid=200001 AND userName LIKE '%redkale%' AND age BETWEEN 14 AND 36" + newUserBean(200001,"redkale",null)等价于"WHERE userid = 200001 AND userName LIKE '%redkale%'" + newUserBean(0,"redkale",null)等价于"WHERE userName LIKE '%redkale%'"

        如上定义UserBean过滤条件,当非数值类字段值为null、字符串值为空、数值类字段值小于@FilterColumn.least()值(least的默认值为1)都不会构建成过滤条件。@FilterColumn.express根据字段的类型有不同的默认值,若字段类型为Collection子类或数组则express默认为FilterExpress.IN;若字段类型为Range的子类则express默认为FilterExpress.BETWEEN;其他类型则express默认为FilterExpress.EQUAL。默认字段之间是AND关系,若想使用OR关系则需要使用@FilterGroup进行标记:

@@ -115,14 +114,14 @@ @FilterGroup("[OR]a")@FilterColumn(express=FilterExpress.LIKE) - privateStringusername; + privateStringuserName;@FilterGroup("[OR]a")privateRangeage; - publicUserBean(intuserid,Stringusername,Rangeage){ + publicUserBean(intuserid,StringuserName,Rangeage){this.userid=userid; - this.username=username; + this.userName=userName;this.age=age;} @@ -133,16 +132,16 @@ newUserBean(200001,"redkale",newIntRange(14,36))等价于 - FilterNodeorNode=FilterNode.create("username",FilterExpress.LIKE,"redkale").or("age",newRange.IntRange(14,36)); + FilterNodeorNode=FilterNode.create("userName",FilterExpress.LIKE,"redkale").or("age",newRange.IntRange(14,36));FilterNodenode=FilterNode.create("userid",200001).and(orNode); - newUserBean(200001,"redkale",newIntRange(14,36))等价于"WHERE userid=200001 AND (username LIKE '%redkale%' OR age BETWEEN 14 AND 36)" - newUserBean(200001,"redkale",null)等价于"WHERE userid = 200001 AND username LIKE '%redkale%'" - newUserBean(0,"redkale",null)等价于"WHERE username LIKE '%redkale%'" + newUserBean(200001,"redkale",newIntRange(14,36))等价于"WHERE userid=200001 AND (userName LIKE '%redkale%' OR age BETWEEN 14 AND 36)" + newUserBean(200001,"redkale",null)等价于"WHERE userid = 200001 AND userName LIKE '%redkale%'" + newUserBean(0,"redkale",null)等价于"WHERE userName LIKE '%redkale%'"source.getNumberResult(User.class,FilterFunc.COUNT,null,newUserBean(0,"redkale",newIntRange(14,36))).intValue()等价于 - "SELECT COUNT(*) FROM user WHERE username LIKE '%redkale%' AND age BETWEEN 14 AND 36" + "SELECT COUNT(*) FROM user WHERE userName LIKE '%redkale%' AND age BETWEEN 14 AND 36"

        如上@FilterGroup 的value 必须是[OR]或者[AND]开头,没有标记@FilterGroup的字段等价于标记了@FilterGroup(value = "[AND]")。[AND]、[OR]后面的字符串为GROUP_NAME,默认的GROUP_NAME为空字符串。如上"[OR]a"可以直接使用"[OR]",有多个[OR]或者[AND]则需要加上不同的NAME。

@@ -187,7 +186,7 @@ } -

        DistributeTableStrategy分表策略需要实现三个接口,模板表由实体类的@Table注解提供。Redkale默认实现的MySQL数据库的拷贝表结构语句,其他数据库类型需要通过指定persistence.xml 中的 javax.persistence.tablenotexist.sqlstatesjavax.persistence.tablecopy.sqltemplate 来配置。

+

        DistributeTableStrategy分表策略需要实现三个接口,模板表由实体类的@Table注解提供。Redkale默认实现的MySQL数据库的拷贝表结构语句,其他数据库类型需要通过指定source.properties 中的 tablenotexist-sqlstatestablecopy-sqltemplate 来配置。

@DistributeTable(strategy = LoginRecord.TableStrategy.class)
 public class LoginRecord extends BaseEntity {
 
@@ -199,22 +198,22 @@
     private long userid; //C端用户ID
 
     @Column(updatable = false, comment = "登录网络类型; wifi/4g/3g")
-    private String netmode = ""; //登录网络类型; wifi/4g/3g
+    private String netMode = ""; //登录网络类型; wifi/4g/3g
 
     @Column(updatable = false, comment = "APP版本信息")
-    private String appversion = ""; //APP版本信息
+    private String appVersion = ""; //APP版本信息
 
     @Column(updatable = false, comment = "APP操作系统信息")
     private String appos = ""; //APP操作系统信息
 
     @Column(updatable = false, comment = "登录时客户端信息")
-    private String loginagent = ""; //登录时客户端信息
+    private String loginAgent = ""; //登录时客户端信息
 
     @Column(updatable = false, comment = "登录时的IP")
-    private String loginaddr = ""; //登录时的IP
+    private String loginAddr = ""; //登录时的IP
 
     @Column(updatable = false, comment = "创建时间")
-    private long createtime; //创建时间
+    private long createTime; //创建时间
 
     /** 以下省略getter setter方法 */
 
@@ -223,7 +222,7 @@
     public static void main(String[] args) throws Throwable {
         LoginRecord record = new LoginRecord();
         long now = System.currentTimeMillis();
-        record.setCreatetime(now); //设置创建时间
+        record.setCreateTime(now); //设置创建时间
         record.setLoginid(Utility.format36time(now) + "-" + Utility.uuid());  //主键的生成规则
         //....  填充其他字段
         source.insert(record);
@@ -241,14 +240,14 @@
         public String getTable(String table, FilterNode node) {
             Serializable day = node.findValue("#day");  //LoginRecord没有day字段,所以前面要加#,表示虚拟字段, 值为yyyyMMdd格式
             if (day != null) getTable(table, (Integer) day, 0L); //存在#day参数则直接使用day值
-            Serializable time = node.findValue("createtime");  //存在createtime则使用最小时间,且createtime的范围必须在一天内,因为本表以天为单位建表
+            Serializable time = node.findValue("createTime");  //存在createTime则使用最小时间,且createTime的范围必须在一天内,因为本表以天为单位建表
             return getTable(table, 0, (time == null ? 0L : (time instanceof Range ? ((Range.LongRange) time).getMin() : (Long) time)));
         }
 
         //创建或单个查询时调用本方法
         @Override
         public String getTable(String table, LoginRecord bean) {
-            return getTable(table, 0, bean.getCreatetime());
+            return getTable(table, 0, bean.getCreateTime());
         }
 
         //根据主键ID查询单个记录时调用本方法
@@ -258,10 +257,10 @@
             return getTable(table, 0, Long.parseLong(id.substring(0, 9), 36));
         }
 
-        private String getTable(String table, int day, long createtime) { //day为0或yyyyMMdd格式数据
+        private String getTable(String table, int day, long createTime) { //day为0或yyyyMMdd格式数据
             int pos = table.indexOf('.');
-            String year = day > 0 ? String.valueOf(day / 10000) : String.format(yearformat, createtime); //没有day取createtime
-            return "platf_login_" + year + "." + table.substring(pos + 1) + "_" + (day > 0 ? day : String.format(dayformat, createtime));
+            String year = day > 0 ? String.valueOf(day / 10000) : String.format(yearformat, createTime); //没有day取createTime
+            return "platf_login_" + year + "." + table.substring(pos + 1) + "_" + (day > 0 ? day : String.format(dayformat, createTime));
         }
     }
 }
@@ -281,7 +280,7 @@
     private String loginid = ""; //LoginRecord主键
 
     @Column(updatable = false, comment = "创建时间")
-    private long createtime; //创建时间
+    private long createTime; //创建时间
 
     /** 以下省略getter setter方法 */
 
@@ -321,7 +320,7 @@
     private long userid; //用户ID
 
     @Column(length = 64, comment = "用户昵称")
-    private String username = ""; //用户昵称
+    private String userName = ""; //用户昵称
 
     @Column(length = 32, comment = "手机号码")
     private String mobile = ""; //手机号码
@@ -334,7 +333,7 @@
     private String remark = ""; //备注
 
     @Column(updatable = false, comment = "创建时间")
-    private long createtime; //创建时间
+    private long createTime; //创建时间
 
     /** 以下省略getter setter方法 */
     
@@ -376,21 +375,21 @@
 
     //使用CacheSource必须要指明泛型
     @Resource(name = "usersessions")
-    protected CacheSource<Integer> sessions;
+    protected CacheSource sessions;
 
     //登录
     public RetResult<UserInfo> login(LoginBean bean) { //bean.sessionid 在接入层进行赋值
         UserInfo user = null;
         // 登陆逻辑 user = ...
         users.put(user.getUserid(), user);
-        sessions.set(600, bean.getSessionid(), user.getUserid()); //session过期时间设置为10分钟
+        sessions.setLong(600, bean.getSessionid(), user.getUserid()); //session过期时间设置为10分钟
         return new RetResult<>(user);
     }
 
     //获取当前用户信息
     public UserInfo current(String sessionid) { //给HTTP的BaseServlet用
-        Integer userid = sessions.getAndRefresh(sessionid);
-        return userid == null ? null : users.get(userid);
+        Long userid = sessions.getLongAndRefresh(sessionid);
+        return userid == null ? null : users.get(userid.intValue());
     }
 
     //注销
@@ -400,61 +399,56 @@
 }

        以上是个简单的范例,用于用户模块存放sessionid。

-

persistence.xml 配置说明

-
<!-- 其配置算是标准的JPA配置文件的缩略版 -->
-<persistence>	
-    <!-- 系统基本库 -->
-    <persistence-unit name="demouser">
-        <!-- 为NONE表示不启动缓存,@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
-        <shared-cache-mode>NONE</shared-cache-mode>
-        <properties>
-            <!-- 
-                DataSource的实现类,没有设置默认为org.redkale.source.DataJdbcSource的实现,使用常规基于JDBC的数据库驱动一般无需设置
-            -->
-            <property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
-            
-            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
-            <!-- 
-                javax.persistence.jdbc.driver在JPA的值是JDBC驱动,Redkale有所不同,值应该是javax.sql.DataSource的子类。 
-                为了兼容用户习惯,Redkale内置常见JDBC驱动到javax.sql.DataSource的映射关系:
-                                     org.mariadb.jdbc.Driver  ——————  org.mariadb.jdbc.MySQLDataSource
-                                       org.postgresql.Driver  ——————  org.postgresql.ds.PGConnectionPoolDataSource
-                                       com.mysql.jdbc.Driver  ——————  com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
-                             oracle.jdbc.driver.OracleDriver  ——————  oracle.jdbc.pool.OracleConnectionPoolDataSource
-                com.microsoft.sqlserver.jdbc.SQLServerDriver  ——————  com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource
-                因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
-                并且如果JDBC驱动是以上几个版本,javax.persistence.jdbc.driver属性都可以省略,Redkale会根据javax.persistence.jdbc.url的值来识别驱动
-            -->
-            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
-            <property name="javax.persistence.jdbc.user" value="root"/>
-            <property name="javax.persistence.jdbc.password" value="123456"/>
-            
-            <!-- 最大连接数,默认值:CPU数*16  -->
-            <property name="javax.persistence.connections.limit" value="32"/>
-            
-            <!--  包含的SQL模板,相当于反向LIKE,不同的JDBC驱动的SQL语句不一样,Redkale内置了MySQL的语句 -->
-            <property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
-            <property name="javax.persistence.notcontain.sqltemplate" value="LOCATE(${keystr}, ${column}) = 0"/>
-            
-            <!--  复制表结构的SQL模板,Redkale内置了MySQL的语句 -->
-            <property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
-            <property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE ${newtable} LIKE ${oldtable}"/>
-           
-        </properties>
-    </persistence-unit>
-    <!-- IM消息库 -->
-    <persistence-unit name="demoim">
-        <shared-cache-mode>NONE</shared-cache-mode>
-        <properties>
-            <!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&amp;autoReconnectForPools=true&amp;characterEncoding=utf8 -->
-            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
-            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
-            <property name="javax.persistence.jdbc.user" value="root"/>
-            <property name="javax.persistence.jdbc.password" value="123456"/>
-        </properties>
-    </persistence-unit>
-</persistence>
-                
+

source.properties 配置说明

+
+# CacheSource   @Resource(name="usersession")
+# type可以不用设置,框架会根据url判断使用哪个CacheSource实现类
+redkale.cachesource[usersession].type = org.redkalex.cache.redis.RedisCacheSource
+# 最大连接数
+redkale.cachesource[usersession].maxconns = 16
+# 节点地址
+redkale.cachesource[usersession].node[0].url = redis://127.0.0.1:6363
+# 节点密码
+redkale.cachesource[usersession].node[0].password = 12345678
+# 节点db
+redkale.cachesource[usersession].node[0].db = 0
+
+
+
+# DataSource   @Resource(name="platf")
+# type可以不用设置,框架会根据url判断使用哪个DataSource实现类,默认值: org.redkale.source.DataJdbcSource
+redkale.datasource[platf].type = org.redkale.source.DataJdbcSource
+# 是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存, 非NONE字样统一视为ALL
+redkale.datasource[platf].cachemode = ALL
+# 是否自动建表当表不存在的时候, 目前只支持mysql、postgres, 默认为false
+redkale.datasource[platf].table-autoddl = false
+# 用户
+redkale.datasource[platf].user = root
+# 密码
+redkale.datasource[platf].password = 12345678
+# 多个URL用;隔开,如分布式SearchSource需要配多个URL
+redkale.datasource[platf].url = jdbc:mysql://127.0.0.1:3306/platf?allowPublicKeyRetrieval=true&amp;rewriteBatchedStatements=true&amp;serverTimezone=UTC&amp;characterEncoding=utf8
+# 最大连接数,默认值:CPU数
+redkale.datasource[platf].maxconns = 16
+# 包含的SQL模板,相当于反向LIKE,不同的JDBC驱动的SQL语句不一样,Redkale内置了MySQL的语句
+redkale.datasource[platf].contain-sqltemplate = LOCATE(${keystr}, ${column}) > 0
+# 包含的SQL模板,相当于反向LIKE,不同的JDBC驱动的SQL语句不一样,Redkale内置了MySQL的语句
+redkale.datasource[platf].notcontain-sqltemplate = LOCATE(${keystr}, ${column}) = 0
+# 复制表结构的SQL模板,Redkale内置了MySQL的语句
+redkale.datasource[platf].tablenotexist-sqlstates = 42000;42S02
+# 复制表结构的SQL模板,Redkale内置了MySQL的语句
+redkale.datasource[platf].tablecopy-sqltemplate = CREATE TABLE IF NOT EXISTS ${newtable} LIKE ${oldtable}
+
+
+# DataSource 读写分离
+redkale.datasource[platf].read.url = jdbc:mysql://127.0.0.1:3306/platf_r?allowPublicKeyRetrieval=true&amp;rewriteBatchedStatements=true&amp;serverTimezone=UTC&amp;characterEncoding=utf8
+redkale.datasource[platf].read.user = root
+redkale.datasource[platf].read.password = 12345678
+
+redkale.datasource[platf].write.url = jdbc:mysql://127.0.0.1:3306/platf_w?allowPublicKeyRetrieval=true&amp;rewriteBatchedStatements=true&amp;serverTimezone=UTC&amp;characterEncoding=utf8
+redkale.datasource[platf].write.user = root
+redkale.datasource[platf].write.password = 12345678
+