yidas/codeigniter-model

CodeIgniter 3 ORM 基础模型模式,包含 My_model 示例

2.19.3 2023-08-29 11:01 UTC

README

CodeIgniter 模型


CodeIgniter 3 Active Record (ORM) 标准模型支持读写连接

Latest Stable Version License

此 ORM 模型扩展已收集到 yidas/codeigniter-pack,这是一个完整的 Codeigniter 框架解决方案。

特性

此包提供基础模型,扩展了 CI_Model,并提供完整的 CRUD 方法,使 CodeIgniter 应用程序中的数据库交互更加容易和快速。

概要

演示

ActiveRecord (ORM)

$this->load->model('Posts_model');

// Create an Active Record
$post = new Posts_model;
$post->title = 'CI3'; // Equivalent to `$post['title'] = 'CI3';`
$post->save();

// Update the Active Record found by primary key
$post = $this->Posts_model->findOne(1);
if ($post) {
    $oldTitle = $post->title; // Equivalent to `$oldTitle = $post['title'];`
    $post->title = 'New CI3';
    $post->save();
}

该模式类似于 Yii2 Active RecordLaravel Eloquent

使用查询构建器进行查找

find() 方法开始使用 CodeIgniter 查询构建器,模型将自动加载其自身的数据库连接和数据表。

$records = $this->Posts_model->find()
    ->select('*')
    ->where('is_public', '1')
    ->limit(25)
    ->order_by('id')
    ->get()
    ->result_array();

CRUD

$result = $this->Posts_model->insert(['title' => 'Codeigniter Model']);

// Find out the record which just be inserted
$record = $this->Posts_model->find()
  ->order_by('id', 'DESC')
  ->get()
  ->row_array();
  
// Update the record
$result = $this->Posts_model->update(['title' => 'CI3 Model'], $record['id']);

// Delete the record
$result = $this->Posts_model->delete($record['id']);

要求

此库需要以下条件

  • PHP 5.4.0+
  • CodeIgniter 3.0.0+

安装

\application 文件夹下运行 Composer,以您的 Codeigniter 项目

composer require yidas/codeigniter-model

检查 Codeigniter application/config/config.php

$config['composer_autoload'] = TRUE;

您可以将供应商路径自定义到 $config['composer_autoload']

配置

安装后,yidas\Model 类即可使用。只需创建一个模型直接扩展 yidas\Model

class Post_model extends yidas\Model {}

然后,此模型即可使用,例如:$this->PostModel->findOne(123);

然而,您应用中如主键等表的架构可能与默认架构不同,为每个模型定义重复的架构非常麻烦。我们建议您将 My_model 扩展为 yidas\Model

使用 My_model 扩展每个模型的基础模型

您可以使用 My_model 来扩展 yidas\Model,然后在 Codeigniter 应用程序中让每个模型扩展 My_model

1. 创建一个扩展 yidas\ModelMy_model,并配置以适应您常见的表架构

class My_model extends yidas\Model
{
    protected $primaryKey = 'sn';
    const CREATED_AT = 'created_time';
    const UPDATED_AT = 'updated_time';
    // Customized Configurations for your app...
}

2. 在应用程序中创建每个扩展 My_model 的模型,并为其配置自己的表

class Post_model extends My_model
{
    protected $table = "post_table";
}

3. 使用扩展的每个模型进行库操作

$this->load->model('post_model', 'PostModel');

$post = $this->PostModel->findOne(123);

带有文档的 My_model 示例

定义模型

要开始,让我们创建一个扩展 yidas\Model 或通过 My_model 的模型,然后定义每个模型以适应其需求。

表名

按照惯例,类名的“snake case”形式(小写字母,末尾不带下划线 _model)将被用作表名,除非显式指定了另一个名称。因此,在这种情况下,Model 假设 Post_model 模型存储在 post 表中的记录。您可以通过在模型上定义表属性来指定自定义表。

// class My_model extends yidas\Model
class Post_model extends My_model
{
    protected $table = "post_table";
}

