谈谈php里的DAO Model AR
这次要谈的3个关键字:DAO、Model、AR,是我们在做web应用时常见的几个概念,也被称作设计模式(design pattern),先简单看看它们的全拼和中文:
- DAO:Data Access Object 数据访问对象
- Model:数据模型
- AR:Active Record 活动记录
几乎所有的web开发框架在设计的时候,都或多或少用到了这些设计模式来实现了MVC中的M层,通过为开发者提供强有力的类库,简单便捷的完成数据库访问。
很多同学对这些概念的理解相对模糊,因此下面我将通过几个例子循序渐进的描述这3个概念,希望与大家分享与讨论我的认识。
M
这里的M就是MVC框架中的M,下面我会先通过DAO和Model两个设计模式来实现一个M层,它提供了对Mysql数据库中的Group表的访问能力。
Model
model是一个类,它生成的1个对象代表了数据库中的一行记录。既然要代表1行记录,那么它应该有若干和数据库列对应的属性,这里就拿一个Group表为例,看看Model类如何定义:
/**
* Object represents table 'groups'
*
* @author: http://phpdao.com
* @date: 2009-10-17 02:53
*/
class Group{ var $id;
var $name; }
?>
可见,Group就是一个Model类,它定义了2个属性对应了数据库表Group中的2个列,这个类的1个对象就代表数据库中的一行记录,就这么简单。
DAO
Data Access Object,数据访问对象,意思就是通过这个类的对象可以实现对数据库的真实访问。
前面我们也看到了,Model仅仅代表了一行数据库记录,但是没有任何与数据库打交道的代码,这是因为DAO才是真正负责与数据库进行通讯的"人"呐...
我们知道,对于任何一张表来说,它们都有一些统一的常见操作,例如:按主键查询,插入,查询,删除。
观察这些操作,我们可以知道无论是查询还是修改操作,其实都是在与数据库里的记录行交互,对应到程序里也就等价于之前看到的Model对象了。因此,我们基本可以想象到DAO的职责:
- 通过向DAO对象的新增/修改方法,传入model对象,实现对数据库中对应记录的新增/修改。
- 通过DAO对象的查询方法,从数据库读取数据,并返回model对象作为结果。
但是我们知道,数据库可能是Mysql,Mongodb,Oracle等等,因此DAO的实现可能不止一种,所以通常会为DAO定义一个通用的接口,并为不同的数据库提供不同的实现。这里,我们为Group model设计一个DAO的interface,无论任何数据库在实现时都应该实现这些接口:
/*
* Intreface DAO
*
* @author: http://phpdao.com
* @date: 2009-10-17 02:53
*/
interface GroupsDAO{ /**
* Get Domain object by primry key
*
* @param String $id primary key
* @Return Groups
*/
public function load($id); /**
* Get all records from table
*/
public function queryAll(); /**
* Get all records from table ordered by field
* @Param $orderColumn column name
*/
public function queryAllOrderBy($orderColumn); /**
* Delete record from table
* @param group primary key
*/
public function delete($id); /**
* Insert record to table
*
* @param Groups group
*/
public function insert($group); /**
* Update record in table
*
* @param Groups group
*/
public function update($group); /**
* Delete all rows
*/
public function clean(); public function queryByName($value); public function deleteByName($value); }
?>
现在,我们继承GroupDAO接口,为Group表实现访问Mysql的DAO类:
/*
* Class that operate on table 'groups'. Database Mysql.
*
* @author: http://phpdao.com
* @date: 2009-10-17 02:53
*/
class GroupsMySqlDAO implements GroupsDAO{ /**
* Get Domain object by primry key
*
* @param String $id primary key
* @return GroupsMySql
*/
public function load($id){
$sql = 'SELECT * FROM groups WHERE id = ?';
$sqlQuery = new SqlQuery($sql);
$sqlQuery->setNumber($id);
return $this->getRow($sqlQuery);
} /**
* Get all records from table
*/
public function queryAll(){
$sql = 'SELECT * FROM groups';
$sqlQuery = new SqlQuery($sql);
return $this->getList($sqlQuery);
} /**
* Get all records from table ordered by field
*
* @param $orderColumn column name
*/
public function queryAllOrderBy($orderColumn){
$sql = 'SELECT * FROM groups ORDER BY '.$orderColumn;
$sqlQuery = new SqlQuery($sql);
return $this->getList($sqlQuery);
} /**
* Delete record from table
* @param group primary key
*/
public function delete($id){
$sql = 'DELETE FROM groups WHERE id = ?';
$sqlQuery = new SqlQuery($sql);
$sqlQuery->setNumber($id);
return $this->executeUpdate($sqlQuery);
} /**
* Insert record to table
*
* @param GroupsMySql group
*/
public function insert($group){
$sql = 'INSERT INTO groups (name) VALUES (?)';
$sqlQuery = new SqlQuery($sql); $sqlQuery->set($group->name); $id = $this->executeInsert($sqlQuery);
$group->id = $id;
return $id;
} /**
* Update record in table
*
* @param GroupsMySql group
*/
public function update($group){
$sql = 'UPDATE groups SET name = ? WHERE id = ?';
$sqlQuery = new SqlQuery($sql); $sqlQuery->set($group->name); $sqlQuery->setNumber($group->id);
return $this->executeUpdate($sqlQuery);
} /**
* Delete all rows
*/
public function clean(){
$sql = 'DELETE FROM groups';
$sqlQuery = new SqlQuery($sql);
return $this->executeUpdate($sqlQuery);
} public function queryByName($value){
$sql = 'SELECT * FROM groups WHERE name = ?';
$sqlQuery = new SqlQuery($sql);
$sqlQuery->set($value);
return $this->getList($sqlQuery);
} public function deleteByName($value){
$sql = 'DELETE FROM groups WHERE name = ?';
$sqlQuery = new SqlQuery($sql);
$sqlQuery->set($value);
return $this->executeUpdate($sqlQuery);
} /**
* Read row
*
* @return GroupsMySql
*/
protected function readRow($row){
$group = new Group(); $group->id = $row['id'];
$group->name = $row['name']; return $group;
} protected function getList($sqlQuery){
$tab = QueryExecutor::execute($sqlQuery);
$ret = array();
for($i=0;$i $ret[$i] = $this->readRow($tab[$i]);
}
return $ret;
} /**
* Get row
*
* @return GroupsMySql
*/
protected function getRow($sqlQuery){
$tab = QueryExecutor::execute($sqlQuery);
return $this->readRow($tab[0]);
} /**
* Execute sql query
*/
protected function execute($sqlQuery){
return QueryExecutor::execute($sqlQuery);
} /**
* Execute sql query
*/
protected function executeUpdate($sqlQuery){
return QueryExecutor::executeUpdate($sqlQuery);
} /**
* Insert row to table
*/
protected function executeInsert($sqlQuery){
return QueryExecutor::executeInsert($sqlQuery);
}
}
?>
我们定义了GroupMysqlDAO类并实现了所有的接口方法,2个比较典型的DAO行为如下:
- load($id)方法:传入主键id,从mysql查询回记录,并最终通过readRow($row)方法将数据库的记录行转换成了一个Group model对象返回。
- insert($group)方法:传入一个Group model对象,方法中将其name属性取出拼成insert语句,最终插入到了mysql中。
这里见到的SqlQuery和QueryExecutor对象,都是对Mysql基础API的进一步封装,因此不做深入,可以认为它们与PDO库功能类似。
通过这个DAO类的对象,我们可以非常方便的操作Group model对象来与mysql进行数据交换,对于上述的简单数据库操作来说,开发者根本不需要写任何SQL即可完成开发,仅仅利用GroupMysqlDAO和Group2个类既可完成业务逻辑的开发。
然而现实情况并没有这么简单,通常我们需要按其他索引进行数据库查询或者排序,按照一些复杂的条件进行数据库的记录批量更新,甚至进行多表Join,这些能力当前的DAO并没有实现,因此我们自然想到对这个GroupMysqlDAO类进行扩展,添加一些我们想要的函数,这些函数可以接受任意参数,返回任意值,这里我并不考虑新函数的通用性(例如排序规则是用户传入的)。
这里拿一个另外的Content model为例,我们继承它的DAO添加2个特殊的查询方法,并且添加1个联查User表的方法,它返回若干UserContent model对象,然而这个UserContent model对象并不对应数据库中真实存在的表,这是没有任何问题的:
/*
* Class that operate on table 'content'. Database Mysql.
* Here you can write non standard sql queries
*
* @author: http://phpdao.com
* @date: 2009-10-17 03:43
*/
class ContentMySqlExtDAO extends ContentMySqlDAO{ function queryByContentAndCreatedBy($content, $createdBy){
$sql = "SELECT * FROM content WHERE title like '%".$content."%' AND created_by=?";
$sqlQuery = new SqlQuery($sql);
$sqlQuery->setNumber($createdBy);
return $this->getList($sqlQuery);
} /**
* Get rows count where column created_by is equal to method param
*/
function getCountByCreatedBy($createdBy){
$sql = "SELECT count(*) FROM content WHERE created_by=?";
$sqlQuery = new SqlQuery($sql);
$sqlQuery->setNumber($createdBy);
return $this->querySingleResult($sqlQuery);
} /**
* This method returns array of object UserContent.
* Here sql query gets data from two tables.
* Developer must loop by variable tab and create for all rows objec UserContent
* and add this object to new array
*/
function getUserNameAndContentTitle(){
$sql = "SELECT u.name, c.title FROM users u, content c WHERE c.created_by=u.id";
$sqlQuery = new SqlQuery($sql);
$tab = $this->execute($sqlQuery);
$ret = array();
for($i=0;$i $userContent = new UserContent();
$userContent->username = $tab[$i]["name"];
$userContent->title = $tab[$i]["title"];
$ret[$i] = $userContent;
}
return $ret;
}
}
/**
* Non standard transfer object
*/
class UserContent{
var $username;
var $title;
}
?>
综上,
1,DAO对象实现了Model和数据库Row之间的互相转化能力。
2,Model不一定必须对应数据库中真实存在的表,但它通常应该对应。
3,DAO的实现并不一定是访问数据库,它的数据来源可以是任意的,例如一个远程的网络服务,只要通过DAO接口可以实现model与数据源之间的互相转换既可,这就是它的抽象能力所在了。
4,DAO+model是实现M层的最基础模式。
AR
Active Record是一种在DAO+model基础上演化出来的东西,像一个混血儿。
它首先是一个model,也就是AR的1个对象对应了数据库中的一行记录,它有若干属性对应了数据库中的列。
此前我们知道,DAO和model是2个类,相当于在2个层级上,彼此分离。而AR则将DAO的能力挪到了model本身,也就是说原本这样的调用:
$model = new Model(); $model->name = "owen"; $dao = new Dao(); $dao->insert($model);
现在变成了这样:
$ar = new AR(); $ar->name = "owen"; $ar->insert();
从直观上来看,AR模式使用起来更加方便,如果你仔细观察2者的差异,你会发现AR模式并不神秘,你只需要简单的将DAO和Model组合一下就可以实现AR了,例如:
class AR extens Model {
// 继承自model的属性
// public $id;
// public $name; // dao对象
private static $dao_ = new Dao(); // 封装dao方法
public function insert() {
self::$dao_->insert($this);
}
}
- 我们让AR继承model,这样AR类的对象就可以进行属性赋值:$ar->name = "owen" 了。
- 其次,我们将DAO放在static属性实现单例,因为它仅仅是一个工具类。
- 为AR类添加实例方法insert,给dao对象传入$this(相当于$model),这样通过:$ar->insert() 既可完成数据的插入。
无论是DAO还是AR,其实都可以实现更加通用的接口,例如:查询可以传入条件,更新/删除支持传入的条件批量更新(本文仅支持1个model对象的更新),并且不再针对具体的model(本文的DAO竟然只针对Group model)。
另外,现在主流思路一般是:针对关系型数据库实现一套DAO/AR,它们的接口尽量通用和全面,底层则通过PDO进行数据库访问的实现统一。对于非关系型数据库,则分别实现自己的DAO/AR类。
更多文章无法转载到cnblog,如果喜欢我的博客可以直接访问:鱼儿的博客
谈谈php里的DAO Model AR的更多相关文章
- mybatis generator cmd 终端命令 生成dao model mapper
mybatis generator cmd 终端命令 生成dao model mapper 文件包下载 mybatis-generator-core-1.3.2.jar 下载地址:https://gi ...
- java项目 里的DAO,model,service, IMPL含义
在一般工程中 基本上都会出现上述的字眼首先 DAO 提供了应用程序与数据库之间的操作规范 和操作 用于通常数据库的增删查改 一般如果使用框架 都是由框架自动生成,提高访问效率和便于快速开发.hiber ...
- Qt的Model/View Framework解析(数据是从真正的“肉(raw)”里取得,Model提供肉,所以读写文件、操作数据库、网络通讯等一系列与数据打交道的工作就在model中做了)
最近在看Qt的Model/View Framework,在网上搜了搜,好像中文的除了几篇翻译没有什么有价值的文章.E文的除了Qt的官方介绍,其它文章也很少.看到一个老外在blog中写道Model/Vi ...
- MyBatis generator 生成生成dao model mappper
MyBatis GeneratorXML配置文件参考 在最常见的用例中,MyBatis Generator(MBG)由XML配置文件驱动. 配置文件告诉MBG: 如何连接到数据库 什么对象要生成,以及 ...
- idea集成 MyBatis Generator 插件,自动生成dao,model,sql map文件
1.集成到开发环境中 以maven管理的功能来举例,只需要将插件添加到pom.xml文件中即可.(注意此处是以plugin的方式,放在<plugins></plugins>中间 ...
- 使用IDEA springboot 如何通过mybatis-generator自动生成mapper dao model
第一步:在maven工程当中的resource下面,创建generatorConfig.xml文件. 务必注意创建的位置!!! <?xml version="1.0" enc ...
- 谈谈php里的IOC控制反转,DI依赖注入
理论 发现问题 在深入细节之前,需要确保我们理解"IOC控制反转"和"DI依赖注入"是什么,能够解决什么问题,这些在维基百科中有非常清晰的说明. 控制反转(In ...
- 谈谈django里的Contex和RequestContext---向模板里添加全局变量
一直很想仔细研究一下,我在django模板里,可以直接访问变量user, request之类的变量,哪里来的,到底都有哪些?这会儿周五,我有空来仔细看看代码. 模拟一下需求: 我们做一个在线商城,需要 ...
- JSP DAO(Model)
示例代码: 1. Users类 package com.po; public class Users { private String username; private String passwor ...
随机推荐
- 承接 AutoCAD 二次开发 项目
本人有多年的CAD开发经验,独立完成多个CAD二次开发项目.熟悉.net及Asp.net开发技术,和Lisp开发技术. 现在成立了工作室,独立承接CAD二次开发项目.结项后提供源码及开发文档,有需要的 ...
- [VijosP1656]萌萌赶考 题解
题目大意: 有一个地图,有障碍,不能重复经过一点(但起点可以),判断能否恰好在t时刻从起点到达终点. 思路: 一开始DFS一遍,30分,于是要有优化减枝.最重要的是从起点到终点的距离的奇偶性是与起点与 ...
- 浅谈我对 jQuery 的了解
总述 0 获取 jQuery 对象 1 对象跳转 2 方法调用 3 常用API 4 $(…); 5 jQuery 对象获取 6 Data 相关方法 7 选择器 8 基本的过滤器 9 内容过滤选择器 1 ...
- 第一章 DeepLab的创作动机
这一段时间一直在做深度学习方面的研究,目前市场上的深度学习工具主要分为两大块.一块是基于Python语言的theano:另一块是可以在多个语言上使用并能够在GPU和CPU之间随意切换的Caffe.但是 ...
- OpenGL入门
OpenGL是个啥... 网上资料挺多的,今天在codeblocks配置了一下..抄了一会书上的代码,还挺有意思的. 首先,从官网把glut的包给下载下来,点这里. 以下内容从网上抄的: 将glut. ...
- 对Hibernate的理解
---恢复内容开始--- 一.面向对象设计的软件内部运行过程可以理解成就是不断创建各种新对象,建立对象之间的关系,调用对象的方法来改变各个对象的状态和对象消亡的过程.不管程序运行的过程和操作怎么样,本 ...
- LabVIEW 吸星大法 - 看见的好东西都是我的(上篇)
前言 写了多年的LabVIEW程序,你是否面临这样的问题 总是在做一些重复的工作,感觉很没有意思: 总在不停的写代码,做类似的控件,实现相同的功能,丝毫没有成就感: 总在天加班,没有时间去提高自己; ...
- #iOS问题记录#关于NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9801)
响应Apple的号召,将APP里的HTTP请求全部升级为HTTPS,一切配置OK,正常的请求也没问题: 但,当使用SDwebImg缓存图片时,遇到了标题写的问题: 根据资料得: 这个问题的出现是因为i ...
- FastReport.Net 常用功能总汇
一.常用控件 文本框:输入文字或表达式 表格:设置表格的行列数,输入数字或表达式 子报表:放置子报表后,系统会自动增加一个页面,你可以在此页面上设计需要的报表.系统在打印处理时,先按主报表打印,当碰到 ...
- ubuntu14.04上Virtualbox安装win7(使用Ghost镜像安装,启用USB设备支持,设置共享目录)
由于某些软件只有windows版本,于是只好安装个虚拟机win7 /**************************安装*************************************/ ...