diff --git a/index.html b/index.html index 9175b1437..f8d99a9c0 100644 --- a/index.html +++ b/index.html @@ -59,7 +59,7 @@

-

        Redkale提供DataSource类对数据层进行操作,其功能类似JPA。最大程度的简化数据层的操作,免去SQL/JPQL语句的编写。同时提供过滤查询与JavaBean的结合、读写分离、数据库热切换、本地/远程部署、数据分库分表、进程间缓存自动同步等功能。

+

        Redkale提供DataSource类对数据层进行操作,其功能类似JPA。最大程度的简化数据层的操作,免去SQL/JPQL语句的编写。同时提供过滤查询与JavaBean的结合、读写分离、数据库热切换、本地/远程部署、数据分表分库、进程间缓存自动同步等功能。

Java 源码

        Github 源码    https://github.com/redkale
diff --git a/source.html b/source.html index 20220a5a4..744f0cd7b 100644 --- a/source.html +++ b/source.html @@ -43,14 +43,14 @@ javax.persistence.Cacheable标记Entity类是否需要缓存,与JPA用法一致 javax.persistence.Column标记字段,只使用其name()、insertable()、updatable()属性 javax.persistence.EntityJPA的Entity类必须标记为@Entity, 而Redkale不强制要求,所以该注解一般无用 - javax.persistence.GeneratedValue仅用于标记主键是否为数据库自增长,其内值的两属性废弃 - javax.persistence.GenerationType被@GeneratedValue的属性引用,在Redkale内不被使用到 + javax.persistence.GeneratedValue仅用于标记主键是否为数据库自增长 javax.persistence.Id标记主键字段,与JPA用法一致 javax.persistence.Table标记表的别名,与JPA用法一致 javax.persistence.Transient标记是否为表对应的字段,与JPA用法一致 以下是Redkale自定义的注解 @VirtualEntity用于非数据库表对应的Entity类,且仅用于开启缓存模式的DataSource @DistributeGenerator标记主键是否采用分布式自增长策略,不能与@GeneratedValue同用 + @DistributeTable标记表进行分表分库存储, 与DistributeTableStrategy接口结合使用 @FilterColumn用于FilterBean过滤类的字段设置 @FilterJoinColumn用于FilterBean过滤类的关联表字段设置 @FilterGroup用于FilterBean过滤类的过滤条件分组设置 @@ -64,7 +64,7 @@ insert插入数据 delete删除数据 update更新数据 - updateColumnXXX更新数据的部分字段 + updateColumn更新数据的部分字段 getNumberResult统计查询,用于查询字段的总和、最大值、平均值等数据 queryColumnXXX单个字段数据查询和字段的统计查询 find查找单个对象 @@ -76,7 +76,7 @@         以上接口除了directXXX,其他都有等同的异步接口。insert、delete、update接口与JPA同名接口用法一样。DataSource提供了丰富的查询接口,且有独特的翻页查询功能。每以系列的方法主要重载三类: 单个字段过滤、FilterBean过滤和FilterNode过滤。

    过滤条件

-

        FilterBean、FilterNode对象用于构造过滤条件。FilterBean可以转化为FilterNode。FilterBean主要用于接收外界构建的过滤条件,而FilterNode为了构建内部的过滤条件且降低过滤条件变化的耦合性。

+

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

public class UserBean implements FilterBean {
 
     private int userid;
@@ -144,6 +144,168 @@
                 

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

+ +

    分表分库

+

        DataSource提供了单个实体类对应多个数据库表的功能,通常流水型的数据量比较大,单个数据库无法存储,DataSource提供了简单的分表操作,同时在接口设计上尽量减少单表操作与分表操作的差异。分表分库只需在实体类上注解@DistributeTable并实现DistributeTableStrategy分表策略即可。

+
public interface DistributeTableStrategy<T> {
+
+    /**
+     * 获取对象的表名
+     * 查询单个对象时调用本方法获取表名
+     *
+     * @param table   模板表的表名
+     * @param primary 记录主键
+     *
+     * @return
+     */
+    default String getTable(String table, Serializable primary) {
+        return null;
+    }
+
+    /**
+     * 获取对象的表名
+     * 查询、修改、删除对象时调用本方法获取表名
+     * 注意: 需保证FilterNode过滤的结果集合必须在一个数据库表中
+     *
+     * @param table 模板表的表名
+     * @param node  过滤条件
+     *
+     * @return
+     */
+    default String getTable(String table, FilterNode node) {
+        return null;
+    }
+
+    /**
+     * 获取对象的表名
+     * 新增对象或更新单个对象时调用本方法获取表名
+     *
+     * @param table 模板表的表名
+     * @param bean  实体对象
+     *
+     * @return
+     */
+    public String getTable(String table, T bean);
+}
+                
+ +