您可以为模型设置表别名,例如定义 protected $alias = 'A1';

表名猜测规则

在我们的模式中,模型类和表之间的命名是相同的,无论使用单数还是复数名称都支持。

获取表名

您可以从每个模型中获取表名。

$tableName = $this->PostModel->getTable();

主键

您可以通过定义受保护的 $primaryKey 属性来覆盖此约定。

class My_model extends yidas\Model
{
    protected $primaryKey = "sn";
}

正确设置模型的主键对于 Active Record (ORM) 是必要的。

时间戳

默认情况下,Model 预期在您的表上存在 created_atupdated_at 列。如果您不希望这些列由基础模型自动管理,请在模型上将 $timestamps 属性设置为 false

class My_model extends yidas\Model
{
    protected $timestamps = false;
}

如果您需要自定义时间戳的格式,请在模型上设置 $dateFormat 属性。该属性确定日期属性如何在数据库中存储。

class My_model extends yidas\Model
{
    /**
     * Date format for timestamps.
     *
     * @var string unixtime(946684800)|datetime(2000-01-01 00:00:00)
     */
    protected $dateFormat = 'datetime';
}

如果您需要自定义存储时间戳所用的列名,您可以在模型中设置 CREATED_ATUPDATED_AT 常量。

class My_model extends yidas\Model
{
    const CREATED_AT = 'created_time';
    const UPDATED_AT = 'updated_time';
}

此外,您还可以通过将其设置为空来自定义关闭特定列的时间戳行为。

class My_model extends yidas\Model
{
    const CREATED_AT = 'created_time';
    const UPDATED_AT = NULL;
}

数据库连接

默认情况下,所有模型都将使用为您的应用程序配置的默认数据库连接 $this->db。如果您想为模型指定不同的连接,请使用 $database 属性。

class My_model extends yidas\Model
{
    protected $database = 'database2';
}

更多数据库连接设置: 读取 & 写入连接

其他设置

class My_model extends yidas\Model
{
    // Enable ORM property check for write
    protected $propertyCheck = true;
}

基本用法

上面的用法示例是在模型外调用模型,例如在控制器中。

$this->load->model('post_model', 'Model');

如果您在模型本身中调用方法,只需像调用模型一样调用 $this。例如,$this->find()... 对应于 find()

方法

find()

为查询目的创建一个具有模型功能的现有 CI Query Builder 实例。

public CI_DB_query_builder find(boolean $withAll=false)

示例

$records = $this->Model->find()
    ->select('*')
    ->where('is_public', '1')
    ->limit(25)
    ->order_by('id')
    ->get()
    ->result_array();
// Without any scopes & conditions for this query
$records = $this->Model->find(true)
    ->where('is_deleted', '1')
    ->get()
    ->result_array();
    
// This is equal to find(true) method
$this->Model->withAll()->find();

从模型开始调用 find() 后,它返回原始的 CI_DB_query_builder 以进行链式操作。查询构建器可以参考 CodeIgniter 查询构建器类文档

查询构建器实现

您可以将查询构建器分配给变量以处理附加条件,而不是使用 $this->Model->getBuilder()

$queryBuilder = $this->Model->find();
if ($filter) {
    $queryBuilder->where('filter', $filter);
}
$records = $queryBuilder->get()->result_array();

reset()

使用模型重置 CI Query Builder 实例。

public self reset()

示例

$this->Model->reset()->find();

insert()

使用此记录的属性值将一行具有时间戳功能插入关联的数据库表。

public boolean insert(array $attributes, $runValidation=true)

示例

$result = $this->Model->insert([
    'name' => 'Nick Tsai',
    'email' => 'myintaer@gmail.com',
]);

batchInsert()

使用此记录的属性值将一批具有时间戳功能的行插入关联的数据库表。

public integer batchInsert(array $data, $runValidation=true)

示例

$result = $this->Model->batchInsert([
     ['name' => 'Nick Tsai', 'email' => 'myintaer@gmail.com'],
     ['name' => 'Yidas', 'email' => 'service@yidas.com']
]);

