林中侠客

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

最近提到一个需求。需要记录app用户在使用app中的移动轨迹,即坐标值。每分钟上传一次XY坐标,有点类似跑步软件的描线轨迹。

不考虑app如何获取,反正api只要接受到坐标数据 就记录下来保存到数据库。接口接收3个参数X,Y,uid

1,建个新库。test 无论你是云DB还是同服务器下都可以

1 'DB_CONFIG2'=>array(
2      'db_type'=>'mysql',
3      'db_user'=>'root',
4      'db_pwd'=>'',
5      'db_host'=>'localhost',
6      'db_port'=>'3306',
7      'db_name'=>'test',
8  ),

2,建一个保存自增主键ID的表

1 CREATE TABLE `create_id` (
2   `id` bigint(20) NOT NULL AUTO_INCREMENT,
3   PRIMARY KEY (`id`)
4 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='自增ID表';

3,附上主要代码

  1 class TestAction extends Action {
  2    
  3     function _initialize(){
  4         $this->db_2= M()->db(2,"DB_CONFIG2");
  5         $this->union_sql="CREATE TABLE IF NOT EXISTS `%s` (
  6   `id` int(11) NOT NULL,
  7   `longitude` decimal(10,6) NOT NULL COMMENT '经度',
  8   `latitude` decimal(10,6) NOT NULL COMMENT '纬度',
  9   `addtime` int(11) NOT NULL COMMENT '添加时间',
 10   `uid` int(11) NOT NULL COMMENT '用户ID',
 11   PRIMARY KEY (`id`)
 12 ) ENGINE=MRG_MyISAM DEFAULT CHARSET=utf8 INSERT_METHOD=LAST UNION=(`%s`);";
 13         $this->num_sql="CREATE TABLE IF NOT EXISTS `%s` (
 14   `id` int(11) NOT NULL,
 15   `longitude` decimal(10,6) NOT NULL COMMENT '经度',
 16   `latitude` decimal(10,6) NOT NULL COMMENT '纬度',
 17   `addtime` int(11) NOT NULL COMMENT '添加时间',
 18   `uid` int(11) NOT NULL COMMENT '用户ID',
 19   PRIMARY KEY (`id`)
 20 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
 21         
 22     }
 23 
 24     public function index() {
 25        $uid=228; 
 26        $id = 10000099;
 27        //$id = $this->create_id();//生成自增ID
 28        //$uid=trim($_GET['uid']);
 29        $union_table_name="point_".$uid;//总表表名
 30        //新增记录分配分表名
 31        $num_table_name= $this->get_data_table($uid,$id);
 32        //分表名拼接
 33        $union_table_string=$this->get_union_string($uid,$id);
 34        //分表语句 
 35        $num_sql=sprintf($this->num_sql,$num_table_name);
 36        $this->execute($num_sql);//新建分表
 37        //总表语句  
 38        $union_sql=sprintf($this->union_sql,$union_table_name,$union_table_string);    
 39        echo $union_sql;
 40        $re1= $this->execute($union_sql);//创建总表
 41        echo ($this->db_2->getDbError());
 42       
 43        //新增记录
 44        $re=$this->execute("INSERT INTO $num_table_name (`id`, `longitude`, `latitude`, `addtime`, `uid`) VALUES ('$id', '1111.000000', '2222.000000', '22222', '$uid');");
 45        
 46        if($re){
 47            echo json_encode(array("status"=>1,"info"=>true));
 48        }else{
 49            echo json_encode(array("status"=>0,"info"=>false));
 50        }
 51        
 52        
 53     }
 54      
 55    
 56     /**
 57      * 创建一个自增主键
 58      * @return int
 59      */
 60     private function create_id(){
 61       $sql = "insert into create_id (id) values('')";
 62       $this->db_2->execute($sql);
 63       return $this->db_2->getLastInsID();
 64     }
 65     
 66     /**
 67      * 获得表名
 68      * @return string
 69      */
 70     private function get_data_table($uid=null,$id=null){
 71         if(empty($uid)||empty($id)){
 72             return false;
 73         }
 74         return 'point_'.$uid.'_'.$this->get_table_num($id);
 75     }
 76     
 77     /**
 78      * 获得记录所在表序号
 79      * @param  $id  记录ID
 80      * @param  $max 表最大记录数
 81      * @return int
 82      */
 83     private function get_table_num($id,$max=10000000){
 84         $num = ($id<$max) ? 1 : intval($id/$max); //整除取整,默认1
 85         $add =  ($id%$max)>0 && ($id>$max)  ?1:0;//有余数,序号加1
 86         return $num+$add;
 87     }
 88     
 89     /**
 90      * 判断表是否存在
 91      */
 92     private function table_exit_create($table=null){
 93      return $this->db_2->query("show tables like '%{$table}%'"); 
 94 //       return $this->db_2->query("desc {$table}"); 
 95     }
 96     
 97     
 98     /**
 99      * 建表
100      * @return bool 
101      */
102     private function execute($sql){
103         return $this->db_2->execute($sql); 
104     }
105     
106     /**
107      * 生成拼接分表名字符串
108      * @param type $uid
109      * @param type $id
110      * @return string
111      */
112     private function get_union_string($uid=null,$id=null){
113        $res = $this->table_exit_create("point_".$uid."_");
114        if($res){
115            if(count($res)>1){
116                $arr=array();
117                foreach($res as $v){
118                    $arr[]=$v["Tables_in_test (%point_".$uid."_%)"];
119                }
120               $str= implode(',',$arr);
121            }else{
122             $str= "point_".$uid."_".$this->get_table_num($id);  
123            }
124         }else{
125             $str= "point_".$uid."_".$this->get_table_num($id);
126         }
127         
128          return $str;
129       
130        
131     }

 4,分析

原理非常简单。

api接受到参数 -》主键表产生一个主键-》判断主键范围,分配分表名-》创建分表,并把这次接受参数插入分表(注意:所有分表的主键字段必须由主键表产生,确保唯一性)

-》创建总表(必须是ENGINE=MRG_MyISAM),把分表union关联起来,方便查询

分表必须MyISAM引擎,主键非自增

 

补充:1,注意完善参数验证 。UID真实性等

     2,每个分表我取1千万,更大的没有测试。

参考文章:百度来的http://soft.chinabyte.com/database/72/12620572.shtml

posted on 2015-10-28 10:07  林中侠客  阅读(394)  评论(0编辑  收藏  举报