DAO

DAO(Data Access Object) 即数据访问对象,封装所有对数据源进行操作的 API。以数据库驱动的应用程序为例,通常数据库中的一张表,对应的会有一个 Dao 类去操作这个数据库表。

通用的DAO基类

框架中定义了基础 DAO 接口 GeneralDaoInterface,以及对应的实现:GeneralDaoImplGeneralDaoInterface 接口如下,定义了常用的增删改查的数据操作方法。

  1. <?php
  2. namespace Codeages\Biz\Framework\Dao;
  3. interface GeneralDaoInterface
  4. {
  5. public function create($fields);
  6. public function update($id, array $fields);
  7. public function delete($id);
  8. public function get($id);
  9. public function search($conditions, $orderBy, $start, $limit);
  10. public function count($conditions);
  11. public function wave(array $ids, array $diffs);
  12. }

我们在声明自己的DAO接口时,可以继承 GeneralDaoInterface,例如:

  1. use Codeages\Biz\Framework\Dao\GeneralDaoInterface;
  2. interface ExampleDao extends GeneralDaoInterface
  3. {
  4. public function getByName($name);
  5. }

同样,在编写DAO实现类时,我们继承 GeneralDaoImpl 类,例如:

  1. <?php
  2. namespace Biz\Dao\Impl;
  3. use Codeages\Biz\Framework\Dao\GeneralDaoImpl;
  4. use Biz\Dao\ExampleDao;
  5. class ExampleDaoImpl extends GeneralDaoImpl implements UserDao
  6. {
  7. protected $table = 'example';
  8. public function getByName($name)
  9. {
  10. return $this->getByField('name', $name);
  11. }
  12. public function declares()
  13. {
  14. return array(
  15. 'timestamps' => array('created_time', 'update_time'),
  16. 'serializes' => array(),
  17. 'orderbys' => array(),
  18. 'conditions' => array(
  19. 'type = :type',
  20. ),
  21. );
  22. }
  23. }

其中属性 $table 表明此 Dao 类所对应的数据库表名。每个 DAO 类,须申明 declares() 方法,该方法返回一个 array 类型的配置:

timestamps

类型: array 必须: 否

定义调用 createupdate 方法时自动更新的时间戳字段。调用 create 方法时会自动更新 timestamps 数组中声明的第1、2个字段的值;调用update 方法时会自动更新第2个字段的值。

serializes

类型: array 必须: 否

定义需序列化的字段,序列化方式有 json, delimiter, php

orderbys

类型:array 必须: 否

定义可排序的字段。

conditions

类型:array 必须: 否

定义可被 search 方法调用的查询条件。例如:

  1. public function declares()
  2. {
  3. return array(
  4. 'conditions' => array(
  5. 'id = :id',
  6. 'id IN (:ids)',
  7. 'id != :not_id',
  8. 'id NOT IN (:not_ids)',
  9. 'updatedTime >= :updatedTime_GTE',
  10. 'updatedTime > :updatedTime_GT',
  11. 'updatedTime <= :updatedTime_LTE',
  12. 'updatedTime < :updatedTime_LT',
  13. 'title LIKE :titleLike', //模糊查询, 相当于%titleLike%
  14. 'title PRE_LIKE :titlePrefixLike', //前缀模糊查询, 相当于titlePrefixLike%
  15. 'title SUF_LIKE :titleSuffixLike', //后缀模糊查询, 相当于%titleSuffixLike
  16. ),
  17. );
  18. }

命名约定

通常 Dao 类中,只会存在一种数据对象,所以方法名命名的时候我们约定省略名词,即由原先的动词+名词的方式,变为只有动词的方式。其他约定有:

  • 数据库如选用 MySQL ,请使用 Innodb 引擎;每个数据表都应定义递增型的 id 主键字段;
  • 查询单行数据,方法名以 get 开头;
  • 查询多行数据,方法名以 find 开头;
  • 查询一列数据的,方法名以 pick 开头;
  • 根据指定条件查询用 By 字段;如根据主键 id 查询,则省略 ById;多个条件用 And 连接;方法参数的顺序跟方法名的查询条件一致;
  • 分页查询多行数据,以 $start, $limit 作为分页参数,加在方法参数的末尾;$start 表示要查询的起始行数,$limit 表示要查询的行数。
    命名示例
方法说明
get($id)根据主键 id 查询单行数据
getByEmail($email)根据 Email 字段查询单行数据
getByNameAndType($name, $type)根据 NameType 字段查询单行数据
pickNamesByIds根据多个 id 获取 name 列数据
findByIds(array $ids)根据多个 id 查询多行数据
findByType($type, $start, $limit)根据 Type 分页查询多行数据

缓存

DAO 可启用 Redis 缓存,在启用缓存之前,需先配置 Redis。配置项有:

dao.cache.enabled

开启/关闭 DAO 的 Redis 缓存。例:

  1. $biz['dao.cache.enabled'] = true; // true:开启 false: 关闭

dao.cache.strategy.default

DAO Cache 的全局默认缓存策略,默认为 TableStrategy。设置无默认缓存策略:

  1. $biz['dao.cache.strategy.default'] = null;

在无默认缓存策略模式下,每个 DAO 需各自指定缓存策略。

dao.cache.array_storage

默认关闭,当设置 dao.cache.array_storage 后,每个请求内,会将 DAO 的 get 结果缓存到数组中,以加快多次调用 get 请求。程序运行在 PHP-FPM 模式下,可开启。在命令行,或者 Swoole 等服务进程中,请勿开启。

  1. $biz['dao.cache.array_storage'] = function() {
  2. return new Codeages\Biz\Framework\Dao\ArrayStorage();
  3. };

缓存策略

框架实现了两种缓存策略,表级 TableStrategy 和行级 RowStrategy

TableStrategy

表级策略,适用于Web类应用。DAO会缓存所有 getfindsearchcount 等方法的数据。一旦有调用 update, delete, wave 等方法时,就清空所有该 DAO 的缓存。

为提高缓存效率,减少不必要的 Cache 清除操作,可在 DAO 的 declares 方法中声明 wave_cahceable_fields,指定哪些字段执行 wave 操作时,不清除缓存。该配置,可以用在非核心业务字段上,例如查看数 viewNum,有强业务逻辑的字段,请勿使用该配置,否则可能会破坏业务逻辑。

RowStrategy

行级策略,适用于 API 类的应用,大部分场景下只查询单行记录。该策略需通过注解的方式声明。例如:

  1. <?php
  2. use Codeages\Biz\Framework\Dao\Annotation\CacheStrategy;
  3. use Codeages\Biz\Framework\Dao\Annotation\RowCache;
  4. /**
  5. * @CacheStrategy("Row")
  6. */
  7. class ExampleDaoImpl extends GeneralDaoImpl implements ExampleDao
  8. {
  9. /**
  10. * @RowCache
  11. */
  12. public function getByName($name)
  13. {
  14. return $this->getByFields(array('name' => $name));
  15. }
  16. /**
  17. * @RowCache
  18. */
  19. public function getByCode($code)
  20. {
  21. return $this->getByFields(array('code' => $code));
  22. }
  23. }
  • @CacheStrategy("Row") 表示当前 DAO 的 Cache 策略为 RowStrategy
  • @RowCache 表示当前方法会被缓存。在 RowStrategy 的 DAO 下,@RowCache 只能用于 get 开头,查询单行数据的方法中。

注意

RowStrategy 下的 DAO,在调用 update 方法时,第一个参数只能是int型的 id,如果传入的是特定的查询条件,那么 update 将无法清除相关缓存。