概况
Yii2 一个高效安全的高性能PHP框架。mongodb 一个高性能分布式文档存储NOSQL数据库。
关于mongodb与mysql的优缺点,应该都了解过。
mysql传统关系数据库,安全稳定、数据完整、资源文档完善、使用群体多、支持事物,V5.7后支持原生Json速度不逊mongodb、分布式主从集群刚刚的……
mongodb新兴NOSQL数据库,Bson文档存储,支持原生Javascript、性能优异百千万数据不在话下、内置GridFS Sharding海量存储、热数据持久化、分片部署……
参考:http://www.wtoutiao.com/p/19an83a.html
那到底mysql与mongodb性能对比如何呢,什么时候选择mysql什么时候选择mongodb呢,网上有很多自己search吧,这里我们讲的是,将mongodb加入Yii2的扩展中,并使用经典的ActiveRecord操作数据。
等等,再说下什么是ActiveRecord
说ActiveRecord之前呐,先要知道ORM(Object Relational Mapping 对象关系映射)用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的"虚拟对象数据库"。ActiveRecord就是一个典型的ORM。Yii2 提供了DAO (Data Access Objects 数据访问对象) ,可以方便的用$db->createCommand()完成任何数据库相关的任务,包括复杂的业务SQL语句。甚至执行速度比ActiveRecord快很多,但是在这个金(敏)钱(捷)社(开)会(发)时代,开发速度才是我们解决的最主要问题。Yii2的ActiveRecord中,每个AR类代表一个数据表,其字段作为AR类的属性,一个AR实例代表在表中的一行。常见的CRUD操作被作为AR类的方法执行。 我们使用更面向对象的方法处理我们的数据,so,开发速度就开到5挡了!
一.mongodb安装
1.Windows安装
下载最新的mongodb 地址:https://www.mongodb.com/download-center 本人使用版本V3.2
一路"下一步"完成安装。mongd为服务端,mongo为客户端。打开终端切换到bin目录
终端中输入:
mongod --logpath C:\data\dbConf\mongodb.log --logappend --dbpath C:\data\db --journal --bind_ip 127.0.0.1 --serviceName MongoDB --port --install
参数说明:
-logpath C:\data\dbConf\mongodb.log #设置日志path
--dbpath C:\data\db #设置db path
--journal #设置数据存储格式
--bind_ip 127.0.0.1 #防止其他ip访问
--port 9888 #27017修改端口
--install #install Windows service
其中bind_ip与port很重要,记得一定要修改,嗯!秘密噢!
当使用了--install后会安装到Windows的系统服务中,如果要卸载mongodb服务,使用
sc delete mongodb
在Windows服务中开启mongodb服务
在终端中输入
mongo --port
出现如下表示成功
2.Linux安装
同理下载Linux版mongodb
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.3.tgz
解压
tar -zxvf mongodb-linux-x86_64-3.4..tgz
移动目录到/usr/local/mongodb
mv mongodb-linux-x86_64-3.4./ /usr/local/mongodb
新建db,与log文件路径,因为mongodb数据存储在data的db目录,但安装启动不会自动生成。我们把data新建在mongodb的同级目录(放哪你自己决定)
mkdir -p data/db
mkdir -p data/dbconf
启动服务
cd bin/ ./mongod --logpath /usr/local/mongodb/data/dbconf/mongodb.log --logappend --dbpath /usr/local/mongodb/data/db --bind_ip 127.0.0.1,201.104.104.104 --port
查看data/dbconf/mongodb.log 显示失败
--30T09::14.324+ I CONTROL [initandlisten] MongoDB starting : pid= port= dbpath=/usr/local/mongodb/data/db -bit host=u23dk88fzrZ
--30T09::14.324+ I CONTROL [initandlisten] db version v3.4.3
--30T09::14.324+ I CONTROL [initandlisten] git version: f07437fb5a6cca07c10bafa78365456eb1d6d5e1
--30T09::14.324+ I CONTROL [initandlisten] allocator: tcmalloc
--30T09::14.324+ I CONTROL [initandlisten] modules: none
--30T09::14.324+ I CONTROL [initandlisten] build environment:
--30T09::14.324+ I CONTROL [initandlisten] distarch: x86_64
--30T09::14.324+ I CONTROL [initandlisten] target_arch: x86_64
--30T09::14.324+ I CONTROL [initandlisten] options: { net: { bindIp: "127.0.0.1,201.104.104.104", port: }, storage: { dbPath: "/usr/local/mongodb/data/db" }, systemLog: { destination: "file", path: "/usr/local/mongodb/data/dbconf/mongodb.log" } }
--30T09::14.347+ E NETWORK [initandlisten] listen(): bind() failed Cannot assign requested address for socket: 201.104.104.104:
--30T09::14.347+ E NETWORK [initandlisten] Failed to set up sockets during startup.
--30T09::14.347+ E STORAGE [initandlisten] Failed to set up listener: InternalError: Failed to set up sockets
--30T09::14.347+ I NETWORK [initandlisten] shutdown: going to close listening sockets...
--30T09::14.347+ I NETWORK [initandlisten] removing socket file: /tmp/mongodb-.sock
--30T09::14.347+ I NETWORK [initandlisten] shutdown: going to flush diaglog...
--30T09::14.347+ I CONTROL [initandlisten] now exiting
--30T09::14.347+ I CONTROL [initandlisten] shutting down with code:
因为没有让防火墙放行端口9898,开放端口
iptables -A INPUT -p tcp -m tcp --dport -j ACCEPT
插曲:linux用的是Centos7,默认使用的firewall防火墙必须启用iptables 链接:http://www.linuxidc.com/Linux/2015-05/117473.htm 、 http://blog.csdn.net/smstong/article/details/39317277
然后我们使用客户端mongo连接
./mongo --port
已经链接成功。
要以守护进程的形式运行mongodb,要添加fork参数:
./mongod --logpath /usr/local/mongodb/data/dbconf/mongodb.log --logappend --dbpath /usr/local/mongodb/data/db --bind_ip 127.0.0.1,201.104.104.104 --port --fork
3.安装php mongodb扩展
下载地址:http://pecl.php.net/package/mongodb
*注: pecl提供了两个package 一个是 http://pecl.php.net/package/mongodb 另外一个是 http://pecl.php.net/package/mongo, 目前后者不在更新已经提示:This package has been superseded, but is still maintained for bugs and security fixes.
Windows版的扩展就不多说了,找到对应的php版本.dll就可以了,我用的是php7.0.8
修改php.ini 加入ext=php_mongodb.dll
说说Linux版本扩展的安装
这个是mongodb官网安装插件的说明:https://github.com/mongodb/mongo-php-driver-legacy
下载最新版: 2017-03-20
wget http://pecl.php.net/get/mongodb-1.2.8.tgz
解压:
tar vxzf mongodb-1.2..tgz
进入目录,此时就要注意了如果php是自己编译安装,在编译mongo之前的要带上php的配置path
使用phpize命令添加外挂模块, 什么是phpize? 链接: http://www.2cto.com/kf/201111/110140.html
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make
make install
貌似php7.0.8下编译一直提示:/usr/local/php/bin/php: symbol lookup error: /home/wwwroot/tools/mongodb-1.2.8/modules/mongodb.so: undefined symbol: OPENSSL_init_ssl
解决php安装mongodb.so 扩展提示 :mongodb.so: undefined symbol: OPENSSL_init_ssl
非php7.0.8版本编译报错,找了好久问题是安装openssl版本的问题
首先我们查看phpinfo,看php -i 显示的openssl支持的多少版本
OpenSSL support | enabled |
OpenSSL Library Version | OpenSSL 1.0.1e-fips 11 Feb 2013 |
OpenSSL Header Version | OpenSSL 1.0.1e-fips 11 Feb 2013 |
Openssl default config | /etc/pki/tls/openssl.cnf |
然后在终端查看openssl版本
OpenSSL 1.1. Aug
问题就在这,因为我yum update过openssl,导致php编译版本与系统现有版本不一致,使mongodb make的时候提示openssl保存有问题。
解决办法:
恢复之前的openssl版本在编译mongodb
通过find / -name openssl
/usr/bin/openssl OpenSSL 1.0.1e-fips Feb
/usr/local/bin/openssl OpenSSL 1.1. Aug
/usr/local/include/openssl -------
/usr/local/ssl/bin/openssl OpenSSL 1.0.2c Jun
/usr/local/ssl/include/openssl --------
/usr/local/share/doc/openssl --------
/usr/include/openssl --------
/usr/lib64/openssl --------
/etc/pki/ca-trust/extracted/openssl--------
要让终端默认使用1.0.1e版本,(Linux终端bash默认/usr/local/bin)
/usr/local/bin/
mv openssl openssl1.1.0
cp /usr/bin/openssl ./
修改/usr/local/include/openssl目录中的.h文件为1.0.1e版本的文件,约72个*.h文件 (可查看opensslv.h文件获取版本)
终端访问:
# openssl version
OpenSSL 1.0.1e-fips Feb
修改php.ini
extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-/mongodb.so
因php由php-fpm控制,因此需要重启php-fpm,使php.ini配置生效。重启php-fpm
参考 Linux 安装基于(PHP5.5)memcache扩展
service php-fpm stop
./php-fpm -c /usr/local/php/etc/php2.ini
二. Yii2 配置mongodb-extensions
可通过composer安装或手动安装
1.通过composer安装
官网安装说明:http://www.yiiframework.com/doc-2.0/ext-mongodb-index.html
命令行切换到项目vendor同级目录执行
php composer.phar require –prefer-dist yiisoft/yii2-mongodb “^2.1”
漫长等待…… 执行完成后composer.json文件和在\vendor\yiisoft下有对应的目录生成
"yiisoft/yii2-mongodb": "~2.1.0"
2.通过手动安装
下载地址:https://github.com/yiisoft/yii2-mongodb
下载后添加到 /vendor/yiisoft/yii2-mongodb
打开 vendor\yiisoft\extensions.php 在最底部添加:
'yiisoft/yii2-mongodb' =>
array (
'name' => 'yiisoft/yii2-mongodb',
'version' => '2.1.0',
'alias' =>
array (
'@yii/mongodb' => $vendorDir . '/yiisoft/yii2-mongodb',
),
),
打开 vendor\composer\autoload_psr4.php 在最底部添加:
'yii\\mongodb\\' => array($vendorDir . '/yiisoft/yii2-mongodb'),
3.配置main文件
main-local.php 配置连接mongodb
'mongodb' => [
'class' => 'yii\mongodb\Connection',
//'class' => 'backend\models\core\mongodb\Mconnection',
# 有账户的配置
//'dsn' => 'mongodb://demofancyecommerce:fdaVBDFS#fdfdtyg423DF23#$@localhost:27017/demofancyecommerce',
# 无账户的配置
'dsn' => 'mongodb://127.0.0.1:9898/mongo_test',
//'dsn' => 'mongodb://10.10.10.252:10001/erp,mongodb://10.10.10.252:10002/erp,mongodb://10.10.10.252:10004/erp?replicaSet=terry&readPreference=primaryPreferred',
],
4. 设置gii
设置gii生成器配置
$config['bootstrap'][] = 'mongogii';
$config['modules']['mongogii'] ['class']= 'yii\mongodb\model\Generator';
$config['modules']['mongogii']['allowedIPs'] =['127.0.0.1','201.104.104.104',"::1"];
三. ActiveRecord操作数据
这步我们要将用ActiveRecord进行数据的CURD操作
1.导入测试数据
如果你是在Windows下操作,强烈建议你用MongoVUE管理工具,很NB的一个mongodb管理工具。 好,将mysql中的数据入mongodb。
如果服务器Linux设置仅127.0.0.1可连接mongod服务端,可以参考SecureCRT端口映射转发,转发到本地对应的端口,使用 localhost:port 连接
查看插入的集合数据
2.生成models
在上一步,我们已经配置了mian文件和gii,同时也给测试库的customer集合插入测试数据,现在用gii来生成models
直接访问项目域+mongogii
生成的路径在models/Customer.php 为了区分与comm里面的,我们将模型改名为MCustomer.php,查看代码
namespace app\models; use Yii; /**
* This is the model class for collection "customer".
*
* @property \MongoDB\BSON\ObjectID|string $_id
* @property mixed $id
* @property mixed $name
* @property mixed $province
* @property mixed $city
* @property mixed $town
* @property mixed $address
* @property mixed $lng
* @property mixed $lat
* @property mixed $create_time
*/
class MCustomer extends \yii\mongodb\ActiveRecord { /**
* @inheritdoc
*/
public static function collectionName() {
return ['mongo_test', 'customer'];
} /**
* @inheritdoc
*/
public function attributes() {
return [
'_id',
'id',
'name',
'province',
'city',
'town',
'address',
'lng',
'lat',
'create_time',
'status',
];
} /**
* @inheritdoc
* 参考 YII2,rules规则
*/
public function rules() {
return [
[['name', 'province', 'city', 'town', 'address'], 'required'],
[['id', 'name', 'province', 'city', 'town', 'address', 'lng', 'lat', 'create_time', 'status'], 'safe'],
[['province', 'city', 'town'], 'integer'],
[['name'], 'string', 'max' => 20],
];
} /**
* @inheritdoc
*/
public function attributeLabels() {
return [
'_id' => 'ID',
'id' => 'Id',
'name' => 'Name',
'province' => 'Province',
'city' => 'City',
'town' => 'Town',
'address' => 'Address',
'lng' => 'Lng',
'lat' => 'Lat',
'create_time' => 'Create Time',
];
} }
其中rules规则是自己加的,因为mongogii仅生成‘safe’规则,rules验证规则可参考:http://www.phpxs.com/post/3443/
3.控制器方法
MVC中Models已经有了,就剩Controller与View了,而最主要的就是Controller了,因为逻辑都放在控制器中了(按照大神的建议,逻辑代码应该放到Models里面)。
其他什么都别说 然后我们吃着火锅一起唱这歌!!!上代码!!!
MongoController.php
/**
* mongo controller
*/ namespace app\controllers; use Yii; class MongoController extends BaseController { public $pageSize = 10; /**
* Index 列表首页
*/
public function actionIndex() {
$search = $this->post('search');
$orderField = $this->post('orderField');
$orderDirection = $this->post('orderDirection');
$where = [];
$orderby = 'id desc';
##################### search ##############################
if ($search['name']) { # 模糊搜索
$where['name'] = ['$regex' => $search['name']];
}
if ($search['id']) { # int 类型匹配
$where['id'] = intval($search['id']);
}
###################### orderby ####################################
if ($orderField && $orderDirection) {
$orderby = $orderField . " {$orderDirection}";
}
############### page #####################
if ($this->post('pageSize')) {
$this->pageSize = $this->post('pageSize');
}
$_GET['page'] = '';
if ($this->post('pageCurrent')) {
$_GET['page'] = $this->post('pageCurrent');
} ####################### data ####################
$data = \app\models\MCustomer::find()->where($where)->orderBy($orderby);
$count = $data->count();
$pagesize = $this->pageSize; // 分页大小
$pages = new \yii\data\Pagination(['totalCount' => $count, 'pageSize' => $pagesize]);
$model = $data->offset($pages->offset)->limit($pages->limit)->all();
$pagge = $this->render('//' . 'default/page', ['pageSize' => $pagesize, 'pageTotal' => $count, 'page' => $_GET['page']]);
return $this->display([
'alist' => $model,
'pages' => $pages,
'search' => $search,
'pagge' => $pagge,
]);
} /**
* 删除操作
*/
public function actionDel() {
$id = self::post('id'); # field id 与字段类型必须对应 (int)
$_id = self::post('_id'); # mongoid
# by _id
$model = \app\models\MCustomer::findOne($_id);
if ($model) {
$model->delete(); # 物理删除
}
# by id
if ($id) {
$model = \app\models\MCustomer::find()->where(["id" => intval($id)])->one();
if ($model) {
$model->status = 3; # 状态删除
$model->save();
}
} if (!$model->errors) {
self::UICallback(200, '删除成功');
}
} /**
* 编辑、 新增 操作
*/
public function actionEdit() {
$id = $this->query('id');
$model = \app\models\MCustomer::find()->where(["id" => intval($id)])->one();
if (!$model) {
$model = new \app\models\MCustomer();
}
return $this->display('edit', [
'model' => $model,
]);
} /**
* 编辑新增 保存save 操作
*/
public function actionDataSave() {
$_id = self::post('_id');
$post = \Yii::$app->request->post();
# 获取省市区县及address, 通过百度解析为lng、lat经纬度保存-- 演示暂无
$post['create_time'] = strtotime($post['create_time']);
if ($_id) { # 编辑
$model = \app\models\MCustomer::findOne($_id);
$model->attributes = $post;
$model->save();
} else { # 新增
$model = new \app\models\MCustomer();
$model->attributes = $post;
$model->save();
#$id= $model->attributes['id']; # 获取插入数据的mongoid
}
if ($model->errors) {
self::UICallback(300, '保存失败', ['node' => $model->errors]);
} else {
self::UICallback(200, '保存成功', ['closeCurrent' => TRUE, 'tabid' => 'monnn']);
}
} }
views/mongo里面代码:
index.php
<?php
use yii\bootstrap\ActiveForm;
?>
<div class="bjui-pageHeader">
<?php
$form = ActiveForm::begin([
'id' => 'pagerForm',
'method' => 'post',
'options' => ['data-toggle' => 'ajaxsearch']
]);
?>
<input type="hidden" name="pageSize" value="${model.pageSize}" placeholder="">
<input type="hidden" name="pageCurrent" value="${model.pageCurrent}">
<input type="hidden" name="orderField" value="">
<input type="hidden" name="orderDirection" value="">
<div class="bjui-searchBar">
<label>客户姓名:</label>
<?php echo yii\helpers\Html::input('text', 'search[name]', $search['name'], ['size' => 12, 'placeholder' => '客户姓名']) ?>
<label>客户id:</label>
<?php echo yii\helpers\Html::input('text', 'search[id]', $search['id'], ['size' => 12, 'placeholder' => '客户ID信息']) ?>
<button type="submit" class="btn-default" data-icon="search">查询</button>
<a href="/mongo/edit" class="btn btn-green" data-id="mongo_data" data-toggle="navtab" data-title="新增客户" data-icon="plus">客户</a> </div>
<?php ActiveForm::end(); ?>
</div>
<div class="bjui-pageContent tableContent">
<table data-toggle="tablefixed" data-width="100%" data-nowrap="true">
<thead>
<tr>
<th data-order-field="id" >ID</th>
<th data-order-field="name">姓名</th>
<th>位置</th>
<th>经纬度</th>
<th width="370">操作</th>
</tr>
</thead>
<tbody>
<?php
if (!empty($alist)) {
foreach ($alist as $key => $value) {
?>
<tr data-id=""> <td><?php echo $value['id']; ?></td>
<td><?php echo $value['name']; ?></td>
<td><?php echo $value['city']; ?><?php echo $value['address']; ?></td>
<td><?php echo $value['lng']; ?>,<?php echo $value['lat']; ?></td>
<td>
<a href="/mongo/edit?id=<?php echo $value->id;?>" class="btn btn-orange" data-id="mongo_data" data-toggle="navtab" data-reload-warn="本页已有打开的内容,确定将刷新本页内容,是否继续?" data-title="查看客户信息" data-icon="edit">查看</a>
<a href="/mongo/del" data-toggle="doajax" data-data="_id=<?php echo $value->{'_id'}?>&id=<?php echo $value['id'] ?>&_csrf=<?php echo Yii::$app->request->csrfToken; ?>" class="btn btn-red row-del" data-confirm-msg="确定要删除该行信息吗?" data-icon="remove">删</a>
</td>
</tr>
<?php
}
}
?>
</tbody>
</table>
</div>
<?php
echo $pagge;
edit.php
<?php use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
?>
<div class="bjui-pageContent">
<?php $form = ActiveForm::begin([ 'action' => '/mongo/data-save', 'options' => ['data-alertmsg' => 'false', 'data-toggle' => 'validate']]); ?>
<?php echo Html::hiddenInput('_id', $model->{'_id'}); ?>
<table class="table table-condensed table-hover" width="100%">
<tbody> <tr>
<td colspan="2">
<label for="name" class="control-label x85">姓名:</label>
<?php echo Html::input('text', 'name', $model->name, ['data-rule' => "required", 'placeholder' => '姓名']); ?>
</td>
</tr>
<tr>
<td>
<label for="j_custom_birthday" class="control-label x85">现居地址:</label>
<?php echo $this->AreaSelect(['name' => 'province', 'chkval' => $model['province'], 'area' => 'province', 'data-rule' => 'required', 'doption' => '请选择省份', 'data-nextselect' => '#employee_j_form_city', 'data-refurl' => '/comm/area?id={value}']); ?>-
<?php echo $this->AreaSelect(['name' => 'city', 'chkval' => $model['city'], 'area' => 'city', 'data-rule' => 'required', 'doption' => '请选择城市', 'parentid' => $model['province'], 'id' => 'employee_j_form_city', 'data-nextselect' => '#employee_j_form_town', 'data-refurl' => '/comm/area?id={value}']); ?>-
<?php echo $this->AreaSelect(['name' => 'town', 'chkval' => $model['town'], 'area' => 'town', 'data-rule' => 'required', 'doption' => '请选择区县', 'data-emptytxt' => '请选择区县', 'parentid' => $model['city'], 'id' => 'employee_j_form_town']); ?> </td>
<td >
<label for="address" class="control-label x85">详细地址:</label>
<?php echo Html::input('text', 'address', $model->address, ['data-rule' => "required", 'id' => 'address', 'size' => 25, 'placeholder' => '详细地址']); ?>
</td>
</tr> <tr>
<td colspan="2">
<label for="url" class="control-label x85">登记时间:</label>
<?php echo Html::input('text', 'create_time', $model->create_time ? date("Y-m-d", $model->create_time) : '', ['data-rule' => "required", 'data-toggle' => 'datepicker', 'data-pattern' => 'yyyy-MM-dd H:m', 'placeholder' => '登记时间', 'data-min-date' => date('Y-m-d')]); ?>
</td>
</tr> </tbody>
</table>
<?php ActiveForm::end(); ?>
</div>
<div class="bjui-pageFooter">
<ul> <li><button type="button" class="btn-close" data-icon="close">取消</button></li>
<li><button type="submit" class="btn-default" data-icon="save">保存</button></li> </ul>
</div>
效果: