From d6affd7321cf751f1bdc7be11c2b158217e71746 Mon Sep 17 00:00:00 2001 From: zizhilong <104978@qq.com> Date: Thu, 11 Feb 2016 15:58:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BAmodel=E6=89=A9=E5=B1=95.?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E5=A4=A7=E6=89=B9=E9=87=8F=E5=9F=BA=E4=BA=8E?= =?UTF-8?q?=E5=BE=AA=E7=8E=AF=E7=9A=84=E6=95=B0=E6=8D=AE=E6=8F=92=E5=85=A5?= =?UTF-8?q?=E6=88=96=E8=80=85=E6=95=B0=E6=8D=AE=E6=9B=B4=E6=96=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit //此演示需要手动修改Adv文件加载Bulk特性 $m=M('think\model\Adv:log'); //连续插入10000条语句.在运行期间,会根据设定执行db的insertAll for($i=0;$i<=10000;$i++) { $m->bulkAdd(array('application'=>'123456','content'=>'xxxx')); } //执行最后更新 //连续修改1万条记录 $m->bulkAdd(true); for($i=0;$i<=10000;$i++){ $m->bulkSave(array('id'=>$i,'admin_id'=>$i*2)); } //执行最后的修改更新. $m->bulkSave(true); --- library/traits/model/Bulk.php | 157 ++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 library/traits/model/Bulk.php diff --git a/library/traits/model/Bulk.php b/library/traits/model/Bulk.php new file mode 100644 index 00000000..258df178 --- /dev/null +++ b/library/traits/model/Bulk.php @@ -0,0 +1,157 @@ + +// +---------------------------------------------------------------------- + +namespace traits\model; + +use think\Lang; + +trait Bulk +{ + //插入缓存 + private $bulkAddCache = []; + //插入缓存SQL语句预估长度 + private $bulkAddSize = 0; + //更新缓存 + private $bulkSaveCache = []; + private $bulkSaveSize = []; + /** + * 进行缓存插入操作 + * @access public + * @param mixed $data 创建数据,如果传入true则更新所有缓存 + * @param string $type 状态 + * @return mixed + */ + public function bulkAdd($data = '',$options=[]) + { + // 如果没有数据传入 + if (empty($data)) { + $this->error = Lang::get('_DATA_TYPE_INVALID_'); + } + + if($data !== true){ + //如不是提交操作,则进行数据处理和缓存累加 + $data = $this->_write_data($data,'insert'); + $this->bulkAddCache[] = $data; + //统计所有字段内容长度 + foreach($data as $key=>$val) + { + $this->bulkAddSize += strlen($val); + } + } + //得到默认的提交SQL数据长度,此设定根据数据库配置不同得到的性能结果会有差异 + //这个数字是否应该写死还是定义一个公共配置名称,需要核心组讨论 + //发现使用insertAll因为bind生成出来的语句比正常的要长不少.字段名+时间戳+序号,还有优化的余地 + if(isset($options['bulkSize'])){ + $bulkSize = $options['bulkSize']; + } + else{ + $bulkSize = 10000; + } + + //数据累计到一定量,则执行 + if($this->bulkAddSize>=10000 || ($data === true && !empty($this->bulkAddCache))){ + + $options = $this->_parseOptions($options); + // 写入数据到数据库 + $result = $this->db->insertAll($this->bulkAddCache, $options,false); + //清空插入缓存 + $this->bulkAddCache = []; + //清空长度计数 + $this->bulkAddSize = 0; + //触发了一个实际插入操作,返回成功或失败 + return (false !== $result); + } + //插入数据到缓存未导致任何触发 + return true; + } + /** + * 批量更新操作 + * @access public + * @param mixed $data 创建数据,如果传入true则更新所有缓存 + * @param string $type 状态 + * @return mixed + */ + public function bulkSave($data = '',$options=[]) + { + // 如果没有数据传入 + if (empty($data)) { + $this->error = Lang::get('_DATA_TYPE_INVALID_'); + } + $options = $this->_parseOptions(); + $pk = $this->getPk(); + if($data !== true){ + //批量跟新必须是带有主键的数组 + if(!isset($data[$pk])){ + throw new Exception('no have pk field'); + } + //由于批量更新存在在原值累加的情况,所以会有 array('id'=>1,'val+'=>10);所以不能先做字段检查 + foreach($data as $field=>$val) + { + //主键不需要处理 + if($field==$pk){ + continue; + } + //对字段缓存初始化.每个字段的更新都会以独立的SQL进行. + if(!isset($this->bulkSaveCache[$field])){ + $this->bulkSaveCache[$field] = []; + $this->bulkSaveSize[$field] = 0; + } + //如果同一个记录的同一字段被多次更新 + if(isset($this->bulkSaveCache[$field][$data[$pk]])){ + //如果是自增自减操作 + $operator = '='; + if(in_array(substr($field,-1,1),['+','-'])){ + $operator = substr($field,-1,1); + } + if($operator == '='){ + //如果是直接赋值,不能重复写入,因为不确定那个值是正确的 + throw new Exception('cannot repeat write in'); + } + else{ + //在原有修改基础上再进行自增或自减操作 + $this->bulkSaveCache[$field][$data[$pk]] += ( $operator =='+' ? $val : - $val ); + } + } + else{ + $this->bulkSaveCache[$field][$data[$pk]] = $val; + } + //计算新增修改增加的SQL长度 + $this->bulkSaveSize[$field] += strlen($val)+strlen($pk)*2+14; + } + } + if(isset($options['bulkSize'])){ + $bulkSize = $options['bulkSize']; + } + else{ + $bulkSize = 5000; + } + //扫描字段长度.看是否有需要先执行的 + foreach($this->bulkSaveSize as $field=>$size) + { + if($size >= $bulkSize || ($size>0 && $data === true)){ + //复制出插入数组 + $dataSet = $this->bulkSaveCache[$field]; + unset($this->bulkSaveCache[$field]); + unset($this->bulkSaveSize[$field]); + //默认运算符 + $operator='='; + //自增或者自减 + if(in_array(substr($field,-1,1),['+','-'])) + { + $operator = substr($field,-1,1); + $field = substr($field,0,-1); + } + //批量字段更新 + $this->db->updateFieldAll($field,$pk,$dataSet,$operator,$options); + } + } + } +}