replace()

使用此记录的属性值替换具有时间戳功能的行到关联的数据库表。

public boolean replace(array $attributes, $runValidation=true)

示例

$result = $this->Model->replace([
    'id' => 1,
    'name' => 'Nick Tsai',
    'email' => 'myintaer@gmail.com',
]);

update()

使用时间戳功能将更改保存到所选记录的关联数据库表中。

public boolean update(array $attributes, array|string $condition=NULL, $runValidation=true)

示例

$result = $this->Model->update(['status'=>'off'], 123)
// Find conditions first then call again
$this->Model->find()->where('id', 123);
$result = $this->Model->update(['status'=>'off']);
// Counter set usage equal to `UPDATE mytable SET count = count+1 WHERE id = 123`
$this->Model->getDB()->set('count','count + 1', FALSE);
$this->Model->find()->where('id', 123);
$result = $this->Model->update([]);

注意:您需要从模型调用update,而不是从CI-DB构建链调用,错误的示例代码

$this->Model->find()->where('id', 123)->update('table', ['status'=>'off']);

batchUpdate()

将批量更新查询合并为查询字符串。

public integer batchUpdate(array $dataSet, boolean $withAll=false, interger $maxLength=4*1024*1024, $runValidation=true)

示例

$result = $this->Model->batchUpdate([
    [['title'=>'A1', 'modified'=>'1'], ['id'=>1]],
    [['title'=>'A2', 'modified'=>'1'], ['id'=>2]],
]);

delete()

使用时间戳功能将所选记录从关联数据库表中删除。

public boolean delete(array|string $condition=NULL, boolean $forceDelete=false, array $attributes=[])

示例

$result = $this->Model->delete(123)
// Find conditions first then call again
$this->Model->find()->where('id', 123);
$result = $this->Model->delete();
// Force delete for SOFT_DELETED mode 
$this->Model->delete(123, true);

getLastInsertID()

在执行数据库插入时获取插入ID。

示例

$result = $this->Model->insert(['name' => 'Nick Tsai']);
$lastInsertID = $this->Model->getLastInsertID();

getAffectedRows()

在执行“写入”类型查询(插入、更新等)时获取受影响行数。

public integer|string getLastInsertID()

示例

$result = $this->Model->update(['name' => 'Nick Tsai'], 32);
$affectedRows = $this->Model->getAffectedRows();

count()

从查询中获取计数。

public integer count(boolean $resetQuery=true)

示例

$result = $this->Model->find()->where("age <", 20);
$totalCount = $this->Model->count();

setAlias()

设置表别名。

public self setAlias(string $alias)

示例

$query = $this->Model->setAlias("A1")
    ->find()
    ->join('table2 AS A2', 'A1.id = A2.id');

ACTIVE RECORD (ORM)

Active Record提供了一种面向对象的接口,用于访问和操作存储在数据库中的数据。Active Record模型类与数据库表关联,Active Record实例对应于该表的一行,Active Record实例的属性表示该行特定列的值。

Active Record (ORM)支持插入和更新等时间戳事件。

插入

要在数据库中创建新记录,创建新的模型实例,设置模型上的属性,然后调用save方法

$this->load->model('Posts_model');

$post = new Posts_model;
$post->title = 'CI3';
$result = $post->save();

更新

save方法还可以用于更新数据库中已存在的模型。要更新模型,您应检索它,设置您希望更新的任何属性,然后调用save方法

$this->load->model('Posts_model');

$post = $this->Posts_model->findOne(1);
if ($post) {
    $post->title = 'New CI3';
    $result = $post->save();
}

删除

要删除Active Record,请在模型实例上调用delete方法

$this->load->model('Posts_model');

$post = $this->Posts_model->findOne(1);
$result = $post->delete();

delete()支持软删除,如果它是Active Record,则指向自身。

访问数据

您可以通过访问Active Record实例的属性来访问列值,如$activeRecord->attribute,或者通过数组键获取,如$activeRecord['attribute']

