2.大约QT数据库操作,简单的数据库连接操作,增删改查数据库,QSqlTableModel和QTableView,事务性操作,大约QItemDelegate 代理...
Linux下的qt安装,命令时:sudoapt-get install qt-sdk
安装mysql数据库,安装方法參考博客:http://blog.csdn.net/tototuzuoquan/article/details/39565783
假设行想进数据库开发。须要安装libqt5sql5-mysql.命令是:
sudo apt-get install libqt5sql5-mysql
4 创建一个项目
要调用数据库。须要加上QT += gui widgets sql 也就是说要加上sql库
注意假设是在windows平台下:要将C:/MySQL/bin文件夹下的libmySQL.dll复制到项目编译后的生成的exe文件所在的同级文件夹下(比方文件夹E:\QT\build-Database01-Desktop_Qt_5_3_MinGW_32bit-Debug\debug下。在此文件夹下有Database01.exe)。比方截图:
A 假设是在Linux文件夹下,输入下面命令:mysql-u root -p123456
创建数据库:
B使用数据库d0718,并创建所需的数据库表
表内容例如以下:
CREATE TABLE `tcontact` ( `username` varchar(32) NOT NULL, `mobile` varchar(16) NOT NULL, `mobile2` varchar(16) NOT NULL, `telephone` varchar(32) DEFAULT NULL, `home` varchar(32) DEFAULT NULL, `homeaddr` varchar(1024) DEFAULT NULL, `company` varchar(128) DEFAULT NULL, `companyaddr` varchar(1024) DEFAULT NULL, `title` varchar(16) DEFAULT NULL, PRIMARY KEY (`mobile`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
CREATE TABLE `tuser` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'this is userid', `username` varchar(32) NOT NULL COMMENT 'username', `password` varchar(32) NOT NULL COMMENT 'password', `gender` int(11) NOT NULL COMMENT '1 is male 0 is female', PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
C 编写项目代码:
Database01.pro |
SOURCES+=\ main.cpp QT+=gui widgets sql CONFIG+=C++11 |
main.cpp |
#include <QApplication> #include <QSqlDatabase> #include <QSqlError> #include <QDebug> #include <QWidget> int main(int argc,char* argv[]) { QApplication app(argc,argv); QWidget w; /*QT能够操作 QSLITE QODBC,QPLSQL 这些数据库*/ //以下表示使用mysql数据库 QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("127.0.0.1"); //设置数据库所在位置 db.setUserName("root"); //设置数据库的username db.setPassword("123456"); //设置数据库的password db.setDatabaseName("d0718"); //设置数据库名称 bool bRet = db.open(); //打开数据库连接 if(bRet == false) { //说明能够通过db.lastError()的方式得到错误信息 qDebug() << "error open database" << db.lastError().text(); exit(0); } qDebug() << "open database success"; w.show(); return app.exec(); } |
执行结果: |
案例二: |
Database01.pro的内容例如以下: |
SOURCES += \ main.cpp \ Widget01.cpp QT += gui widgets sql #假设用到C++11的才会用到。否则不用 CONFIG += C++11 HEADERS += \ Widget01.h |
Widget01.h的内容例如以下: |
#ifndef WIDGET01_H #define WIDGET01_H #include <QWidget> class Widget01 : public QWidget { Q_OBJECT public: explicit Widget01(QWidget *parent = 0); signals: public slots: }; #endif // WIDGET01_H |
Widget01.cpp的内容例如以下: |
#include "Widget01.h" #include <QSqlDatabase> #include <QSqlError> #include <QSqlQuery> #include <QSqlResult> #include <QDebug> Widget01::Widget01(QWidget *parent) : QWidget(parent) { QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("127.0.0.1"); db.setUserName("root"); db.setPassword("123456"); db.setDatabaseName("d0718"); bool bRet = db.open(); if(bRet == false) { qDebug() << "error open database" << db.lastError().text(); exit(0); } qDebug() << "open database success"; //向数据库中加入数据 db.exec("insert into tuser(username,password,gender) values('涂作权','123456','1')"); db.close(); } |
main.cpp的内容例如以下: |
#include <QApplication> #include "Widget01.h" int main(int argc,char* argv[]) { QApplication app(argc,argv); Widget01 w; w.show(); return app.exec(); } |
执行结果: |
案例2,使用QSqlTableModel |
Database01.pro |
SOURCES += \ main.cpp \ Widget02.cpp QT += gui widgets sql CONFIG += C++11 HEADERS += \ Widget02.h |
Widget02.h |
#ifndef WIDGET02_H #define WIDGET02_H #include <QWidget> class Widget02 : public QWidget { Q_OBJECT public: explicit Widget02(QWidget *parent = 0); signals: public slots: }; #endif // WIDGET02_H |
Widget02.cpp |
#include "Widget02.h" #include <QSqlDatabase> #include <QSqlTableModel> #include <QSqlRecord> #include <QDebug> #include <QSqlError> Widget02::Widget02(QWidget *parent) : QWidget(parent) { // QSqlTableModel: 数据表相应的数据结构 QSqlTableModel model; //设置表名。通过这样的方式不用写sql语句了 model.setTable("tuser"); //设置过滤器,当加上这一句的时候仅仅返回username不是"toto"数据 //model.setFilter("username<>'toto'"); model.select(); // exec query int ret = model.rowCount(); // read data from database for(int i=0; i<ret; ++i) { QSqlRecord record = model.record(i); for(int j=0; j<record.count(); j++) { qDebug() << record.value(j); } } // update data to database //将第0行(脚标以0開始),第1列的数据改成toto //注意仅仅能改动上满select出来的结果。 model.setData(model.index(2, 1), "tototuzuoquan"); //要想让上面的这一句也运行成功。要放开以下一句 model.submitAll(); // insert data to database QSqlRecord record = model.record(); //能够指定id的值,通过以下的方式实现向数据库中插入一条记录 // record.setValue("id", ); record.setValue("username", "toto12"); record.setValue("password", "password12"); record.setValue("gender", 1); model.insertRecord(-1, record); model.submitAll(); } |
main.cpp |
#include <QApplication> #include "Widget02.h" #include <QSqlDatabase> #include <QSqlError> #include <QDebug> int main(int argc,char* argv[]) { QApplication app(argc,argv); /*QT能够操作 QSLITE QODBC,QPLSQL 这些数据库*/ //以下表示使用mysql数据库。由于这里的db没实用到db。所以能够把它放在main中 //本质:在QT里面打开一个数据库之后,就会保存一个数据库连接, //其他的位置就能够随意使用这个全局的变量了 QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("127.0.0.1"); //设置数据库所在位置 db.setUserName("root"); //设置数据库的username db.setPassword("123456"); //设置数据库的password db.setDatabaseName("d0718"); //设置数据库名称 bool bRet = db.open(); //打开数据库连接 if(bRet == false) { //说明能够通过db.lastError()的方式得到错误信息 qDebug() << "error open database" << db.lastError().text(); exit(0); } qDebug() << "open database success"; //注意Widget02要写在上面代码的以下 Widget02 w; w.show(); return app.exec(); } |
执行结果: 数据库中的变化的内容例如以下: |
案例三(QTableView),事务操作: |
Database01.pro |
SOURCES += \ main.cpp \ Widget03.cpp QT += gui widgets sql CONFIG += C++11 HEADERS += \ Widget03.h |
Widget03.h |
#ifndef WIDGET03_H #define WIDGET03_H #include <QObject> #include <QSqlTableModel> #include <QTableView> // show table class Widget03 : public QWidget { Q_OBJECT public: explicit Widget03(QWidget *parent = 0); QSqlTableModel* _model; QTableView* _view; signals: public slots: void slotSubmitClicked(); void slotDelClicked(); void slotAddClicked(); }; #endif // WIDGET03_H |
Widget03.cpp |
#include "Widget03.h" #include <QVBoxLayout> #include <QHBoxLayout> #include <QPushButton> #include <QMessageBox> #include <QSqlError> #include <QSqlDatabase> #include <QSqlRecord> Widget03::Widget03(QWidget *parent) : QWidget(parent) { _model = new QSqlTableModel; _model->setTable("tuser"); _model->select(); _model->setEditStrategy(QSqlTableModel::OnManualSubmit); _model->setHeaderData(0, Qt::Horizontal, "编号"); _model->setHeaderData(1, Qt::Horizontal, "username"); _model->setHeaderData(2, Qt::Horizontal, "password"); _model->setHeaderData(3, Qt::Horizontal, "性别"); _view = new QTableView; //_view中加入_model _view->setModel(_model); //隐藏第3列 //_view->hideColumn(2); QVBoxLayout* lay = new QVBoxLayout(this); lay->addWidget(_view); QHBoxLayout* hBox = new QHBoxLayout; lay->addLayout(hBox); hBox->addStretch(); //删除的信号和槽 QPushButton* del = new QPushButton("del"); connect(del, SIGNAL(clicked()), this, SLOT(slotDelClicked())); hBox->addWidget(del); //提交的信号和槽 QPushButton* submit = new QPushButton("submit"); connect(submit, SIGNAL(clicked()), this, SLOT(slotSubmitClicked())); hBox->addWidget(submit); //加入的信号和槽 QPushButton* add = new QPushButton("add"); connect(add, SIGNAL(clicked()), this, SLOT(slotAddClicked())); hBox->addWidget(add); } /** * @brief Widget03::slotAddClicked 加入的槽 */ void Widget03::slotAddClicked() { //开启事务 _model->database().transaction(); QSqlRecord record = _model->record(); _model->insertRecord(-1,record); } /** * @brief Widget03::slotDelClicked 删除的信号槽 */ void Widget03::slotDelClicked() { // 通过_view去获取被选中的部分的数据model QItemSelectionModel * selectModel = _view->selectionModel(); // 通过选中的数据结构,获取这些格子的ModelIndex QModelIndexList selectList = selectModel->selectedIndexes(); QList<int> delRow; // 遍历这些格子。获取格子所在行,由于可能存在同样的行,所以要去重 for(int i=0; i<selectList.size(); ++i) { QModelIndex index = selectList.at(i); // _model->removeRow(index.row()); delRow << index.row(); } while(delRow.size() > 0) { int row = delRow.at(0); delRow.removeAll(row); _model->removeRow(row); } _model->submitAll(); } void Widget03::slotSubmitClicked() { if(!_model->submitAll()) { QMessageBox::critical(this, "Error", QSqlDatabase().lastError().text()); _model->database().rollback(); } else { _model->database().commit(); } } |
main.cpp |
#include <QApplication> #include "Widget03.h" #include <QSqlDatabase> #include <QSqlError> #include <QDebug> int main(int argc,char* argv[]) { QApplication app(argc,argv); /*QT能够操作 QSLITE QODBC,QPLSQL 这些数据库*/ //以下表示使用mysql数据库,由于这里的db没实用到db,所以能够把它放在main中 //本质:在QT里面打开一个数据库之后,就会保存一个数据库连接, //其他的位置就能够随意使用这个全局的变量了 QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("127.0.0.1"); //设置数据库所在位置 db.setUserName("root"); //设置数据库的username db.setPassword("123456"); //设置数据库的password db.setDatabaseName("d0718"); //设置数据库名称 bool bRet = db.open(); //打开数据库连接 if(bRet == false) { //说明能够通过db.lastError()的方式得到错误信息 qDebug() << "error open database" << db.lastError().text(); exit(0); } qDebug() << "open database success"; //注意Widget02要写在上面代码的以下 Widget03 w; w.show(); return app.exec(); } |
执行结果: |
案例四:关于QItemDelegate代理 |
Database01.pro |
SOURCES+=\ main.cpp\ Widget04.cpp QT+=gui widgets sql CONFIG+=C++11 HEADERS+=\ Widget04.h |
Widget04.h |
#ifndefWIDGET04_H #defineWIDGET04_H #include<QObject> #include<QSqlTableModel> #include<QTableView>//showtable #include<QItemDelegate> #include<QComboBox> /** *@briefTheTUserDelegateclass对整张表进行代理 */ classTUserDelegate:publicQItemDelegate { QWidget*createEditor(QWidget*parent, constQStyleOptionViewItem&option, constQModelIndex&index)const { if(index.column()==0) returnNULL; if(index.column()==3) { QComboBox* combo=newQComboBox(parent); combo->addItem("男"); combo->addItem("女"); returncombo; } returnQItemDelegate::createEditor(parent,option,index); } }; /** *@briefTheReadOnlyDelegateclass做一个仅仅读的代理 */ classReadOnlyDelegate:publicQItemDelegate { QWidget*createEditor(QWidget*, constQStyleOptionViewItem&, constQModelIndex&)const { returnNULL; } }; /** *@briefTheGenderDelegateclass对指定列进行代理 */ classGenderDelegate:publicQItemDelegate { public: QWidget*createEditor(QWidget*parent, constQStyleOptionViewItem&, constQModelIndex&)const { QComboBox* combo=newQComboBox(parent); combo->addItem("男"); combo->addItem("女"); returncombo; } }; /** *@briefTheMyTableModelclass对TableModel的重写 */ classMyTableModel:publicQSqlTableModel { public: QVariantdata(constQModelIndex&idx,introle=Qt::DisplayRole)const { // if(role==Qt::DisplayRole) // returnQSqlTableModel::data(idx,role); //假设不是第三列,直接返回 if(idx.column()!=3) returnQSqlTableModel::data(idx,role); //假设是第三列 QVariantvar=QSqlTableModel::data(idx,role); if(var==0) { return"女"; } return"男"; } boolsetData(constQModelIndex&index,constQVariant&value,introle=Qt::EditRole) { if(index.column()!=3) returnQSqlTableModel::setData(index,value,role); if(value=="男") returnQSqlTableModel::setData(index,1,role); returnQSqlTableModel::setData(index,0,role); } }; classWidget04:publicQWidget { Q_OBJECT public: explicitWidget04(QWidget*parent= 0); MyTableModel*_model; QTableView*_view; signals: publicslots: voidslotSubmitClicked(); voidslotDelClicked(); voidslotAddClicked(); }; #endif//WIDGET04_H |
Widget04.cpp |
#include"Widget04.h" #include<QVBoxLayout> #include<QHBoxLayout> #include<QPushButton> #include<QMessageBox> #include<QSqlError> #include<QSqlDatabase> #include<QSqlRecord> Widget04::Widget04(QWidget*parent): QWidget(parent) { _model=newMyTableModel; _model->setTable("tuser"); _model->select(); //数据库的提交策略是手动提交 _model->setEditStrategy(QSqlTableModel::OnManualSubmit); //改变现实的表的名字 _model->setHeaderData(0,Qt::Horizontal,"编号"); _model->setHeaderData(1,Qt::Horizontal,"username"); _model->setHeaderData(2,Qt::Horizontal,"password"); _model->setHeaderData(3,Qt::Horizontal,"性别"); _view=newQTableView; _view->setModel(_model); // _view->hideColumn(2); //以下是为指定的列设置代理 // _view->setItemDelegateForColumn(3,newGenderDelegate); //_view->setItemDelegateForColumn(0,newReadOnlyDelegate); //为整个表设置代理 _view->setItemDelegate(newTUserDelegate); QVBoxLayout*lay=newQVBoxLayout(this); lay->addWidget(_view); QHBoxLayout*hBox=newQHBoxLayout; lay->addLayout(hBox); hBox->addStretch(); //删除button QPushButton*del=newQPushButton("del"); connect(del,SIGNAL(clicked()),this,SLOT(slotDelClicked())); hBox->addWidget(del); //提交button QPushButton*submit=newQPushButton("submit"); connect(submit,SIGNAL(clicked()),this,SLOT(slotSubmitClicked())); hBox->addWidget(submit); //加入button QPushButton*add=newQPushButton("add"); connect(add,SIGNAL(clicked()),this,SLOT(slotAddClicked())); hBox->addWidget(add); } voidWidget04::slotAddClicked() { QSqlRecordrecord=_model->record(); _model->insertRecord(-1,record); } voidWidget04::slotDelClicked() { //通过_view去获取被选中的部分的数据model QItemSelectionModel*selectModel=_view->selectionModel(); //通过选中的数据结构,获取这些格子的ModelIndex QModelIndexListselectList= selectModel->selectedIndexes(); QList<int>delRow; //遍历这些格子,获取格子所在行,由于可能存在同样的行。所以要去重 for(inti=0;i<selectList.size();++i) { QModelIndexindex=selectList.at(i); // _model->removeRow(index.row()); delRow<<index.row(); } while(delRow.size()>0) { introw=delRow.at(0); delRow.removeAll(row); _model->removeRow(row); } _model->submitAll(); } /** *@briefWidget04::slotSubmitClicked提交button */ voidWidget04::slotSubmitClicked() { if(!_model->submitAll()) { QMessageBox::critical(this,"Error",QSqlDatabase().lastError().text()); } } |
main.cpp |
#include<QApplication> #include"Widget04.h" #include<QSqlDatabase> #include<QSqlError> #include<QDebug> intmain(intargc,char*argv[]) { QApplicationapp(argc,argv); /*QT能够操作QSLITEQODBC,QPLSQL这些数据库*/ //以下表示使用mysql数据库。由于这里的db没实用到db,所以能够把它放在main中 //本质:在QT里面打开一个数据库之后。就会保存一个数据库连接, //其他的位置就能够随意使用这个全局的变量了 QSqlDatabasedb=QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("127.0.0.1"); //设置数据库所在位置 db.setUserName("root"); //设置数据库的username db.setPassword("123456"); //设置数据库的password db.setDatabaseName("d0718"); //设置数据库名称 boolbRet=db.open(); //打开数据库连接 if(bRet==false) { //说明能够通过db.lastError()的方式得到错误信息 qDebug()<<"erroropendatabase"<<db.lastError().text(); exit(0); } qDebug()<<"opendatabasesuccess"; //注意Widget02要写在上面代码的以下 Widget04w; w.show(); returnapp.exec(); } |
执行结果: |
Widget05.h
#ifndef WIDGET05_H
#define WIDGET05_H
#include <QWidget>
#include <QSqlQueryModel>
#include <QTableView>
class Widget05 : public QWidget
{
Q_OBJECT
public:
explicit Widget05(QWidget *parent = 0);
QSqlQueryModel* _model;
QTableView *_view;
signals:
public slots:
};
#endif // WIDGET05_H
Widget05.cpp
#include "Widget05.h"
#include <QSqlQuery>
#include <QVBoxLayout>
Widget05::Widget05(QWidget *parent) :
QWidget(parent)
{
_model = new QSqlQueryModel;
_view = new QTableView(this);
_view->setModel(_model);
_model->setQuery("select * from tuser");
_model->query();
QVBoxLayout* lay = new QVBoxLayout(this);
lay->addWidget(_view);
}
main.cpp
#include <QApplication>
#include "Widget05.h"
#include <QSqlDatabase>
#include <QSqlError>
#include <QDebug>
#include "Contact.h"
int main(int argc,char* argv[])
{
QApplication app(argc,argv);
/*QT能够操作 QSLITE QODBC,QPLSQL 这些数据库*/
//以下表示使用mysql数据库,由于这里的db没实用到db。所以能够把它放在main中
//本质:在QT里面打开一个数据库之后,就会保存一个数据库连接,
//其他的位置就能够随意使用这个全局的变量了
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("127.0.0.1"); //设置数据库所在位置
db.setUserName("root"); //设置数据库的username
db.setPassword("123456"); //设置数据库的password
db.setDatabaseName("d0718"); //设置数据库名称
bool bRet = db.open(); //打开数据库连接
if(bRet == false)
{
//说明能够通过db.lastError()的方式得到错误信息
qDebug() << "error open database" << db.lastError().text();
exit(0);
}
qDebug() << "open database success";
//注意Widget02要写在上面代码的以下
Widget05 w;
w.show();
return app.exec();
}
执行结果:
版权声明:本文博客原创文章,博客,未经同意,不得转载。
2.大约QT数据库操作,简单的数据库连接操作,增删改查数据库,QSqlTableModel和QTableView,事务性操作,大约QItemDelegate 代理...相关推荐
- ASP.NET操作简单的xml,增删改查
温习一下对xml的简单操作,贴出来收藏 xml文件格式: <?xml version="1.0" encoding="utf-8"?> <st ...
- 2.关于QT中数据库操作,简单数据库连接操作,数据库的增删改查,QSqlTableModel和QTableView,事务操作,关于QItemDelegate 代理
Linux下的qt安装,命令时:sudoapt-get install qt-sdk 安装mysql数据库,安装方法参考博客:http://blog.csdn.net/tototuzuoquan ...
- 关于Qt的CRUD增删改查数据库那些事,带GUI图像界面
关于Qt的CRUD增删改查数据库那些事,带GUI图像界面 首先感谢CSDN平台提供这样强大的分享平台. Qt Creator 的几个常用快捷键必须要会,开发事半功倍, Ctrl 简称 C C + i ...
- MVC的简单项目 客户信息-增删改查 崔希凡JavaWeb 之 day-19
目录 增删改查 以"增"举例 查询 改 查询与修改总结 删除 高级搜索 增删改查 以"增"举例 Servlet的功能:(MVC中的C,控制层,一般包名servl ...
- 【JS笔记】JS中的DOM对象以及通过JS获取DOM结点,操作DOM属性、DOM增删改查
这篇文章,主要介绍JS中的DOM对象以及通过JS获取DOM结点,操作DOM属性.DOM增删改查. 目录 一.JS中的DOM 1.1.什么是DOM 1.2.获取DOM结点 (1)获取htm ...
- python操作postgre库,批量进行增删改查和计时比较效率,封装好的普通增删改查和批量增删改查类拿来即用
python操作postgre库,批量进行增删改查,封装类,拿来即用 1. 新建postgre.py文件,使用psycopg2封装普通增删改查和批量增删改查类 postgre.py import ps ...
- PHP增删改查数据库(前端+后台)
PHP增删改查数据库(前端+后台) 要求: 首页导航栏中内置功能 查看数据库 点击Edit修改数据库内容 点击Delete后删除数据库内此记录,返回首页输出删除成功. 向数据库里增加数据 向搜索框输入 ...
- 【02】Java进阶:18-MySQL基础、数据库概述、数据库的安装/卸载/启动/登录、SQL概述、DDL操作数据库、DDL操作表、DML增删改查、
day18-MySql基础 今日内容 数据库概述 数据库安装和卸载 SQL语句 DDL-----操作数据库,操作表 DML-----操作记录(增删改) DQL------操作记录(查) 学习目标 能够 ...
- python增删改查的框架_简单的Django框架增删改查操作
Django之orm对MysqL数据库的增删改查操作简介: 利用Django中orm来查找数据库中的数据,对数据库进行增.删.改.查: 增:新增数据 # 操作数据库user表新增记录 # 方式1: u ...
- C/C++编程操作Redis数据库,hiredis包装redis数据库操作接口及测试(增删改查与连接)
介绍一个实际应用场景,对于客户频繁需要查询的信息,可以将其放在redis内存数据库中,相当于一个缓存,每次查的时候先去redis内存数据库中去查询,如果查询不到再去oracle数据库中查询,这样提高了 ...
最新文章
- 2022-2028年中国渣油行业市场研究及前瞻分析报告
- 报错解决:Liquid Warning: Liquid syntax error (line 2): Expected dotdot but found id in {{(site.github.p
- 自定义导航栏,实现缓存,更新缓存,提高效率
- JavaScript面向对象与传统面向对象的一点区别
- conda create -n python 3.6_conda创建python环境
- FTP(File Transfer Protocol)搭建文件传输服务器vsftp(vsftpd)(FTP和SFTP区别)(未完成)
- 编程之性能优化知多少
- ansys流固耦合分析与工程实例模型文件_平板射流冲击流固耦合分析
- 如何在centos安装python3.4
- FormatJS – 让你的 Web 应用程序国际化
- Kali Linux 从入门到精通(八)-主动信息收集
- 操作系统知识点整理【均来自于网络】
- map--Bit Compression
- ZooKeeper 到底解决了什么问题?
- 软件工程 -- 用例图
- 微创新:粉丝电子商务及微博的9种盈利模式
- 计算机英语怎么念视频,计算机的英语怎么念
- 华为大佬:做一个快乐的程序员
- linux flock 命令安装,在Linux上使用flock命令控制程序的异步执行
- mac 开启android 模拟器,Mac下安卓模拟器环境配置