数据访问在一个
框架的设计上面起着非常重要的作用,要理解
ThinkPHP的数据访问层首先要明白什么是Dao对象。
Dao是指Data Access Object (数据方法对象),Dao设计模式把底层的数据访问逻辑和业务逻辑分开,夹在业务层与数据层中间,用于
数据库访问和操作。可以针对单表和多表操作。ThinkPHP中的Dao对象属于建立在抽象数据库访问层之上的事务性对象。
什么是HashMap ? HashMap来源于Java,是一种哈希表,用途是把各个对象映射起来,实现了“键――值”对应的快速存取。
PHP本身并不支持HashMap,ThinkPHP中的HashMap对象采用数组方式模拟实现,其机理和HashMap的不同,但是接口和使用方法是一致的。HashMap在实现O/R Mapping的时候非常重要,在ThinkPHP框架中是一个非常重要的类库,通过简单的put和get方法存取对象属性。在保存数据对象的时候,ThinkPHP会自动把HashMap对象转换成相应的VO对象。
系统提供了VO对象和HashMap对象之间的相互转换方法。
业务逻辑一般都是对数据的访问和操作,为了兼容性考虑,ThinkPHP框架没有使用Adodb或者PDO(PHP5才内置支持)作为抽象数据库访问层,而是内置实现了一个抽象数据库访问层,当然这个抽象层的实现上也参考了部分目前比较先进的抽象数据库访问层框架,并且会保持不断完善。
抽象数据库访问层的关键类库在于数据库的公共访问类Db类,这个类是操作数据库的底层接口,换句话说,Db类不能够独立存在,必须有对应的数据库驱动类库,但是开发人员不能够跨过该类直接进行数据库操作的访问。目前系统支持的数据库包含有
MySQL、MySQLi、MsSQL、PgSQL、SqLite和Oracle,可以通过插件方式增加自己需要的数据库驱动,开发人员也可以按照规范编写自己的数据库驱动(甚至包括众多的嵌入式数据库的驱动)。
数据库的配置
文件有多种
定义方式:
第一种 在每个
应用的配置文件中定义
- //数据库设置
- define('DB_TYPE', 'mysql');define('DB_HOST', 'localhost');define('DB_NAME','web');define('DB_USER','root');define('DB_PWD','');define('DB_PORT','');
系统推荐使用该种方式,因为一般一个应用的数据库访问配置是相同的。
第二种 使用DSN方式在初始化Db类的时候传参数
- $db_dsn = “mysql://username:passwd@localhost:3306/DbName”;$db = new Db($db_dsn);
第三种 使用数组传参数
- $DSN = array(
-
'dbms' => 'mysql',-
'username' => 'username',-
'password' => 'password',-
'hostname' => 'localhost',-
'hostport' => '3306',-
'database' => 'dbname'-
);-
$db = new Db($DSN);
在初始化数据库公共类的时候,会根据dbms的值来定位数据库类型,并进行数据库连接,如果数据库驱动不存在或者连接失败,会抛出异常。
Db类的查询结果保存在数据集对象ResultSet中,并且支持数据查询的缓存操作。为了更加方便和直观,ThinkPHP还在抽象数据库访问层之上,构建了一个数据访问对象(Dao),采用了简单的OO-RDBMS mapping机制,把数据集对象ResultSet转换成Vo对象或者VoList对象,可以把数据表的一条记录看成是一个Vo对象
实例,对数据表的任何操作都是对Vo对象的操作。
接下来,让我们看下在Dao对象的一些使用例子。
- //实例化UserDao数据访问对象
- $userDao = new UserDao();
-
//首先要取得编号为$id的用户信息-
$userVo = $userDao->getById($id);-
//保存UserVo对象-
$userDao->save($userVo);-
//删除UserVo$userDao->delete($userVo);//取得用户所在的用户组$userDao->getUserGroup($userVo->id);
上面引用的getById、save、delete和getUserGroup方法就是一些简单的业务逻辑的封装,我们可以看到每个业务方法都通过一个Dao对象来调用,而不是通过Action控制器来直接调用。ThinkPHP把数据访问对象Dao来作为连接
控制器和数据对象的纽带。对于控制器来说,只需要知道,我应该调用那个逻辑访问方法,来获取我需要的数据,但是具体怎么访问数据库,以及中间还做了哪些操作,我不关心。因此,在控制器中应该尽量避免直接访问数据库,应该用事务的方式来看待Dao对象中的方法,因为可能其中不只包含一次数据库访问或者操作。
一般而言,Dao类中定义的方法是和视图无关的,返回的仅仅是数据,而没有任何表现层的元素。通常的,我们都是返回一个数值或者一个Vo对象、VoList对象,甚至是你需要的任何对象。相对而言,Dao对象中的开发工作是核心的工作,关注的是一个系统业务的实现,但是对数据的处理和一些校验工作是由控制器来完成的,保持Dao方法的单纯性能够尽可能地提高方法的重用性。
对于使用ThinkPHP框架的开发人员来说,系统已经在Dao基础类中封装了对数据表的CURD操作,对于这些操作,完全不需要编写任何
SQL语句,并且支持主键、自动增长类型和事务操作。
Dao基础类中主要定义了下列操作:
- 1、Add($Data[,$Table]) 新增一个数据对象
- $Data 可以是一个关联数组、Vo数据对象,也可以是一个Map对象
- $Table 可以指定数据表的名称,默认会根据当前的Dao对象来分析取得表名
- 2、Save($Data[,$Table]) 保存一个数据对象
- 该方法的用法类似于Add方法,只不过用于Update
- 3、DeleteById($Id[,$Table]) 根据主键的值来删除一个数据对象
- $Id 是数据对象的主键的值
- Dao类中有一个专门定义主键名称的属性$PK,默认为Id,如果需要可以设定为其它值
- 4、Delete($Condition[,$Table]) 根据条件Map删除数据对象
- $Condition 是一个HashMap对象或者条件字符串
- 5、getById($Id[,$Table,$Fields]) 根据主键得到Vo对象
- 6、find($Condition[,$Table,$Fields]) 根据条件查询取得Vo对象
- 7、findAll([$Condition,$Table,$fields,$order,$limit,$group,$having]) 根据条件查询取得VoList对象
- 8、getCount($condition[,$table]) 取得符合条件的记录数目
- 9、getSum($field[,$condition,$table]) 取得记录集中某个字段的总和
数据访问对象类中还实现了ResultSet对象的转换,把Db类中的查询结果转换成Vo或者VoList对象(这样的好处有很多,最起码知道自己在操作什么数据表,而不是和枯燥的数据集对象打交道,也便于
模板引擎的输出)。
数据访问对象类中另外一个非常实用的方法就是CreateVo方法,这个方法能够根据表单提交的数据自动创建出一个Vo对象。
- $dao = new UserVo();$user = $dao->createVo();
如果是编辑状态,那么需要使用createVo来获取编辑
页面提交的Vo对象。
- $user = $dao->createVo('edit');
数据缓存
ThinkPHP框架从0.8版本开始支持动态数据缓存,之前已经实现了模板缓存。
ThinkPHP的动态数据缓存有三层实现,第一层是Db类的查询数据集缓存,这层缓存是基于SQL指令的;第二层是由Dao类实现的Vo对象和VoList对象的缓存,这层缓存是基于Vo对象和分页VoList对象的;第三层是由控制器类实现的,在数据更新的时候能够自动更新Vo对象缓存,由于某些特殊原因,目前还没法支持VoList对象的缓存更新。
定义一个Dao类非常简单,对于某些应用,你甚至只需要定义一个空的Dao基础类的子类就可以了。
class UserDao extends Dao { }
一个简单的Dao方法定义如下:
- function forbid($condition,$table)
- {
- if(
FALSE === $this->db->execute('update '.$table.' set status=0 where status=1 and ('.$condition.')')){- return
false;- }else {
- return
True;- }
- }
Dao类中提供了对事务的支持,如果要使用事务操作,可以通过下面的方法
- startTrans()commit()rollback();