$this->load->model('Posts_model');

// Set attributes
$post = new Posts_model;
$post->title = 'CI3';
$post['subtitle'] = 'PHP';
$post->save();

// Get attributes
$post = $this->Posts_model->findOne(1);
$title = $post->title;
$subtitle = $post['subtitle'];

关系

数据库表通常相互关联。例如,一篇文章可能有许多评论,或者一个订单可能与下单的用户相关。这个库使管理这些关系并与之交互变得简单,并支持不同类型的关系

要使用Active Record处理关系数据,您首先需要在模型中声明关系。这项任务就像为每个感兴趣的关系声明一个relation method一样简单,如下所示

class CustomersModel extends yidas\Model
{
    // ...

    public function orders()
    {
        return $this->hasMany('OrdersModel', ['customer_id' => 'id']);
    }
}

一旦定义了关系,我们就可以使用动态属性检索相关的记录。动态属性允许您像访问模型上定义的属性一样访问关系方法

$orders = $this->CustomersModel->findOne(1)->orders;

动态属性名称与方法名称相同,如Laravel Eloquent

对于查询关系,您可以使用CI查询构建器查询orders关系,并像这样向关系添加额外的约束

$customer = $this->CustomersModel->findOne(1)

$orders = $customer->orders()->where('active', 1)->get()->result_array();

方法

findOne()

通过主键或一列值的数组返回单个Active Record模型实例。

public object findOne(array $condition=[])

示例

// Find a single active record whose primary key value is 10
$activeRecord = $this->Model->findOne(10);

// Find the first active record whose type is 'A' and whose status is 1
$activeRecord = $this->Model->findOne(['type' => 'A', 'status' => 1]);

// Query builder ORM usage
$this->Model->find()->where('id', 10);
$activeRecord = $this->Model->findOne();

findAll()

返回与指定的主键值或一组列值匹配的Active Record模型列表。

public array findAll(array $condition=[], integer|array $limit=null)

示例

// Find the active records whose primary key value is 10, 11 or 12.
$activeRecords = $this->Model->findAll([10, 11, 12]);

// Find the active recordd whose type is 'A' and whose status is 1
$activeRecords = $this->Model->findAll(['type' => 'A', 'status' => 1]);

// Query builder ORM usage
$this->Model->find()->where_in('id', [10, 11, 12]);
$activeRecords = $this->Model->findAll();

// Print all properties for each active record from array
foreach ($activeRecords as $activeRecord) {
    print_r($activeRecord->toArray());
}

限制示例

// LIMIT 10
$activeRecords = $this->Model->findAll([], 10);

// OFFSET 50, LIMIT 10
$activeRecords = $this->Model->findAll([], [50, 10]);

save()

Active Record (ORM)的插入或更新保存

public boolean save(boolean $runValidation=true)

beforeSave()

该方法在插入或更新Active Record开始时调用

public boolean beforeSave(boolean $insert)

示例

public function beforeSave($insert)
{
    if (!parent::beforeSave($insert)) {
        return false;
    }

    // ...custom code here...
    return true;
}

afterSave()

该方法在插入或更新Active Record结束时调用

public boolean beforeSave(boolean $insert, array $changedAttributes)

hasOne()

声明一对一关系

public CI_DB_query_builder hasOne(string $modelName, string $foreignKey=null, string $localKey=null)

示例

class OrdersModel extends yidas\Model
{
    // ...
    
    public function customer()
    {
        return $this->hasOne('CustomersModel', 'id', 'customer_id');
    }
}

访问关系数据

$this->load->model('OrdersModel');
// SELECT * FROM `orders` WHERE `id` = 321
$order = $this->OrdersModel->findOne(321);

// SELECT * FROM `customers` WHERE `customer_id` = 321
// $customer is a Customers active record
$customer = $order->customer;

hasMany()

声明一对多关系

public CI_DB_query_builder hasMany(string $modelName, string $foreignKey=null, string $localKey=null)

