学习教程来源于:
php中文网 ThinkPHP5 视频教程
ThinkPHP5.0完全开发手册
TP5采用的是惰性连接,故而仅在查询时才会连接到数据库
TP5的数据库操作对底层进行优化设计,对各种操作进行高级封装。既可以直接使用连接器进行高效的原生查询,也可以使用封装好的查询构造器进行直观便捷的查询,为模型操作打下基础。
静态连接:应用/模块中的数据库配置文件database.php
动态连接:入口类Db.php
中的connect
(参数:数组/字符串)方法
参数名 | 默认值 | 说明 |
---|---|---|
type | mysql | 数据库类型 |
hostname | 127.0.0.1 | 服务器地址 |
database | 无 | 数据库名称 |
username | 无 | 数据库用户名 |
passward | 无 | 数据库密码 |
hostport | 3306 | 数据库连接端口 |
charset | utf8 | 数据库默认编码 |
prefix | 无 | 数据库表的前缀 |
debug | TRUE | 数据库调试模式 |
①动态设置
public function demo()
{
$config = [
'type' => 'mysql',
'hostname' => 'localhost',
'username' => 'root',
'password' => 'root',
'database' =>'tp5',
];
//1.获取数据库的链接实例/对象
$link = Db::connect($config);
//2.用连接实例调用查询类的查询方法
$result = $link->table('staff')->select();
//3.输出查询结果
dump($result);
}
②动态配置连接字符串
mysql://root:1234@localhost:3306/thinkphp#usf8
数据库类型://用户名:密码@数据库地址:数据库端口/数据库名称#字符集
public function demo()
{
//1.获取数据库的链接实例/对象
$config = 'mysql://root:root@localhost:3306/tp5#utf8';
$link = Db::connect($config);
//2.用连接实例调用查询类的查询方法
$result = $link->table('staff')->select();
//3.输出查询结果
dump($result);
}
简化代码如下:
public function demo()
{
$result = Db::table('staff')->select();
dump($result);
}
!!!db()助手函数不支持惰性连接
Connection类:
①query(sql语句字符串,[参数绑定]):读操作—>select
②execute(sql语句字符串,[参数绑定]):写操作—>insert/update/delete
支持在原生查询的时候使用参数绑定,包括问号占位符或者命名占位符,参数绑定可以防止sql注入:
Db::query("select * from think_user where id=? AND status=?",[8,1]);
// 命名绑定
Db::execute("update think_user set name=:name where status=:status",['name'=>'thinkphp','status'=>1]);
Connection类实例通过入口类Db静态自动调用,不用显示写出
public function demo()
{
//1.查询操作:查询工资大于4000远的员工信息用命名占位符进行参数绑定
$sql = "select name,salary,dept from staff where salary > :salary";
$result = Db::query($sql,['salary'=>4000]);//数组中的第一个元素和第一个问号对应
dump($result);
//2.更新操作:将Id=3的记录,salary增加1000
$sql = "update staff set salary = salary+1000 where id=:id";
$result = Db::execute($sql,['id'=>3]);
dump($result);//返回受影响非记录条数
//3.插入操作:默认添加到表的尾部的
$sql = "insert into staff (name,sex,salary) values (:name,:sex,:salary)";
$result = Db::execute($sql,['name'=>'郭襄','sex'=>0,'salary'=>3500]);
dump($result);
//4.删除操作:id=4的记录删除
$sql = "delete from staff where id=:id";
$result = Db::execute($sql,['id'=>4]);
dump($result);
}
①链式操作的功能是快速生成查询条件
②链式操作中的所有的方法都来自于query查询类
③链式操作的返回值就是当前的查询对象
2个方法:
①where():AND条件
②whereOr():OR条件
三种格式:
①where(‘字段名’,‘表达式’,‘查询条件’)
public function index()
{
dump(
Db::table('staff')
->field(['name','salary'])
->where('id','>',2)
->select()
);
}
②where([‘字段名’=>[‘表达式’,‘查询条件’],…])
public function index()
{
dump(
Db::table('staff')
->field(['name','salary'])
->where([
'id'=>['>',2],
'salary'=>['>',3000]
])
->select()
);
}
③where(function($query){//链式查询语句;})
推荐方式:闭包的好处在于可以实现复杂的条件调用,且可以使用外部传入的变量
public function index()
{
dump(
Db::table('staff')
->field(['name','salary'])
->where(function ($query){
$query->where('id','>',1)
->where('salary','>',4000);
})
->select()
);
}
public function index()
{
$salary = 4000;
// dump(
// Db::table('staff')
// ->field(['name','salary'])
// ->where(function ($query) use ($salary){
// $query->where('id','>',1)
// ->where('salary','>',$salary);
// })
// ->select()
// );
dump(
Db::select(
function ($query) use ($salary) {
$query->table('staff')
->field(['name','salary'])
->where([
'id'=>['>',2],
'salary'=>['>',$salary]
]);
})
);
}
参考:TP5 完全开发手册
查询一个数据使用find
:
// table方法必须指定完整的数据表名
Db::table('think_user')->where('id',1)->find();
find 方法查询结果不存在,返回 null
查询数据集使用select
:
Db::table('think_user')->where('status',1)->select();
select 方法查询结果不存在,返回空数组
1.新增
insert(['字段'=>'值'])
插入单条记录
insertAll(['二维数组'])
同时插入多条记录
2.更新
update(['字段'=>'值'])
根据条件更新一条或多条记录
setInc/setDec('字段','步长')
如果字段类型是数字型,且每次更新时有规律的,则可以使用这种方式
setInc/setDec
支持延时更新,如果需要延时更新则传入第三个参数
下例中延时10秒,给score字段增加1
Db::table('think_user')->where('id', 1)->setInc('score', 1, 10);
setInc/setDec
方法返回影响数据的条数
3.读取
find(主键)
单条读取,以一维数组的形式返回
select(主键)
返回多条满足条件的记录,可以以二维数组的方式返回
4.删除
delete(主键)
根据条件进行删除
delete(true)
无条件删除,清空数据表(危险操作)
delete删除方法不支持闭包
1.value
获取某个字段的值
public function index()
{
//value('字段','默认值')
$result = Db::table('staff')->where('id',1)->value('name');
dump($result);
}
2.column
输出一列数据
public function index()
{
//value('字段','默认值')
$result = Db::table('staff')->where('id','>',1)->column('name','id');//column的第一个参数为值,第二个参数为键名
dump($result);
}
3.delete
删除数据
public function index()
{
//value('字段','默认值')
$result = Db::table('staff')
->delete(7);
return $result?'成功删除了'.$result.'条记录' : '删除失败';
}
模型是对实体的抽象描述,快速直观的展示出实体的特征。
TP5中的模型是指数据表(粗略理解)。
模型类中的属性与方法:
1.模型类中的属性和方法需要在基类Model中查看
2.Model.php类位于public/library/think/Model.php
3.该类是一个抽象类,不能被实例化,必须由子类继承并实现内部的全部抽象方法
模型与数据表的对应关系:
模型的属性与数据表的字段一一对应,数据表中的一行信息对应模型的一个实例。而模型的方法则定义了对当前数据表的一些操作。
区别:
1.分工不同:Db类负责数据表的访问,模型专注于业务逻辑的处理
2.返回值不同:Db访问返回数组,模型操作返回对象
联系:
模型最终仍需调用Db类完成数据表的查询操作。
模型可以看做是一种更高级别的抽象,最终的底层仍然需要依靠Db类完成数据表的增删改查操作。
1.手工创建:
在应用或模块下创建模型目录model,并在该目录下创建与数据表同名的类文件:如User.php对应user.dbf表。(首字母大写)
2.命令创建:
在当前项目目录下,用命令:php think make:model 模块名/模型名
,会自动创建指定位置和命名空间的空模型,并自动与数据表绑定;
3.模型创建完成后,会自动获取当前数据表名称$table
,表中所有字段信息$field
,主键$pk
和数据库配置信息$connection
.同时会自动继承基类Model中所有属性和方法,protected类型在本模型中使用,public类型还可以在控制器使用,静态方法大多直接用在控制器,进行CURD操作。
一、实例化调用:
1.用new生成模型对象
2.用模型对象处理相关业务
where('id',3)->find();
dump($result->getData('name'));
}
}
二、静态调用:
1.通过静态查询直接将一个空模型转为数据模型
2.再调用相关方法完成增删改查操作
getData('sex'));
}
}
三、不推荐使用助手函数model()和添加模型类后缀
1.控制器访问(外部)->用模型对象:$model
2.模型访问(内部)->用伪对象变量:$this
Cread/Update/Read/Delete
save()/saveAll()/update()
方法 | 说明 | 调用方法 | 返回值 |
---|---|---|---|
save($data=[]) |
添加单条 | 实例化 | 影响记录数 |
saveAll($data=[]) |
批量添加 | 实例化 | 模型对象数组 |
create($data=[]) |
单条添加 | 静态 | 模型对象 |
①数据创建过程可以触发很多操作,非Db类操作可比
②静态调用的实质其实仍是实例化调用,只是将CURD方法进行静态封装
③saveAll()
方法实际上是通过多次执行insert语句完成,很少用到
④理论上讲,通过模型向表中添加数据,尽可能都采用静态方式
name = '韦小宝';
$staff->sex = 1;
$staff->salary = 9000;
//3.执行数据添加操作
$result = $staff->save();
return $result ? '成功添加了'.$result.'条记录' : '添加失败';
}
}
'陈近南','salary'=>40000],
['name'=>'吴三桂','salary'=>60000],
['name'=>'陈圆圆','salary'=>8000],
];
//3.执行数据添加操作
$result = $staff->saveAll($data);
dump($result);
}
}
'林平之','sex'=>'1','salary'=>300
]);
dump($result->getData());
}
}
save()/saveAll()/update()
方法 | 说明 | 调用方法 | 返回值 |
---|---|---|---|
save($data=[],$where=[]) |
单条更新 | 实例化 | 影响记录数 |
saveAll($data=[].true ) |
批量更新 | 实例化 | 模型对象数组 |
update($data=[],$where=[],$field=[]) |
单条更新 | 静态 | 模型对象 |
1.不允许无条件更新,必须设置更新条件
2.可以将更新条件,如主键写在更新数据中,方法可以自动识别
3.更新条件可以使用闭包,完成更复杂的业务逻辑
8,
'name'=>'岳不群',
'sex'=>1
];
$staff->isUpdate(true)->save($data);
dump($staff->getData());
}
}
'张无忌',
'sex'=>1,
];
$where = [
'Id'=>13,
];
$staff->save($data,$where);
dump($staff->getData());
}
}
14,'name'=>'张无忌','sex'=>1],
['Id'=>15,'name'=>'赵敏','sex'=>0],
['Id'=>16,'name'=>'小昭','sex'=>1],
];
$staff->isUpdate(true)->saveAll($data);
dump($staff->getData());
}
}
'韦一笑','sex'=>1,'salary'=>5600
];
$where = ['id'=>24];
$field = ['name','sex'];
$result = Staff::update($data,$where,$field);
dump($result->getData());
}
}
'韦一笑','sex'=>1,'salary'=>5600
];
//更新条件使用闭包写法
//闭包支持外部传入的变量
$where = function ($query){
$query->where('Id',25);
};
$field = ['name','sex'];
$result = Staff::update($data,$where,$field);
dump($result->getData());
}
}
find()/select()/get()/all()
方法 | 调用方式 | 返回值 |
---|---|---|
find($where) 和get($where) |
实例化/静态 | 模型对象 |
select($where) 和all($where) |
实例化/静态 | 模型对象数组 |
1.原则来说,查询都应该采用静态查询方法
2.尽可能采用get()
和all()
方法代替find()
和selec()
3.牢记一条原则:一个模型对象实例应该唯一对应数据表的一条记录
field(['name','salary'])
-> where('id','=',3);
};
$result = $staff->find($where);
//$result = $staff->get($where);
dump($result->getData());
}
}
field(['name','salary'])
-> where('salary','>',10000);
};
$result = $staff->select($where);
//$result = $staff->all($where);
foreach ($result as $value) {
dump($value->getData());
}
}
}
field(['name','salary'])
-> where('salary','>',10000);
};
$result = $staff->all($where);
foreach ($result as $key => $value) {
// dump($value->getData());
echo '记录编号:'.($key+1).' | 姓名:'.$value->name.' | 工资:'.$value->salary.'
';
}
}
}
field(['name','salary'])
->where('id','=',2);
};
// $result = Staff::find($where);
$result = Staff::get($where);
dump($result->getData());
}
}
field(['name','salary'])
->where('id','>',2);
};
// $result = Staff::select($where);
$result = Staff::all($where);
foreach ($result as $value) {
dump($value->getData());
}
}
}
delete()和destroy()
方法 | 调用方式 | 返回值 |
---|---|---|
delete() | 实例化 | 受影响的记录数量 |
destroy(条件/闭包) | 静态 | 受影响记录数量 |
1.delete()
不要传任何参数,他只删除当前模型对象对应的记录
2.destroy()
中的删除条件,推荐采用闭包方式
3.推荐用软删除替代该方法,即用更新的方式来实现删除操作
where('id','>',12)
->where('sex','=',1)
->whereOr('salary','>',4000);
};
$value = Staff::destroy($where);
dump($value);
}
}
①模型的读取器
触发条件:当用模型对象读取表中字段值的时候
应用场景:日期时间字段、集合或枚举数据、数字状态与文本转换、字段拼接
设置位置:在模型中设置,访问属性通常为protected,不允许外部直接访问
方法名称:get属性名称Attr($name,$data=[])
get FieldName Attr($name,$data=[])
驼峰命名法,对应表中字段:field_name
②模型的修改器
触发条件:当用模型对象向数据表中新增记录或更新字段值的时候
应用场景:日期时间字段、集合或枚举数据、数字状态与文本转换、字段拼接
设置位置:在模型中设置,访问属性通常为protected,不允许外部直接访问
方法名称:set属性名称Attr($name,$data=[])
set FieldName Attr($name)
驼峰命名法,对应表中字段:field_name
$type
属性设置技巧字符串类型是默认的读取类型
'array', //以json格式写入,取出自动编码为array
'age' => 'integer', //该字段写入和输出的时候都会字段转换为整型
'salary' => 'float', //该字段写入和输出的时候都会自动转换为浮点型
'dept' => 'serialize', //自动序列化写入,读取的时候自动反序列化
'home' => 'json', //json_encode写入,读取时json_decode处理
'hiredate' => 'timestamp', //用strtotime转为时间戳写入,读出按$dateFormat格式输出
'birthday' => 'datetime' //读写都是按$dateFormat格式处理
];
?>
$insert/$update/$auto
属性配置技巧一、自动时间戳
1.模型中开启:protected $autoEriteTimestamp=true
2.在表中手工创建二个字段:create_time,update_time
3.用户自行新增和更新操作时,会自动将新增与更新时间写入表中
4.默认以时间戳格式写入,可以配置为:datatime格式
二、自动完成
1.$insert=['字段'=>'值',...];
//新增时自动插入到表中的
2.$update=['字段'=>'值',...];
//更新时自动更新字段值
3.$auto=['字段'=>'值',...];
//新增或更新时自动填入或更新字段值
通常要与类型自动转换属性:$type=['字段'=>'类型',...]
相配合
4500,
'hiredate'=>'2019-09-16',
];
// 新增自动完成列表
protected $insert = [
// 'sex'=>1,
'dept', //部门名称,根据员工性别sex字段的值确定
'hiredate'=>'2019-09-16',
];
// 更新自动完成列表
protected $update = [
'dept'=>'测试部',
];
protected $type = [
'hiredate'=>'timestamp',
];
protected function setDeptAttr($dept,$data)
{
if ($data['sex']) {
return $this->dept = '开发部';
}else{
return $this->dept = '客服部';
}
}
}
?>