        DistributeTableStrategy分表策略需要实现三个接口,除了第三个必须实现,其他两个是可选的,因第三个是新增时需要用到,不实现则不会创建表,而模板表由实体类的@Table注解提供。Redkale默认实现的MySQL数据库的拷贝表结构语句,其他数据库类型需要通过指定persistence.xml 中的 javax.persistence.tablenotexist.sqlstatesjavax.persistence.tablecopy.sqltemplate 来配置。

+ +
@DistributeTable(strategy = LoginRecord.TableStrategy.class)
+public class LoginRecord extends BaseEntity {
+
+    @Id
+    @GeneratedValue
+    @Column(comment = "UUID")
+    private String seqid = ""; //UUID
+
+    @Column(updatable = false, comment = "C端用户ID")
+    private long userid; //C端用户ID
+
+    @Column(updatable = false, comment = "登录网络类型; wifi/4g/3g")
+    private String netmode = ""; //登录网络类型; wifi/4g/3g
+
+    @Column(updatable = false, comment = "APP版本信息")
+    private String appversion = ""; //APP版本信息
+
+    @Column(updatable = false, comment = "APP操作系统信息")
+    private String appos = ""; //APP操作系统信息
+
+    @Column(updatable = false, comment = "登录时客户端信息")
+    private String loginagent = ""; //登录时客户端信息
+
+    @Column(updatable = false, comment = "登录时的IP")
+    private String loginaddr = ""; //登录时的IP
+
+    @Column(updatable = false, comment = "创建时间")
+    private long createtime; //创建时间
+
+    /** 以下省略getter setter方法 */
+ 
+
+    public static class TableStrategy implements DistributeTableStrategy<LoginRecord> {
+
+        private static final String dayformat = "%1$tY%1$tm%1$td";
+
+        private static final String yearformat = "%1$tY";
+
+        //过滤查询时调用本方法
+        @Override
+        public String getTable(String table, FilterNode node) {
+            Serializable day = node.findValue("#day");
+            if (day != null) getTable(table, (Integer) day, 0L); //存在#day参数则直接使用day值
+            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());
+        }
+
+        private String getTable(String table, int day, long createtime) {
+            int pos = table.indexOf('.');
+            String year = (day > 0 ? "" + day / 10000 : String.format(yearformat, createtime));
+            return "platf_login_" + year + "." + table.substring(pos + 1) + "_" + (day > 0 ? day : String.format(dayformat, createtime));
+        }
+    }
+}
+                
+

         以上范例是用户登陆记录的分表分库策略,一年一个库,一个库中365张表,每天一个表。由于分表是根据记录的创建时间作为策略分表,因此策略接口中的public String getTable(String table, Serializable primary) 方法不能实现,因为根据主键id无法确定到数据库表。

+
@DistributeTable(strategy = UserDetail.TableStrategy.class)
+public class UserDetail extends BaseEntity {
+
+    @Id
+    private long userid; //用户ID
+
+    @Column(length = 64, comment = "用户昵称")
+    private String username = ""; //用户昵称
+
+    @Column(length = 32, comment = "手机号码")
+    private String mobile = ""; //手机号码
+
+    @Column(length = 64, comment = "密码")
+    @ConvertColumn(ignore = true, type = ConvertType.ALL)
+    private String password = ""; //密码
+
+    @Column(length = 128, comment = "备注")
+    private String remark = ""; //备注
+
+    @Column(updatable = false, comment = "创建时间")
+    private long createtime; //创建时间
+
+    /** 以下省略getter setter方法 */
+    
+
+    public static class TableStrategy implements DistributeTableStrategy<UserDetail> {
+
+        @Override
+        public String getTable(String table, UserDetail bean) {
+            return getTable(table, bean.getUserid());
+        }
+
+        @Override
+        public String getTable(String table, FilterNode node) {
+            Serializable id = node.findValue("userid");
+            if (id != null) return getTable(table, id);
+            return getHashTable(table, (Integer) node.findValue("#hash"));
+        }
+
+        @Override
+        public String getTable(String table, Serializable userid) {
+            return getHashTable(table, (int) (((Long) userid) % 100));
+        }
+
+        private String getHashTable(String table, int hash) {
+            int pos = table.indexOf('.');
+            return "platf_user." + table.substring(pos + 1) + "_" + (hash > 9 ? hash : ("0" + hash));
+        }
+
+    }
+}
+                
+

CacheSource 入门

         CacheSource同Memcached类似,像一个带有过期功能地Map容器,存放key-value数据。常见的使用场景就是存放HTTP的Session信息。Redkale把用户会话信息数据当做业务数据处理,而不是接入层的数据。WebSocket的连接态数据也是用CacheSource存储。key为WebSocket的groupid,value为WebSocket服务端节点的IP地址列表。

public class UserService implements Service {
@@ -178,49 +340,54 @@
             

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

persistence.xml 配置说明

-
<!-- 其配置算是标准的JPA配置文件的缩略版 -->
-<persistence>	
+            
<!-- 其配置算是标准的JPA配置文件的缩略版 -->
+<persistence>	
     <!-- 系统基本库 -->
-    <persistence-unit name="demouser">
+    <persistence-unit name="demouser">
         <!-- 为NONE表示不启动缓存,@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
-        <shared-cache-mode>NONE</shared-cache-mode>
-        <properties>
-            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
+        <shared-cache-mode>NONE</shared-cache-mode>
+        <properties>
+            <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的映射关系:
-                                       com.mysql.jdbc.Driver  ——————  com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
                                      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
             -->
-            <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、Oracle、Sqlserver的语句
-            <property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
-            <property name="javax.persistence.notcontain.sqltemplate" value="LOCATE(${keystr}, ${column}) = 0"/>
-	    -->
-        </properties>
-    </persistence-unit>
+            <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>
+    <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>
+ <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> +