示例

class CustomersModel extends yidas\Model
{
    // ...
    
    public function orders()
    {
        return $this->hasMany('OrdersModel', 'customer_id', 'id');
    }
}

访问关系数据

$this->load->model('CustomersModel');
// SELECT * FROM `customers` WHERE `id` = 123
$customer = $this->CustomersModel->findOne(123);

// SELECT * FROM `order` WHERE `customer_id` = 123
// $orders is an array of Orders active records
$orders = $customer->orders;

toArray()

Active Record转换为数组记录

public array toArray()

示例

if ($activeRecord)
    $record = $activeRecord->toArray();

建议使用find()与CI构建器一起使用,而不是使用ORM并将其转换为数组。

软删除

除了实际上从您的数据库中删除记录之外,此模型还可以“软删除”模型。当模型被软删除时,它们实际上并没有从您的数据库中删除。相反,可以在模型上设置一个deleted_at属性并将其插入数据库。

配置

您可以通过提供字段名称给SOFT_DELETED来启用软删除功能

class My_model extends yidas\Model
{
    const SOFT_DELETED = 'is_deleted';
}

当启用 SOFT_DELETED 时,你可以设置 $softDeletedFalseValue$softDeletedTrueValue 以适配表结构。此外,你可以通过将列名设置为 DELETED_AT 来启用时间戳功能,或者默认设置为 NULL 来禁用。

class My_model extends yidas\Model
{
    const SOFT_DELETED = 'is_deleted';
    
    // The actived value for SOFT_DELETED
    protected $softDeletedFalseValue = '0';
    
    // The deleted value for SOFT_DELETED
    protected $softDeletedTrueValue = '1';

    const DELETED_AT = 'deleted_at';
}

如果你需要禁用特定模型的 SOFT DELETED 功能,可以将 SOFT_DELETED 设置为 false,这将禁用所有 SOFT DELETED 功能,包括 DELETED_AT 功能。

// class My_model extends yidas\Model
class Log_model extends My_model
{
    const SOFT_DELETED = false;
}

方法

forceDelete()

强制将选定的记录(带时间戳功能)删除到相关数据库表中。

public boolean forceDelete($condition=null)

示例

$result = $this->Model->forceDelete(123)
// Query builder ORM usage
$this->Model->find()->where('id', 123);
$result = $this->Model->forceDelete();

restore()

将 SOFT_DELETED 字段值恢复到相关数据库表中的选定记录。

public boolean restore($condition=null)

示例

$result = $this->Model->restore(123)
// Query builder ORM usage
$this->Model->withTrashed()->find()->where('id', 123);
$this->Model->restore();

withTrashed()

在下一个 find() 查询中不使用 SOFT DELETED 查询条件。

public self withTrashed()

示例

$this->Model->withTrashed()->find();

QUERY SCOPES

查询作用域允许你为给定模型的查询添加约束。编写自己的全局作用域可以提供一个方便、简单的方法来确保给定模型的每个查询都收到某些约束。《SOFT DELETED》作用域是一个独立的作用域,它不包括在全局作用域中。

配置

你可以重写 _globalScopes 方法来定义你的约束

class My_model extends yidas\Model
{
    protected $userAttribute = 'uid';
    
