Files
redkale/source.html
Redkale e413f6d51d
2022-03-17 17:38:59 +08:00

470 lines
73 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3><a id="source_intro" class="anchor" href="#" aria-hidden="true"></a>Source 组件介绍</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Source 主要为数据源提供简易的操作接口,使底层的具体数据源(传统数据库、文件系统、内存数据库、Memcached/Redis缓存)对上层是透明的。其提供两种类型的数据源DataSource 和 CacheSource。DataSource 为数据库或内存数据库提供类似JPA、Hibernate的接口与功能。CacheSource 为缓存数据提供类似Memcached、Redis的接口和功能。两者也提供了异步接口(基于<a href="service.html#service_remote" target="_blank">远程模式Service</a>)。<br/></p>
<a href="article_regain.html"></a>
<h3><a id="source_datasource" class="anchor" href="#" aria-hidden="true"></a>DataSource 入门</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JPA虽已提供了简洁成熟的数据库操作接口但当数据、业务量很庞大的时候就显得捉襟见肘与JPA相比DataSource有以下几个特点<br/>
<a href="article_regain.html"></a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、简易的过滤查询接口但仅支持简单的表关联查询。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、简化分表分库操作。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、通过watch组件动态更改数据库连接参数。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4、读写分离的简易配置。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5、提供异步接口。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据库操作方面常见的是过滤查询操作JPA规范中的JPQL虽然简化了SQL但是对于动态产生的过滤条件,开发人员还是无法免去组装过滤条件的过程(无论JPQL还是CriteriaQuery), DataSource定义了FilterBean接口可以省略组装条件的过程FilterNode提供了类似CriteriaQuery的功能且这两种对象都可以序列化<a href="service.html#service_remote" target="_blank">远程模式Service</a>提供了基础微服务架构提倡服务之间尽量降低耦合因此DataSource仅支持简单的关联查询复杂的表关联查询或统计应放在数据分析系统中。一个服务通常部署多个进程若用JPA的缓存则进程之间的缓存无法同步而DataSource采用SNCP协议即可方便地达到自动同步缓存功能。JPA无法在主数据库异常时动态切换到备份数据库<a href="#source_confproperties">source.properties</a>文件更改后已运行中的进程不会自动切换需要开启watch组件通过watch动态更改正在运行进程中的配置。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了降低学习成本DataSource重用了JPA里的部分注解与配置文件使用方法基本相同与JPA用法的区别是注解只能标记于字段不能标记在方法上。
</p>
<table style="margin: auto;">
<tr><th>注解类名</th><th>功能描述</th></tr>
<tr><td style="text-align: left;">javax.persistence.Cacheable</td><td>标记Entity类是否需要缓存与JPA用法一致</td></tr>
<tr><td style="text-align: left;">javax.persistence.Column</td><td>标记字段只使用其name()、insertable()、updatable()属性</td></tr>
<tr><td style="text-align: left;">javax.persistence.Entity</td><td>JPA的Entity类必须标记为@Entity, 而Redkale不强制要求该注解一般较少使用</td></tr>
<tr><td style="text-align: left;">javax.persistence.Id<td>标记主键字段与JPA用法一致</td></tr>
<tr><td style="text-align: left;">javax.persistence.Table<td>标记表的别名与JPA用法一致</td></tr>
<tr><td style="text-align: left;">javax.persistence.Transient<td>标记是否为表对应的字段与JPA用法一致</td></tr>
<tr><td style="text-align: center;font-size: 0.9rem;" colspan="2"><b>以下是Redkale自定义的注解</b></td></tr>
<tr><td style="text-align: left;"><b>@VirtualEntity</b></td><td>用于非数据库表对应的Entity类且仅用于开启缓存模式的DataSource</td></tr>
<tr><td style="text-align: left;"><b>@DistributeTable</b></td><td>标记表进行分表分库存储, 与DistributeTableStrategy接口结合使用</td></tr>
<tr><td style="text-align: left;"><b>@FilterColumn</b></td><td>用于FilterBean过滤类的字段设置</td></tr>
<tr><td style="text-align: left;"><b>@FilterJoinColumn</b></td><td>用于FilterBean过滤类的关联表字段设置</td></tr>
<tr><td style="text-align: left;"><b>@FilterGroup</b></td><td>用于FilterBean过滤类的过滤条件分组设置</td></tr>
</table>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;操作数据源主要使用的对象有 DataSource、FilterBean、FilterNode。DataSource 提供的接口分几种系列:
</p>
<table style="margin: auto;">
<tr><th>系列方法</th><th>功能描述</th></tr>
<tr><td style="text-align: left;">insert</td><td>插入数据</td></tr>
<tr><td style="text-align: left;">delete</td><td>删除数据</td></tr>
<tr><td style="text-align: left;">update</td><td>更新数据</td></tr>
<tr><td style="text-align: left;">updateColumn</td><td>更新数据的部分字段</td></tr>
<tr><td style="text-align: left;">getNumberXXX</td><td>统计查询,用于查询字段的总和、最大值、平均值等数据</td></tr>
<tr><td style="text-align: left;">queryColumnXXX<td>单个字段数据查询和字段的统计查询</td></tr>
<tr><td style="text-align: left;">find<td>查找单个对象</td></tr>
<tr><td style="text-align: left;">queryList<td>查询对象的List集合</td></tr>
<tr><td style="text-align: left;">querySheet</td><td>查询对象的Sheet页式集合</td></tr>
<tr><td style="text-align: left;">directXXX<td>直接运行SQL语句用于复杂的关联查询与更新(仅限DataSqlSource)</td></tr>
</table>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以上接口除了directXXX其他都有等同的异步接口。insert、delete、update接口与JPA同名接口用法一样。DataSource提供了丰富的查询接口且有独特的翻页查询功能。每以系列的方法主要重载三类 单个字段过滤、FilterBean过滤和FilterNode过滤。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>返回类型为CompletableFuture的接口均为异步接口</b><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;开发者可以借鉴 <a href="https://github.com/redkale/redkale-demo" target="_blank">Redkale-demo</a> 中的 <a href="https://github.com/redkale/redkale-demo/blob/master/src/main/java/org/redkale/demo/base/AutoClassCreator.java" target="_blank"> AutoClassCreator</a>的代码根据数据表自动生成Entity代码。
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<b>过滤条件</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FilterBean、FilterNode对象用于构造过滤条件。FilterBean可以转化为FilterNode。FilterBean主要用于接收外界构建的过滤条件而FilterNode为了构建内部的过滤条件且降低过滤条件变化的耦合性FilterNode中name值以#开头的视为虚拟字段不会构建成过滤条件仅供分布分库的DistributeTableStrategy策略使用。</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserBean</span> <span class="kd">implements</span> <span class="n">FilterBean</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">userid</span><span class="o">;</span>
<span class="nd">@FilterColumn</span><span class="o">(</span><span class="n">express</span> <span class="o">=</span> <span class="n">FilterExpress</span><span class="o">.</span><span class="na">LIKE</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">userName</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">Range</span> <span class="n">age</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">UserBean</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">userName</span><span class="o">,</span> <span class="n">Range</span> <span class="n">age</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">userid</span> <span class="o">=</span> <span class="n">userid</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">userName</span> <span class="o">=</span> <span class="n">userName</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">age</span> <span class="o">=</span> <span class="n">age</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">/**</span> <span class="n">以下省略getter</span> <span class="n">setter方法</span> <span class="o">*/</span>
<span class="o">}</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="nf">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span> <span class="mi">36</span><span class="o">))</span> <span class="o">等价于</span>
<span class="n">FilterNode</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="s">&quot;userid&quot;</span><span class="o">,</span> <span class="mi">200001</span><span class="o">).</span><span class="na">and</span><span class="o">(</span><span class="s">&quot;userName&quot;</span><span class="o">,</span> <span class="n">FilterExpress</span><span class="o">.</span><span class="na">LIKE</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">).</span><span class="na">and</span><span class="o">(</span><span class="s">&quot;age&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="n">Range</span><span class="o">.</span><span class="na">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span> <span class="mi">36</span><span class="o">))</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span><span class="s">&quot;redkale&quot;</span><span class="o">,</span><span class="k">new</span> <span class="nf">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span><span class="mi">36</span><span class="o">))</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userid=200001 AND userName LIKE &#39;%redkale%&#39; AND age BETWEEN 14 AND 36&quot;</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="kc">null</span><span class="o">)</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userid = 200001 AND userName LIKE &#39;%redkale%&#39;&quot;</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="kc">null</span><span class="o">)</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userName LIKE &#39;%redkale%&#39;&quot;</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上定义UserBean过滤条件当非数值类字段值为null、字符串值为空、数值类字段值小于@FilterColumn.least()值(least的默认值为1)都不会构建成过滤条件。@FilterColumn.express根据字段的类型有不同的默认值若字段类型为Collection子类或数组则express默认为FilterExpress.IN若字段类型为Range的子类则express默认为FilterExpress.BETWEEN其他类型则express默认为FilterExpress.EQUAL。默认字段之间是AND关系若想使用OR关系则需要使用@FilterGroup进行标记</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserBean</span> <span class="kd">implements</span> <span class="n">FilterBean</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">userid</span><span class="o">;</span>
<span class="nd">@FilterGroup</span><span class="o">(</span><span class="s">&quot;[OR]a&quot;</span><span class="o">)</span>
<span class="nd">@FilterColumn</span><span class="o">(</span><span class="n">express</span> <span class="o">=</span> <span class="n">FilterExpress</span><span class="o">.</span><span class="na">LIKE</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">userName</span><span class="o">;</span>
<span class="nd">@FilterGroup</span><span class="o">(</span><span class="s">&quot;[OR]a&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">Range</span> <span class="n">age</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">UserBean</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">userName</span><span class="o">,</span> <span class="n">Range</span> <span class="n">age</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">userid</span> <span class="o">=</span> <span class="n">userid</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">userName</span> <span class="o">=</span> <span class="n">userName</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">age</span> <span class="o">=</span> <span class="n">age</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">/**</span> <span class="n">以下省略getter</span> <span class="n">setter方法</span> <span class="o">*/</span>
<span class="o">}</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="nf">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span> <span class="mi">36</span><span class="o">))</span> <span class="o">等价于</span>
<span class="n">FilterNode</span> <span class="n">orNode</span> <span class="o">=</span> <span class="n">FilterNode</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="s">&quot;userName&quot;</span> <span class="o">,</span> <span class="n">FilterExpress</span><span class="o">.</span><span class="na">LIKE</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">).</span><span class="na">or</span><span class="o">(</span><span class="s">&quot;age&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="n">Range</span><span class="o">.</span><span class="na">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span> <span class="mi">36</span><span class="o">));</span>
<span class="n">FilterNode</span> <span class="n">node</span> <span class="o">=</span> <span class="n">FilterNode</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="s">&quot;userid&quot;</span><span class="o">,</span> <span class="mi">200001</span><span class="o">).</span><span class="na">and</span><span class="o">(</span><span class="n">orNode</span><span class="o">);</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span><span class="s">&quot;redkale&quot;</span><span class="o">,</span><span class="k">new</span> <span class="nf">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span><span class="mi">36</span><span class="o">))</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userid=200001 AND (userName LIKE &#39;%redkale%&#39; OR age BETWEEN 14 AND 36)&quot;</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="kc">null</span><span class="o">)</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userid = 200001 AND userName LIKE &#39;%redkale%&#39;&quot;</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="kc">null</span><span class="o">)</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userName LIKE &#39;%redkale%&#39;&quot;</span>
<span class="n">source</span><span class="o">.</span><span class="na">getNumberResult</span><span class="o">(</span><span class="n">User</span><span class="o">.</span><span class="k">class</span><span class="o">,</span> <span class="n">FilterFunc</span><span class="o">.</span><span class="na">COUNT</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="nf">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span> <span class="mi">36</span><span class="o">))).</span><span class="na">intValue</span><span class="o">()</span> <span class="o">等价于</span>
<span class="s">&quot;SELECT COUNT(*) FROM user WHERE userName LIKE &#39;%redkale%&#39; AND age BETWEEN 14 AND 36&quot;</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上@FilterGroup 的value 必须是[OR]或者[AND]开头,没有标记@FilterGroup的字段等价于标记了@FilterGroup(value = "[AND]")。[AND]、[OR]后面的字符串为GROUP_NAME默认的GROUP_NAME为空字符串。如上"[OR]a"可以直接使用"[OR]",有多个[OR]或者[AND]则需要加上不同的NAME。</p>
<p id="source_distribute">&nbsp;&nbsp;&nbsp;&nbsp;<b>分表分库</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DataSource提供了单个实体类对应多个数据库表的功能通常流水型的数据量比较大单个数据库无法存储DataSource提供了简单的分表操作同时在接口设计上尽量减少单表操作与分表操作的差异。分表分库只需在实体类上注解@DistributeTable并实现DistributeTableStrategy分表策略即可。</p>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">DistributeTableStrategy</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="cm">/**</span>
<span class="cm"> * 获取对象的表名</span>
<span class="cm"> * 查询单个对象时调用本方法获取表名</span>
<span class="cm"> *</span>
<span class="cm"> * @param table 模板表的表名</span>
<span class="cm"> * @param primary 记录主键</span>
<span class="cm"> *</span>
<span class="cm"> * @return</span>
<span class="cm"> */</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">Serializable</span> <span class="n">primary</span><span class="o">);</span>
<span class="cm">/**</span>
<span class="cm"> * 获取对象的表名</span>
<span class="cm"> * 查询、修改、删除对象时调用本方法获取表名</span>
<span class="cm"> * 注意: 需保证FilterNode过滤的结果集合必须在一个数据库表中</span>
<span class="cm"> *</span>
<span class="cm"> * @param table 模板表的表名</span>
<span class="cm"> * @param node 过滤条件</span>
<span class="cm"> *</span>
<span class="cm"> * @return</span>
<span class="cm"> */</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">FilterNode</span> <span class="n">node</span><span class="o">);</span>
<span class="cm">/**</span>
<span class="cm"> * 获取对象的表名</span>
<span class="cm"> * 新增对象或更新单个对象时调用本方法获取表名</span>
<span class="cm"> *</span>
<span class="cm"> * @param table 模板表的表名</span>
<span class="cm"> * @param bean 实体对象</span>
<span class="cm"> *</span>
<span class="cm"> * @return</span>
<span class="cm"> */</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">T</span> <span class="n">bean</span><span class="o">);</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DistributeTableStrategy分表策略需要实现三个接口模板表由实体类的@Table注解提供。Redkale默认实现的MySQL数据库的拷贝表结构语句其他数据库类型需要通过指定<a href="#source_confproperties">source.properties</a> 中的 <b>tablenotexist-sqlstates</b><b>tablecopy-sqltemplate</b> 来配置。</p>
<div class="highlight"><pre><span></span><span class="nd">@DistributeTable</span><span class="o">(</span><span class="n">strategy</span> <span class="o">=</span> <span class="n">LoginRecord</span><span class="o">.</span><span class="na">TableStrategy</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">LoginRecord</span> <span class="kd">extends</span> <span class="n">BaseEntity</span> <span class="o">{</span>
<span class="nd">@Id</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">comment</span> <span class="o">=</span> <span class="s">"主键ID; 值=create36time(9位)+'-'+UUID(32位)"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">loginid</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//主键ID; 值=create36time(9位)+'-'+UUID(32位)</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"C端用户ID"</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">userid</span><span class="o">;</span> <span class="c1">//C端用户ID</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"登录网络类型; wifi/4g/3g"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">netMode</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//登录网络类型; wifi/4g/3g</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"APP版本信息"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">appVersion</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//APP版本信息</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"APP操作系统信息"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">appos</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//APP操作系统信息</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"登录时客户端信息"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">loginAgent</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//登录时客户端信息</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"登录时的IP"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">loginAddr</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//登录时的IP</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"创建时间"</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">createTime</span><span class="o">;</span> <span class="c1">//创建时间</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="c1">//创建对象</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">Throwable</span> <span class="o">{</span>
<span class="n">LoginRecord</span> <span class="n">record</span> <span class="o">=</span> <span class="k">new</span> <span class="n">LoginRecord</span><span class="o">();</span>
<span class="kt">long</span> <span class="n">now</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">();</span>
<span class="n">record</span><span class="o">.</span><span class="na">setCreateTime</span><span class="o">(</span><span class="n">now</span><span class="o">);</span> <span class="c1">//设置创建时间</span>
<span class="n">record</span><span class="o">.</span><span class="na">setLoginid</span><span class="o">(</span><span class="n">Utility</span><span class="o">.</span><span class="na">format36time</span><span class="o">(</span><span class="n">now</span><span class="o">)</span> <span class="o">+</span> <span class="s">"-"</span> <span class="o">+</span> <span class="n">Utility</span><span class="o">.</span><span class="na">uuid</span><span class="o">());</span> <span class="c1">//主键的生成规则</span>
<span class="c1">//.... 填充其他字段</span>
<span class="n">source</span><span class="o">.</span><span class="na">insert</span><span class="o">(</span><span class="n">record</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">TableStrategy</span> <span class="kd">implements</span> <span class="n">DistributeTableStrategy</span><span class="o">&lt;</span><span class="n">LoginRecord</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">dayformat</span> <span class="o">=</span> <span class="s">"%1$tY%1$tm%1$td"</span><span class="o">;</span> <span class="c1">//一天一个表</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">yearformat</span> <span class="o">=</span> <span class="s">"%1$tY"</span><span class="o">;</span> <span class="c1">//一年一个库</span>
<span class="c1">//过滤查询时调用本方法</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">FilterNode</span> <span class="n">node</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Serializable</span> <span class="n">day</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">"#day"</span><span class="o">);</span> <span class="c1">//LoginRecord没有day字段所以前面要加#,表示虚拟字段, 值为yyyyMMdd格式</span>
<span class="k">if</span> <span class="o">(</span><span class="n">day</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="o">(</span><span class="n">Integer</span><span class="o">)</span> <span class="n">day</span><span class="o">,</span> <span class="mi">0</span><span class="n">L</span><span class="o">);</span> <span class="c1">//存在#day参数则直接使用day值</span>
<span class="n">Serializable</span> <span class="n">time</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">"createTime"</span><span class="o">);</span> <span class="c1">//存在createTime则使用最小时间且createTime的范围必须在一天内因为本表以天为单位建表</span>
<span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="o">(</span><span class="n">time</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="mi">0</span><span class="n">L</span> <span class="o">:</span> <span class="o">(</span><span class="n">time</span> <span class="k">instanceof</span> <span class="n">Range</span> <span class="o">?</span> <span class="o">((</span><span class="n">Range</span><span class="o">.</span><span class="na">LongRange</span><span class="o">)</span> <span class="n">time</span><span class="o">).</span><span class="na">getMin</span><span class="o">()</span> <span class="o">:</span> <span class="o">(</span><span class="n">Long</span><span class="o">)</span> <span class="n">time</span><span class="o">)));</span>
<span class="o">}</span>
<span class="c1">//创建或单个查询时调用本方法</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">LoginRecord</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">bean</span><span class="o">.</span><span class="na">getCreateTime</span><span class="o">());</span>
<span class="o">}</span>
<span class="c1">//根据主键ID查询单个记录时调用本方法</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">Serializable</span> <span class="n">primary</span><span class="o">)</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">id</span> <span class="o">=</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">primary</span><span class="o">;</span>
<span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">Long</span><span class="o">.</span><span class="na">parseLong</span><span class="o">(</span><span class="n">id</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">9</span><span class="o">),</span> <span class="mi">36</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="kt">int</span> <span class="n">day</span><span class="o">,</span> <span class="kt">long</span> <span class="n">createTime</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//day为0或yyyyMMdd格式数据</span>
<span class="kt">int</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="sc">'.'</span><span class="o">);</span>
<span class="n">String</span> <span class="n">year</span> <span class="o">=</span> <span class="n">day</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">String</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="n">day</span> <span class="o">/</span> <span class="mi">10000</span><span class="o">)</span> <span class="o">:</span> <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="n">yearformat</span><span class="o">,</span> <span class="n">createTime</span><span class="o">);</span> <span class="c1">//没有day取createTime</span>
<span class="k">return</span> <span class="s">"platf_login_"</span> <span class="o">+</span> <span class="n">year</span> <span class="o">+</span> <span class="s">"."</span> <span class="o">+</span> <span class="n">table</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="n">pos</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">+</span> <span class="s">"_"</span> <span class="o">+</span> <span class="o">(</span><span class="n">day</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">day</span> <span class="o">:</span> <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="n">dayformat</span><span class="o">,</span> <span class="n">createTime</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如上范例用户登陆记录的分表分库策略为一年一个库一个库中365张表每天一个表。为了分表策略的三个接口均得到实现需要对主键ID的生成规则进行一定的设计。常见的场景是查询单个用户的登录列表。上面的范例就无法满足查询单个用户的登录信息需求而分表策略又只能根据一种规则生成因此需要按用户维度存在另外一张表中。</p>
<div class="highlight"><pre><span></span><span class="nd">@DistributeTable</span><span class="o">(</span><span class="n">strategy</span> <span class="o">=</span> <span class="n">LoginUserRecord</span><span class="o">.</span><span class="na">TableStrategy</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">LoginUserRecord</span> <span class="kd">extends</span> <span class="n">BaseEntity</span> <span class="o">{</span>
<span class="nd">@Id</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;记录ID; 值=userid+'-'+UUID&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">seqid</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//记录ID; 值=userid+'-'+UUID</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;C端用户ID&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">userid</span><span class="o">;</span> <span class="c1">//C端用户ID</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;LoginRecord主键&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">loginid</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//LoginRecord主键</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;创建时间&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">createTime</span><span class="o">;</span> <span class="c1">//创建时间</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">TableStrategy</span> <span class="kd">implements</span> <span class="n">DistributeTableStrategy</span><span class="o">&lt;</span><span class="n">LoginUserRecord</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">LoginUserRecord</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="n">bean</span><span class="o">.</span><span class="na">getUserid</span><span class="o">());</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">FilterNode</span> <span class="n">node</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Serializable</span> <span class="n">id</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">&quot;userid&quot;</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">id</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="n">id</span><span class="o">);</span>
<span class="k">return</span> <span class="n">getHashTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="o">(</span><span class="n">Integer</span><span class="o">)</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">&quot;#hash&quot;</span><span class="o">));</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">Serializable</span> <span class="n">primary</span><span class="o">)</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">id</span> <span class="o">=</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">primary</span><span class="o">;</span>
<span class="k">return</span> <span class="n">getHashTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">Long</span><span class="o">.</span><span class="na">parseLong</span><span class="o">(</span><span class="n">id</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">id</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="sc">&#39;-&#39;</span><span class="o">)))</span> <span class="o">%</span> <span class="mi">100</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="n">String</span> <span class="nf">getHashTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="kt">int</span> <span class="n">hash</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="sc">&#39;.&#39;</span><span class="o">);</span>
<span class="k">return</span> <span class="s">&quot;platf_login.&quot;</span> <span class="o">+</span> <span class="n">table</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="n">pos</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="o">(</span><span class="n">hash</span> <span class="o">&gt;</span> <span class="mi">9</span> <span class="o">?</span> <span class="n">hash</span> <span class="o">:</span> <span class="o">(</span><span class="s">&quot;0&quot;</span> <span class="o">+</span> <span class="n">hash</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如上表LoginUserRecord只存储用户ID与登录信息ID的关联关系以用户ID取模100进行hash存储获取用户登录列表时先查询LoginUserRecord一页的数据再根据loginid查询LoginRecord实体。常见的分表策略是时间和主键hash例如用户信息表采用主键hash分表</p>
<div class="highlight"><pre><span></span><span class="nd">@DistributeTable</span><span class="o">(</span><span class="n">strategy</span> <span class="o">=</span> <span class="n">UserDetail</span><span class="o">.</span><span class="na">TableStrategy</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserDetail</span> <span class="kd">extends</span> <span class="n">BaseEntity</span> <span class="o">{</span>
<span class="nd">@Id</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">userid</span><span class="o">;</span> <span class="c1">//用户ID</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">length</span> <span class="o">=</span> <span class="mi">64</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;用户昵称&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">userName</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//用户昵称</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">length</span> <span class="o">=</span> <span class="mi">32</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;手机号码&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">mobile</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//手机号码</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">length</span> <span class="o">=</span> <span class="mi">64</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;密码&quot;</span><span class="o">)</span>
<span class="nd">@ConvertColumn</span><span class="o">(</span><span class="n">ignore</span> <span class="o">=</span> <span class="kc">true</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="n">ConvertType</span><span class="o">.</span><span class="na">ALL</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">password</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//密码</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">length</span> <span class="o">=</span> <span class="mi">128</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;备注&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">remark</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//备注</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;创建时间&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">createTime</span><span class="o">;</span> <span class="c1">//创建时间</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">TableStrategy</span> <span class="kd">implements</span> <span class="n">DistributeTableStrategy</span><span class="o">&lt;</span><span class="n">UserDetail</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">UserDetail</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="n">bean</span><span class="o">.</span><span class="na">getUserid</span><span class="o">());</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">FilterNode</span> <span class="n">node</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Serializable</span> <span class="n">id</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">&quot;userid&quot;</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">id</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="n">id</span><span class="o">);</span>
<span class="k">return</span> <span class="n">getHashTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="o">(</span><span class="n">Integer</span><span class="o">)</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">&quot;#hash&quot;</span><span class="o">));</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">Serializable</span> <span class="n">userid</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">getHashTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(((</span><span class="n">Long</span><span class="o">)</span> <span class="n">userid</span><span class="o">)</span> <span class="o">%</span> <span class="mi">100</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="n">String</span> <span class="nf">getHashTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="kt">int</span> <span class="n">hash</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="sc">&#39;.&#39;</span><span class="o">);</span>
<span class="k">return</span> <span class="s">&quot;platf_user.&quot;</span> <span class="o">+</span> <span class="n">table</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="n">pos</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="o">(</span><span class="n">hash</span> <span class="o">&gt;</span> <span class="mi">9</span> <span class="o">?</span> <span class="n">hash</span> <span class="o">:</span> <span class="o">(</span><span class="s">&quot;0&quot;</span> <span class="o">+</span> <span class="n">hash</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如上用户表以userid取模100进行hash分表若需要提供根据手机号查询单个用户信息则需要另外存在一个用户ID对应手机号码的关系表同样可以以手机号后两位数字为hash存储。</p>
<h3><a id="source_cachesource" class="anchor" href="#" aria-hidden="true"></a>CacheSource 入门</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CacheSource同Memcached类似像一个带有过期功能地Map容器存放key-value数据。常见的使用场景就是存放HTTP的Session信息。Redkale把用户会话信息数据当做业务数据处理而不是接入层的数据。WebSocket的连接态数据也是用CacheSource存储。key为WebSocket的groupidvalue为WebSocket服务端节点的IP地址列表。</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserService</span> <span class="kd">implements</span> <span class="n">Service</span> <span class="o">{</span>
<span class="c1">//用户简单信息缓存</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">UserInfo</span><span class="o">&gt;</span> <span class="n">users</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ConcurrentHashMap</span><span class="o">&lt;&gt;();</span>
<span class="c1">//使用CacheSource必须要指明泛型</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;usersessions&quot;</span><span class="o">)</span>
<span class="kd">protected</span> <span class="n">CacheSource</span> <span class="n">sessions</span><span class="o">;</span>
<span class="c1">//登录</span>
<span class="kd">public</span> <span class="n">RetResult</span><span class="o">&lt;</span><span class="n">UserInfo</span><span class="o">&gt;</span> <span class="nf">login</span><span class="o">(</span><span class="n">LoginBean</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//bean.sessionid 在接入层进行赋值</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="c1">// 登陆逻辑 user = ...</span>
<span class="n">users</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">(),</span> <span class="n">user</span><span class="o">);</span>
<span class="n">sessions</span><span class="o">.</span><span class="na">setLong</span><span class="o">(</span><span class="mi">600</span><span class="o">,</span> <span class="n">bean</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(),</span> <span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">());</span> <span class="c1">//session过期时间设置为10分钟</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">&lt;&gt;(</span><span class="n">user</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//获取当前用户信息</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">current</span><span class="o">(</span><span class="n">String</span> <span class="n">sessionid</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//给HTTP的BaseServlet用</span>
<span class="n">Long</span> <span class="n">userid</span> <span class="o">=</span> <span class="n">sessions</span><span class="o">.</span><span class="na">getLongAndRefresh</span><span class="o">(</span><span class="n">sessionid</span><span class="o">);</span>
<span class="k">return</span> <span class="n">userid</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="n">users</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">userid.intValue()</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//注销</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">logout</span><span class="o">(</span><span class="n">String</span> <span class="n">sessionid</span><span class="o">)</span> <span class="o">{</span>
<span class="n">sessions</span><span class="o">.</span><span class="na">remove</span><span class="o">(</span><span class="n">sessionid</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以上是个简单的范例用于用户模块存放sessionid。</p>
<h3><a id="source_confproperties" href="#" aria-hidden="true"></a>source.properties 配置说明</h3>
<div class="highlight"><pre>
<span></span><span class="c1"># CacheSource @Resource(name="usersession")</span>
<span class="c1"># type可以不用设置框架会根据url判断使用哪个CacheSource实现类</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">cachesource</span><span class="p">[</span><span class="n">usersession</span><span class="p">]</span><span class="o">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">org</span><span class="o">.</span><span class="n">redkalex</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">redis</span><span class="o">.</span><span class="n">RedisCacheSource</span>
<span class="c1"># 最大连接数</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">cachesource</span><span class="p">[</span><span class="n">usersession</span><span class="p">]</span><span class="o">.</span><span class="n">maxconns</span> <span class="o">=</span> <span class="mi">16</span>
<span class="c1"># 节点地址</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">cachesource</span><span class="p">[</span><span class="n">usersession</span><span class="p">]</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="n">redis</span><span class="p">:</span><span class="o">//</span><span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">6363</span>
<span class="c1"># 节点密码</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">cachesource</span><span class="p">[</span><span class="n">usersession</span><span class="p">]</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">password</span> <span class="o">=</span> <span class="mi">12345678</span>
<span class="c1"># 节点db</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">cachesource</span><span class="p">[</span><span class="n">usersession</span><span class="p">]</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">db</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1"># DataSource @Resource(name="platf")</span>
<span class="c1"># type可以不用设置框架会根据url判断使用哪个DataSource实现类默认值: org.redkale.source.DataJdbcSource</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">org</span><span class="o">.</span><span class="n">redkale</span><span class="o">.</span><span class="n">source</span><span class="o">.</span><span class="n">DataJdbcSource</span>
<span class="c1"># 是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存, 非NONE字样统一视为ALL</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">cachemode</span> <span class="o">=</span> <span class="n">ALL</span>
<span class="c1"># 是否自动建表当表不存在的时候, 目前只支持mysql、postgres 默认为false</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">table</span><span class="o">-</span><span class="n">autoddl</span> <span class="o">=</span> <span class="n">false</span>
<span class="c1"># 用户</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">user</span> <span class="o">=</span> <span class="n">root</span>
<span class="c1"># 密码</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">password</span> <span class="o">=</span> <span class="mi">12345678</span>
<span class="c1"># 多个URL用;隔开如分布式SearchSource需要配多个URL</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="n">jdbc</span><span class="p">:</span><span class="n">mysql</span><span class="p">:</span><span class="o">//</span><span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">3306</span><span class="o">/</span><span class="n">platf</span><span class="">?</span><span class="n">allowPublicKeyRetrieval</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">rewriteBatchedStatements</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">serverTimezone</span><span class="o">=</span><span class="n">UTC</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">characterEncoding</span><span class="o">=</span><span class="n">utf8</span>
<span class="c1"># 最大连接数默认值CPU数</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">maxconns</span> <span class="o">=</span> <span class="mi">16</span>
<span class="c1"># 包含的SQL模板相当于反向LIKE不同的JDBC驱动的SQL语句不一样Redkale内置了MySQL的语句</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">contain</span><span class="o">-</span><span class="n">sqltemplate</span> <span class="o">=</span> <span class="n">LOCATE</span><span class="p">(</span><span class="">$</span><span class="p">{</span><span class="n">keystr</span><span class="p">},</span> <span class="">$</span><span class="p">{</span><span class="n">column</span><span class="p">})</span> <span class="o">&gt;</span> <span class="mi">0</span>
<span class="c1"># 包含的SQL模板相当于反向LIKE不同的JDBC驱动的SQL语句不一样Redkale内置了MySQL的语句</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">notcontain</span><span class="o">-</span><span class="n">sqltemplate</span> <span class="o">=</span> <span class="n">LOCATE</span><span class="p">(</span><span class="">$</span><span class="p">{</span><span class="n">keystr</span><span class="p">},</span> <span class="">$</span><span class="p">{</span><span class="n">column</span><span class="p">})</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1"># 复制表结构的SQL模板Redkale内置了MySQL的语句</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">tablenotexist</span><span class="o">-</span><span class="n">sqlstates</span> <span class="o">=</span> <span class="mi">42000</span><span class="p">;</span><span class="mi">42</span><span class="n">S02</span>
<span class="c1"># 复制表结构的SQL模板Redkale内置了MySQL的语句</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">tablecopy</span><span class="o">-</span><span class="n">sqltemplate</span> <span class="o">=</span> <span class="n">CREATE</span> <span class="n">TABLE</span> <span class="n">IF</span> <span class="n">NOT</span> <span class="n">EXISTS</span> <span class="">$</span><span class="p">{</span><span class="n">newtable</span><span class="p">}</span> <span class="n">LIKE</span> <span class="">$</span><span class="p">{</span><span class="n">oldtable</span><span class="p">}</span>
<span class="c1"># DataSource 读写分离</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="n">jdbc</span><span class="p">:</span><span class="n">mysql</span><span class="p">:</span><span class="o">//</span><span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">3306</span><span class="o">/</span><span class="n">platf_r</span><span class="">?</span><span class="n">allowPublicKeyRetrieval</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">rewriteBatchedStatements</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">serverTimezone</span><span class="o">=</span><span class="n">UTC</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">characterEncoding</span><span class="o">=</span><span class="n">utf8</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="o">.</span><span class="n">user</span> <span class="o">=</span> <span class="n">root</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="o">.</span><span class="n">password</span> <span class="o">=</span> <span class="mi">12345678</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">write</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="n">jdbc</span><span class="p">:</span><span class="n">mysql</span><span class="p">:</span><span class="o">//</span><span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">3306</span><span class="o">/</span><span class="n">platf_w</span><span class="">?</span><span class="n">allowPublicKeyRetrieval</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">rewriteBatchedStatements</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">serverTimezone</span><span class="o">=</span><span class="n">UTC</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">characterEncoding</span><span class="o">=</span><span class="n">utf8</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">write</span><span class="o">.</span><span class="n">user</span> <span class="o">=</span> <span class="n">root</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">write</span><span class="o">.</span><span class="n">password</span> <span class="o">=</span> <span class="mi">12345678</span>
</pre></div>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>