当前位置:Gxlcms > 数据库问题 > 数据库分表之Mybatis+Mysql实践(含部分关键代码)

数据库分表之Mybatis+Mysql实践(含部分关键代码)

时间:2021-07-01 10:21:17 帮助过:18人阅读

package com.**.uc.utils; import java.util.Calendar; import org.apache.commons.lang.StringUtils; public class TableRouter {                          /**              * table路由规则,获取新表名称              * @param prefix  表明前缀              * @param strategy 切分策略,              * @return              */             public static String getUcCaptchaTable(String prefix,String strategy ){                         //根据切分策略进行切分,添加一定的容错,该部分主要是针对读写频繁的验证码表,故部分代码写死为主表的数据;                         //切分策略为周时,返回“表名_年份周次”,也就是说一年会有52张表                         //切分策略为月时,返回“表名_年份月份”,也就是说一年会有12张表                         //该种切分策略的弊端,是在周末凌晨或者月末凌晨的几分钟,存在验证不存在的情况,在我们的系统允许范围内,故此处未做特殊处理。                         if(StringUtils.isNotBlank(prefix)&&StringUtils.isNotBlank(strategy)&&prefix.equals("uc_captcha")&&"week".equals(strategy)){                                     Calendar c=Calendar.getInstance();                     int i = c.get(Calendar.WEEK_OF_YEAR);                     StringBuffer sb = new StringBuffer();                     int year = c.get(Calendar.YEAR);                     String suffix = sb.append(year).append(i).toString();                     System.out.println(suffix);                     return prefix+"_"+suffix;                         }else if(StringUtils.isNotBlank(prefix)&&StringUtils.isNotBlank(strategy)&&prefix.equals("uc_captcha")&&"month".equals(strategy)){                                     Calendar c=Calendar.getInstance();                     int i = c.get(Calendar.MONTH);                     StringBuffer sb = new StringBuffer();                     int year = c.get(Calendar.YEAR);                     String suffix = sb.append(year).append(i).toString();                     System.out.println(suffix);                     return prefix+"_"+suffix;                         }                         //获取不到分表名称,则返回主表名称                         return "uc_captcha";             }              }
切分策略写好后,关键的是我们需要将我们的sql中对应的表名更改为动态传入,此处用到的是mybatis的多参数映射属性。 部分java代码与xml代码如下: java代码如下(支持集中基本的数据类型,注意map的写法,list的话,采用list 小写):
             /**插入一条数据 **/    public int add(@Param("table") String table  ,@Param("map") Map<String,Object> map);              /**更新一条数据**/    public int update(@Param("table") String table  ,@Param("map") Map<String,Object> map);
  xml文件:注意表名的写法 ${table}使用${}不携带jabcType,也不能使用#;map取参数,使用map.prapmeter 取参数
      <!-- 插入一条新记录 -->       <insert id="add" parameterType="map">        insert into ${table}(pid,btype,uid,naccount,capthcha,ntype,ctime,expiration)        values(        #{map.pid, jdbcType=VARCHAR},        #{map.type, jdbcType=VARCHAR},        #{map.uid, jdbcType=VARCHAR},        #{map.phone, jdbcType=VARCHAR},        #{map.code, jdbcType=VARCHAR},        #{map.is_active, jdbcType=VARCHAR},        #{map.ctime, jdbcType=VARCHAR},        #{map.invalid_time, jdbcType=VARCHAR}        )        <selectKey resultType="int" keyProperty="pid" >              SELECT @@IDENTITY AS pid        </selectKey>       </insert>
domain层调用如下:  
int validation_id = validationDao.add(getCurrentTableName(),map);
其中getCurrentTableName()为内部方法,其中是根据配置的策略以及路由规则获取分表表名,代码如下:  
/**              * 获取当前分表名称              */             public String getCurrentTableName() {                         String tableName =  TableRouter.getUcCaptchaTable("uc_captcha", strategy);                         if(!this._this.existTable(tableName)){//不存在新表,则创建新表,并返回新表表名                                     try {                                                 int tableCreateRes = validationDao.dynamicCreateTable(tableName);                                                          if(tableCreateRes >=0){                                                             //创建新表,清空表不存在的缓存,                                                             this._this.notExistTable(tableName);                                                 }                                     } catch (Exception e) {                                                 return "uc_captcha";                                     }                         }                         return tableName;             }               /**              * 缓存表是否存在,减轻              */             @Cacheable(value="uc2cache", key="‘uc_captcha_exist_‘+#tableName")             public boolean existTable(String tableName){                         int tableCount = validationDao.existTable(tableName);                         if(tableCount == 0){//不存在新表,则创建新表,并返回新表表名                                     return false;                         }                         return true;//存在             }            @CacheEvict(value="uc2cache", key="‘uc_captcha_exist_‘+#tableName")             public void notExistTable(String tableName){}
 
考虑到每次都会调用数据库查询表是否存在,我们为减少对数据库的IO,我们采用了redis缓存的方式,其中AOP切面,自调用不起作用的情况,不在此处赘述。 你可以看到,不存在路由的分表的时候,我们会进行创建表,创建语句如下:  
<!-- 查询表是否存在 --> <select id="existTable" parameterType="String" resultType="Integer">          select count(1)         from information_schema.tables          where LCASE(table_name)=#{table,jdbcType=VARCHAR}      </select> <!-- 创建表 --> <update id="dynamicCreateTable" parameterType="String">       CREATE TABLE  if not EXISTs ${table} (   `pid` varchar(36) NOT NULL,   `uid` int(11) DEFAULT NULL,   `btype` varchar(30) NOT NULL COMMENT ‘业务类型例如:sign 用户注册。login 用户登陆‘,   `ntype` varchar(30) NOT NULL COMMENT ‘短信、邮箱、微信等。根据系统支持取值‘,   `naccount` varchar(30) NOT NULL COMMENT ‘手机号、邮箱、微信等‘,   `capthcha` varchar(6) NOT NULL COMMENT ‘6位随机验证码‘,   `expiration` int(11) NOT NULL COMMENT ‘有效期,距离1970年秒数‘,   `ctime` int(11) NOT NULL COMMENT ‘创建时间距离1970年秒数‘,   PRIMARY KEY (`pid`),   KEY `fk_uccaptcha_uid` (`uid`),   KEY `uk_uc_captcha_ub` (`btype`) USING BTREE,   CONSTRAINT ${table}_ibfk_1 FOREIGN KEY (`uid`) REFERENCES `uc_users_ext` (`uid`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 </update> <!--成功返回0  失败会跑错,我们已经做了容错处理-->
至此,数据库的切分表功能基本完成。   发一个beanselfaware的链接 :http://fyting.iteye.com/blog/109236  

数据库分表之Mybatis+Mysql实践(含部分关键代码)

标签:case   uri   out   strong   多参数   system   you   微信   ali   

人气教程排行