    /**
     * Override _globalScopes with User validation
     */
    protected function _globalScopes()
    {
        $this->db->where(
            $this->_field($this->userAttribute), 
            $this->config->item('user_id')
            );
        return parent::_globalScopes();
    }

重写后,My_model 将在每次 find() 查询中约束此作用域,除非你在查找查询之前删除查询作用域,例如使用 withoutGlobalScopes()

方法

withoutGlobalScopes()

在下一个 find() 查询中不使用全局作用域查询条件。

public self withoutGlobalScopes()

示例

$this->Model->withoutGlobalScopes()->find();

withAll()

在下一个 find() 查询中不使用所有查询条件(SOFT DELETEDQUERY SCOPES)。

这意味着在下一个 find() 中使用所有模型数据集。

public self withAll()

示例

$this->Model->withAll()->find();

VALIDATION

一般来说,你不应该相信来自最终用户的数据,在将其用于实际用途之前应该始终对其进行验证。

ORM 模型验证集成了 CodeIgniter 表单验证,它提供了一种一致且流畅的方式来处理模型数据验证。

验证输入

给定一个用用户输入填充的模型,你可以通过调用 validate() 方法来验证输入。该方法将返回一个布尔值,指示验证是否成功。如果不成功,你可以从 getErrors() 方法中获取错误消息。

validate()

使用过滤器执行数据验证

ORM 只对指定的属性执行验证。

public boolean validate($data=[], $returnData=false)

Exmaple

$this->load->model('PostsModel');

if ($this->PostsModel->validate($inputData)) {
    // all inputs are valid
} else {
    // validation failed: $errors is an array containing error messages
    $errors = $this->PostsModel->getErrors();
}

yidas\Model 的方法,如 insert()update(),在执行验证时也会执行验证。如果你确保输入数据已验证,可以关闭方法的 $runValidation 参数。

ORM 模型示例

$this->load->model('PostsModel');
$post = new PostsModel;
$post->title = '';
// ORM assigned or modified attributes will be validated by calling `validate()` without parameters
if ($post->validate()) {
    // Already performing `validate()` so that turn false for $runValidation
    $result = $post->save(false);
} else {
    // validation failed: $errors is an array containing error messages
    $errors = post->getErrors();
}

ORM 模型的属性将在执行验证后由过滤器更改。如果你已经调用过 validate()。你可以关闭 save()$runValidation 来保存而无需重复验证。

getErrors()

Validation - 获取最后失败的验证引用的错误数据

public array getErrors()

声明规则

要使 validate() 真正生效,你应该为计划验证的属性声明验证规则。这应该通过重写返回 CodeIgniter 规则rules() 方法来完成。

rules()

返回属性的验证规则。

public array rules()

示例

class PostsModel extends yidas\Model
{
    protected $table = "posts";
    
    /**
     * Override rules function with validation rules setting
     */
    public function rules()
    {
        return [
            [
                'field' => 'title',
                'rules' => 'required|min_length[3]',
            ],
        ];
    }
}

返回数组格式可参考 CodeIgniter - 使用数组设置规则,规则模式可参考 CodeIgniter - 规则参考

带有语言的错误信息

当您处理验证错误消息的 i18n 问题,可以将 CodeIgniter 语言类 集成到规则中。以下示例代码可供您实现

public function rules()
{
    /**
     * Set CodeIgniter language
     * @see https://www.codeigniter.com/userguide3/libraries/language.html
     */
    $this->lang->load('error_messages', 'en-US');

    return [
        [
            'field' => 'title',
            'rules' => 'required|min_length[3]',
            'errors' => [
                'required' => $this->lang->line('required'),
                'min_length' => $this->lang->line('min_length'),
            ],
        ],
    ];
}

在此情况下,语言文件可以是 application/language/en-US/error_messages_lang.php

$lang['required'] = '`%s` is required';
$lang['min_length'] = '`%s` requires at least %d letters';

之后,getErrors() 可以返回当前语言下的字段错误消息。

过滤器

用户输入通常需要过滤或预处理。例如,您可能想要修剪用户名输入周围的空格。您可以在 filter() 方法中声明过滤规则来实现此目标。

在模型的 validate() 过程中,filters() 将在 rules() 之前执行,这意味着由 rules() 验证的输入数据已经过过滤。

要为 validate() 启用过滤,您应该为计划执行的属性声明过滤规则。这应通过重写 filters() 方法来完成。

filters()

返回验证的过滤规则。

public array filters()

示例

public function filters()
{
    return [
        [['title', 'name'], 'trim'],    // Perform `trim()` for title & name input data
        [['title'], 'static::method'],  // Perform `public static function method($value)` in this model
        [['name'], function($value) {   // Perform defined anonymous function. 'value' => '[Filtered]value'
            return "[Filtered]" . $value;
        }],
        [['content'], [$this->security, 'xss_clean']], // Perform CodeIgniter XSS Filtering for content input data
    ];
}

过滤器的格式:[[['attr1','attr2'], callable],]

读 & 写 连接

有时您可能希望对 SELECT 语句使用一个数据库连接,而对 INSERTUPDATEDELETE 语句使用另一个连接。此模型实现了复制和读写分离,确保在使用模型时始终使用数据库连接。

配置

读 & 写 连接可以在扩展 yidas\Model 的模型中设置,您可以为每个模型定义扩展的 My_model 中的读 & 写数据库。

有三种方法来设置读 & 写数据库

Codeigniter 数据库连接

建议在构造函数部分在父类的构造函数之前预先准备 CI 数据库连接,您可以直接分配给构造函数中的属性。

class My_model extends yidas\Model
{
    function __construct()
    {
        $this->database = $this->db;
        
        $this->databaseRead = $this->dbr;
        
        parent::__construct();
    }
}

如果您已经有 $this->db,则这是两个连接的默认设置。

此设置方式支持 重连

Codeigniter 数据库键

您可以将从 \application\config\database.php 引用的数据库键设置到模型的 database & databaseRead 属性中,将自动创建设置连接

class My_model extends yidas\Model
{
    protected $database = 'default';
    
    protected $databaseRead = 'slave';
}

此方法支持 DB 连接的缓存机制,每个模型可以定义自己的连接,但通过键共享相同的连接。

Codeigniter 数据库配置数组

此方式用于在请求周期中与特定模型相关的一次性连接的数据库,将为每个模型创建一个新的连接

class My_model extends yidas\Model
{
    protected $databaseRead = [
        'dsn'   => '',
        'hostname' => 'specified_db_host',
        // Database Configuration...
        ];
}

数据库负载均衡

在上面的例子中,您可以设置多个数据库,并实现为读或写数据库实现随机选择的连接。

例如,在 application/config/database 中配置读数据库

$slaveHosts = ['192.168.1.2', '192.168.1.3'];

$db['slave']['hostname'] = $slaveHosts[mt_rand(0, count($slaveHosts) - 1)];

之后,您可以使用数据库键 slave 来加载或分配它到属性

class My_model extends yidas\Model
{
    protected $databaseRead = 'slave';
}

重新连接

如果您想在 Codeigniter 3 中重新连接数据库以重新建立连接,例如对于 $this->db

$this->db->close();
$this->db->initialize();

具有 Codeigniter 数据库连接 设置的模型连接可以在重置引用的数据库连接后重置。

不要使用 reconnect(),这是一个无用的方法。

悲观锁

模型还包含一些功能,帮助您在 select 语句上实现“悲观锁定”。要使用“共享锁定”执行语句,您可以使用 sharedLock 方法获取查询。共享锁定可以防止选择的行在事务提交之前被修改

$this->Model->find()->where('id', 123);
$result = $this->Model->sharedLock()->row_array();

或者,您也可以使用 lockForUpdate 方法。“for update”锁定可以防止行被修改或被另一个共享锁定选择

$this->Model->find()->where('id', 123);
$result = $this->Model->lockForUpdate()->row_array();

示例代码

此事务块将使用 FOR UPDATE 锁锁定选择的行,以便在下一次相同的查询中使用

$this->Model->getDB()->trans_start();
$this->Model->find()->where('id', 123)
$result = $this->Model->lockForUpdate()->row_array();
$this->Model->getDB()->trans_complete(); 

辅助工具

模型提供了一些辅助方法

indexBy()

按键索引

public array indexBy(array & $array, Integer $key=null, Boolean $obj2Array=false)

示例

$records = $this->Model->findAll();
$this->Model->indexBy($records, 'sn');

// Result example of $records:
[
    7 => ['sn'=>7, title=>'Foo'],
    13 => ['sn'=>13, title=>'Bar']
]