CakePHP 数据库访问层抽象并提供帮助,处理与关系数据库有关的大多数方面,例如维护与服务器的连接、构建查询、防止 SQL 注入、检查和更改模式,以及调试和分析发送到数据库的查询。
本章中描述的函数说明了使用低级数据库访问 API 可以做些什么。如果你想了解更完整的 ORM,可以阅读查询构建器和表对象部分。
创建数据库连接最简单的方法是使用DSN
字符串
use Cake\Datasource\ConnectionManager;
$dsn = 'mysql://root:password@localhost/my_database';
ConnectionManager::setConfig('default', ['url' => $dsn]);
创建后,你可以访问连接对象以开始使用它
$connection = ConnectionManager::get('default');
注意
对于支持的数据库,请参阅安装说明。
运行原始 SQL 查询非常容易
use Cake\Datasource\ConnectionManager;
$connection = ConnectionManager::get('default');
$results = $connection->execute('SELECT * FROM articles')->fetchAll('assoc');
你可以使用预备语句插入参数
$results = $connection
->execute('SELECT * FROM articles WHERE id = :id', ['id' => 1])
->fetchAll('assoc');
也可以使用复杂数据类型作为参数
use Cake\Datasource\ConnectionManager;
use DateTime;
$connection = ConnectionManager::get('default');
$results = $connection
->execute(
'SELECT * FROM articles WHERE created >= :created',
['created' => new DateTime('1 day ago')],
['created' => 'datetime']
)
->fetchAll('assoc');
无需手动编写 SQL,你可以使用查询构建器
// Prior to 4.5 use $connection->query() instead.
$results = $connection
->selectQuery('*', 'articles')
->where(['created >' => new DateTime('1 day ago')], ['created' => 'datetime'])
->order(['title' => 'DESC'])
->execute()
->fetchAll('assoc');
将行插入数据库通常只需要几行代码
use Cake\Datasource\ConnectionManager;
use DateTime;
$connection = ConnectionManager::get('default');
$connection->insert('articles', [
'title' => 'A New Article',
'created' => new DateTime('now')
], ['created' => 'datetime']);
更新数据库中的行同样直观,以下示例将更新具有**id**为 10 的文章
use Cake\Datasource\ConnectionManager;
$connection = ConnectionManager::get('default');
$connection->update('articles', ['title' => 'New title'], ['id' => 10]);
类似地,delete()
方法用于从数据库中删除行,以下示例删除具有**id**为 10 的文章
use Cake\Datasource\ConnectionManager;
$connection = ConnectionManager::get('default');
$connection->delete('articles', ['id' => 10]);
按照惯例,数据库连接在**config/app.php**中配置。在此文件中定义的连接信息被馈送到Cake\Datasource\ConnectionManager
,从而创建您的应用程序将使用的连接配置。示例连接信息可以在**config/app.default.php**中找到。示例连接配置如下所示
'Datasources' => [
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'my_app',
'password' => 'secret',
'database' => 'my_app',
'encoding' => 'utf8mb4',
'timezone' => 'UTC',
'cacheMetadata' => true,
],
],
以上操作将创建名为“default”的连接,并使用提供的参数。你可以在配置文件中定义任意多个连接。你也可以使用Cake\Datasource\ConnectionManager::setConfig()
在运行时定义额外的连接。例如
use Cake\Datasource\ConnectionManager;
ConnectionManager::setConfig('default', [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'my_app',
'password' => 'secret',
'database' => 'my_app',
'encoding' => 'utf8mb4',
'timezone' => 'UTC',
'cacheMetadata' => true,
]);
配置选项也可以作为DSN字符串提供。这在处理环境变量或PaaS提供商时很有用
ConnectionManager::setConfig('default', [
'url' => 'mysql://my_app:sekret@localhost/my_app?encoding=utf8&timezone=UTC&cacheMetadata=true',
]);
使用 DSN 字符串时,你可以将任何其他参数/选项定义为查询字符串参数。
默认情况下,所有 Table 对象将使用default
连接。要使用非默认连接,请参阅配置连接。
数据库配置中支持许多键。以下是完整列表
代表与数据库服务器连接的类的完全限定类名。此类负责加载数据库驱动程序、提供 SQL 事务机制以及准备 SQL 语句等。
用于实现数据库引擎的所有特性的驱动程序的类名。这可以是使用插件语法的简短类名,完全限定的名称,或构造的驱动程序实例。简短类名示例包括 Mysql、Sqlite、Postgres 和 Sqlserver。
是否使用与数据库的持久连接。SqlServer 不支持此选项。如果你尝试将persistent
设置为true
,SqlServer 会抛出异常。
数据库服务器的主机名(或 IP 地址)。
帐户的用户名。
帐户的密码。
此连接要使用的数据库的名称。避免在数据库名称中使用.
。由于其在标识符引用方面带来的复杂性,CakePHP 不支持数据库名称中的.
。SQLite 数据库的路径应该是绝对路径(例如,ROOT . DS . 'my_app.db'
),以避免由于相对路径导致的错误路径。
用于连接到服务器的 TCP 端口或 Unix 套接字。
指示将 SQL 语句发送到服务器时使用的字符集。除了 DB2 之外,所有其他数据库都默认使用数据库的默认编码。
要设置的服务器时区。
在 PostgreSQL 数据库设置中使用,用于指定要使用的模式。
由支持它的驱动程序使用,通过 Unix 套接字文件进行连接。如果你使用的是 PostgreSQL 并希望使用 Unix 套接字,请将 host 键保留为空。
SSL 密钥文件的路径。(仅 MySQL 支持)。
SSL 证书文件的路径。(仅 MySQL 支持)。
SSL 证书颁发机构的路径。(仅 MySQL 支持)。
创建连接时应发送到数据库服务器的查询列表。
设置为true
以启用查询日志记录。启用后,查询将在debug
级别记录,具有queriesLog
范围。
如果在表名或列名中使用保留字或特殊字符,则设置为true
。启用此设置将导致使用查询构建器构建的查询在创建 SQL 时引用标识符。需要注意的是,这会降低性能,因为每个查询都需要在执行之前进行遍历和操作。
应传递到底层 PDO 实例的 PDO 常量关联数组。有关驱动程序支持的标志,请参阅 PDO 文档。
布尔值true
,或包含要存储元数据的缓存配置的字符串。建议不要通过将其设置为false
来禁用元数据缓存,这会导致性能非常差。有关详细信息,请参阅元数据缓存部分。
设置生成的数据库文件的权限。(仅 SQLite 支持)
要发送到 SQLite 的cache
标志。
要发送到 SQLite 的mode
标志值。
此时,你可能想看看CakePHP 约定。对你的表使用正确的命名(以及添加一些列)可以为你节省一些功能,并帮助你避免配置。例如,如果你将数据库表命名为 big_boxes,你的表命名为 BigBoxesTable,你的控制器命名为 BigBoxesController,那么一切都会自动协同工作。按照惯例,对数据库表名使用下划线、小写和复数形式 - 例如:bakers、pastry_stores 和 savory_cakes。
注意
如果您的 MySQL 服务器配置了 skip-character-set-client-handshake
,那么您**必须**使用 flags
配置来设置您的字符集编码。例如
'flags' => [\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8']
连接可以有单独的读和写角色。读角色预期代表只读副本,写角色预期为默认连接并支持写操作。
读角色通过在连接配置中提供 read
键来配置。写角色通过提供 write
键来配置。
角色配置会覆盖共享连接配置中的值。如果读写角色配置相同,则使用单个数据库连接。
'default' => [
'driver' => 'mysql',
'username' => '...',
'password' => '...',
'database' => '...',
'read' => [
'host' => 'read-db.example.com',
],
'write' => [
'host' => 'write-db.example.com',
]
];
您可以为 read
和 write
键指定相同的值,而无需创建多个数据库连接。
ConnectionManager
类充当访问应用程序拥有的数据库连接的注册表。它提供了一个位置,其他对象可以从中获取对现有连接的引用。
配置完成后,可以使用 Cake\Datasource\ConnectionManager::get()
获取连接。如果连接之前尚未构建,此方法将构建并加载连接,否则将返回已知的现有连接。
use Cake\Datasource\ConnectionManager;
$connection = ConnectionManager::get('default');
尝试加载不存在的连接将引发异常。
使用 setConfig()
和 get()
,您可以在运行时创建未在配置文件中定义的新连接。
ConnectionManager::setConfig('my_connection', $config);
$connection = ConnectionManager::get('my_connection');
有关创建连接时使用的配置数据的更多信息,请参见 配置。
由于并非所有数据库供应商都包含相同的数据类型集,或者对类似数据类型使用相同的名称,CakePHP 为数据库层提供了一组抽象数据类型。CakePHP 支持的类型有
映射到 VARCHAR
类型。在 SQL Server 中,使用 NVARCHAR
类型。
映射到 CHAR
类型。在 SQL Server 中,使用 NCHAR
类型。
映射到 TEXT
类型。
如果数据库提供 UUID 类型,则映射到该类型,否则将生成一个 CHAR(36)
字段。
如果数据库提供 UUID 类型,则映射到该类型,否则将生成一个 BINARY(16)
列。
映射到数据库提供的 INTEGER
类型。目前不支持 BIT 类型。
映射到数据库提供的 SMALLINT
类型。
映射到数据库提供的 TINYINT
或 SMALLINT
类型。在 MySQL 中,TINYINT(1)
被视为布尔值。
映射到数据库提供的 BIGINT
类型。
根据数据库映射到 DOUBLE
或 FLOAT
。可以使用 precision
选项定义使用的精度。
映射到 DECIMAL
类型。支持 length
和 precision
选项。十进制类型的值将被表示为字符串(而不是某些人可能期望的浮点数)。这是因为十进制类型用于在数据库中表示精确的数字值,并且在 PHP 中使用浮点类型可能会导致精度损失。
如果您希望 PHP 代码中的值为 float,请考虑在数据库中使用 FLOAT 或 DOUBLE 类型列。此外,根据您的用例,您可以在表模式中将十进制列显式映射到 float 类型。
映射到 BOOLEAN
,除了 MySQL,它使用 TINYINT(1)
来表示布尔值。目前不支持 BIT(1)
类型。
映射到数据库提供的 BLOB
或 BYTEA
类型。
映射到本机 DATE
列类型。此列类型的返回值为 Cake\I18n\Date
,它模拟 PHP 的 DateTime
类的日期相关方法。
参见 DateTime 类型。
参见 DateTime 类型。
映射到 TIMESTAMP
类型。
映射到 TIMESTAMP(N)
类型。
映射到所有数据库中的 TIME
类型。
如果可用,则映射到 JSON
类型,否则映射到 TEXT
。
参见 Enum 类型。
映射到通用几何存储类型。
映射到地理空间存储中的单个点。
映射到地理空间存储中的单条线。
映射到地理空间存储中的单个多边形。
这些类型用于 CakePHP 提供的模式反射功能以及 CakePHP 在使用测试夹具时使用的模式生成功能。
每种类型还可以提供 PHP 和 SQL 表示之间的转换函数。这些方法是根据在执行查询时提供的类型提示调用的。例如,标记为“datetime”的列会自动将来自 DateTime
实例的输入参数转换为时间戳或格式化的日期字符串。同样,“binary”列会接受文件句柄,并在读取数据时生成文件句柄。
版本 5.1.0 中的更改: 添加了 geometry
、point
、linestring
和 polygon
类型。
映射到本机 DATETIME
列类型。在 PostgreSQL 和 SQL Server 中,这将变为 TIMESTAMP
类型。此列类型的默认返回值为 Cake\I18n\DateTime
,它扩展了 Chronos 和本机 DateTimeImmutable
。
如果您的数据库服务器时区与您的应用程序的 PHP 时区不匹配,则可以使用此方法指定您的数据库时区。然后,此时区将在将 PHP 对象转换为数据库的日期时间字符串以及将数据库的日期时间字符串转换为 PHP 对象时使用。
可用于映射包含微秒的日期时间列,例如 MySQL 中的 DATETIME(6)
。要使用此类型,您需要将其添加为映射类型。
// in config/bootstrap.php
use Cake\Database\TypeFactory;
use Cake\Database\Type\DateTimeFractionalType;
// Overwrite the default datetime type with a more precise one.
TypeFactory::map('datetime', DateTimeFractionalType::class);
可用于映射包含时区的日期时间列,例如 PostgreSQL 中的 TIMESTAMPTZ
。要使用此类型,您需要将其添加为映射类型。
// in config/bootstrap.php
use Cake\Database\TypeFactory;
use Cake\Database\Type\DateTimeTimezoneType;
// Overwrite the default datetime type with a more precise one.
TypeFactory::map('datetime', DateTimeTimezoneType::class);
将 BackedEnum 映射到字符串或整数列。要使用此类型,您需要在表类中指定哪个列与哪个 BackedEnum 关联。
use \Cake\Database\Type\EnumType;
use \App\Model\Enum\ArticleStatus;
// in src/Model/Table/ArticlesTable.php
public function initialize(array $config): void
{
$this->getSchema()->setColumnType('status', EnumType::from(ArticleStatus::class));
}
其中 ArticleStatus
包含类似以下内容:
namespace App\Model\Enum;
enum ArticleStatus: string
{
case Published = 'Y';
case Unpublished = 'N';
}
CakePHP 建议枚举的一些约定:
枚举类名应遵循 {Entity}{ColumnName}
样式,以便在运行 bake 时进行检测,并有助于项目一致性。
枚举情况应使用驼峰式。
枚举应实现 Cake\Database\Type\EnumLabelInterface
以提高与 bake 和 FormHelper
的兼容性。
geometry
、point
、linestring
和 polygon
类型也称为“地理空间类型”。CakePHP 对地理空间列提供有限支持。目前,它们可以在迁移中定义,在架构反射中读取,并且可以将值设置为文本。
在版本 5.1.0 中添加: 添加了地理空间架构类型。
如果您需要使用 CakePHP 中未内置的供应商特定类型,您可以将其他新类型添加到 CakePHP 的类型系统中。类型类应实现以下方法
toPHP
:将给定值从数据库类型转换为 PHP 等效值。
toDatabase
:将给定值从 PHP 类型转换为数据库可接受的类型。
toStatement
:将给定值转换为其 Statement 等效值。
marshal
:将扁平数据编组到 PHP 对象中。
要实现基本接口,请扩展 Cake\Database\Type
。例如,如果我们想添加一个 JSON 类型,我们可以创建以下类型类
// in src/Database/Type/JsonType.php
namespace App\Database\Type;
use Cake\Database\Driver;
use Cake\Database\Type\BaseType;
use PDO;
class JsonType extends BaseType
{
public function toPHP(mixed $value, Driver $driver): mixed
{
if ($value === null) {
return null;
}
return json_decode($value, true);
}
public function marshal(mixed $value): mixed
{
if (is_array($value) || $value === null) {
return $value;
}
return json_decode($value, true);
}
public function toDatabase(mixed $value, Driver $driver): mixed
{
return json_encode($value);
}
public function toStatement(mixed $value, Driver $driver): int
{
if ($value === null) {
return PDO::PARAM_NULL;
}
return PDO::PARAM_STR;
}
}
默认情况下,toStatement()
方法将值视为字符串,这将适用于我们的新类型。
创建了新类型后,我们需要将其添加到类型映射中。在应用程序启动时,我们应该执行以下操作
use Cake\Database\TypeFactory;
TypeFactory::map('json', \App\Database\Type\JsonType::class);
然后,我们有两种方法可以在模型中使用我们的数据类型。
第一种方法是覆盖反射的架构数据以使用我们的新类型。
第二种方法是实现 Cake\Database\Type\ColumnSchemaAwareInterface
并定义 SQL 列类型和反射逻辑。
使用自定义类型覆盖反射的架构将使 CakePHP 的数据库层能够在创建查询时自动转换 JSON 数据。在表的 getSchema() 方法 中添加以下内容
class WidgetsTable extends Table
{
public function getSchema(): TableSchemaInterface
{
return parent::getSchema()->setColumnType('widget_prefs', 'json');
}
}
实现 ColumnSchemaAwareInterface
使您能够更好地控制自定义数据类型。如果您的数据类型具有明确的 SQL 列定义,则可以避免覆盖架构定义。例如,我们可以让我们的 JSON 类型在任何使用具有特定注释的 TEXT
列时使用
// in src/Database/Type/JsonType.php
namespace App\Database\Type;
use Cake\Database\Driver;
use Cake\Database\Type\BaseType;
use Cake\Database\Type\ColumnSchemaAwareInterface;
use Cake\Database\Schema\TableSchemaInterface;
use PDO;
class JsonType extends BaseType
implements ColumnSchemaAwareInterface
{
// other methods from earlier
/**
* Convert abstract schema definition into a driver specific
* SQL snippet that can be used in a CREATE TABLE statement.
*
* Returning null will fall through to CakePHP's built-in types.
*/
public function getColumnSql(
TableSchemaInterface $schema,
string $column,
Driver $driver
): ?string {
$data = $schema->getColumn($column);
$sql = $driver->quoteIdentifier($column);
$sql .= ' JSON';
if (isset($data['null') && $data['null'] === false) {
$sql .= ' NOT NULL';
}
return $sql;
}
/**
* Convert the column data returned from schema reflection
* into the abstract schema data.
*
* Returning null will fall through to CakePHP's built-in types.
*/
public function convertColumnDefinition(
array $definition,
Driver $driver
): ?array {
return [
'type' => $this->_name,
'length' => null,
];
}
传递给 convertColumnDefinition()
的 $definition
数据将包含以下键。所有键都将存在,但如果键对当前数据库驱动程序没有值,则可能包含 null
length
如果可用,则为列的长度。
precision
如果可用,则为列的精度。
scale
可用于 SQLServer 连接。
前面的示例为“json”列类型映射了自定义数据类型,该类型可以轻松地作为字符串表示在 SQL 语句中。复杂的 SQL 数据类型无法作为字符串/整数表示在 SQL 查询中。当处理这些数据类型时,您的 Type 类需要实现 Cake\Database\Type\ExpressionTypeInterface
接口。此接口允许您的自定义类型将值表示为 SQL 表达式。例如,我们将为处理 MySQL 中的 POINT
类型数据构建一个简单的 Type 类。首先,我们将定义一个“值”对象,我们可以用它在 PHP 中表示 POINT
数据
// in src/Database/Point.php
namespace App\Database;
// Our value object is immutable.
class Point
{
protected $_lat;
protected $_long;
// Factory method.
public static function parse($value)
{
// Parse the WKB data from MySQL.
$unpacked = unpack('x4/corder/Ltype/dlat/dlong', $value);
return new static($unpacked['lat'], $unpacked['long']);
}
public function __construct($lat, $long)
{
$this->_lat = $lat;
$this->_long = $long;
}
public function lat()
{
return $this->_lat;
}
public function long()
{
return $this->_long;
}
}
创建了值对象后,我们需要一个 Type 类将数据映射到该值对象和 SQL 表达式中
namespace App\Database\Type;
use App\Database\Point;
use Cake\Database\Driver;
use Cake\Database\Expression\FunctionExpression;
use Cake\Database\ExpressionInterface;
use Cake\Database\Type\BaseType;
use Cake\Database\Type\ExpressionTypeInterface;
class PointType extends BaseType implements ExpressionTypeInterface
{
public function toPHP($value, Driver $d): mixed
{
return $value === null ? null : Point::parse($value);
}
public function marshal($value): mixed
{
if (is_string($value)) {
$value = explode(',', $value);
}
if (is_array($value)) {
return new Point($value[0], $value[1]);
}
return null;
}
public function toExpression($value): ExpressionInterface
{
if ($value instanceof Point) {
return new FunctionExpression(
'POINT',
[
$value->lat(),
$value->long()
]
);
}
if (is_array($value)) {
return new FunctionExpression('POINT', [$value[0], $value[1]]);
}
// Handle other cases.
}
public function toDatabase($value, Driver $driver): mixed
{
return $value;
}
}
上面的类做了一些有趣的事情
toPHP
方法处理将 SQL 查询结果解析为值对象。
marshal
方法处理将数据(例如给定请求数据)转换为我们的值对象。现在我们将接受字符串值(如 '10.24,12.34'
)和数组。
toExpression
方法处理将我们的值对象转换为等效的 SQL 表达式。在我们的示例中,生成的 SQL 将类似于 POINT(10.24, 12.34)
。
构建了自定义类型后,我们需要 将我们的类型连接到我们的表类。
连接类提供了一个简单的接口,以一致的方式与数据库连接进行交互。它们旨在作为驱动程序层的更抽象的接口,并提供执行查询、记录查询和执行事务操作的功能。
获得连接对象后,您可能希望使用它发出一些查询。CakePHP 的数据库抽象层在 PDO 和本机驱动程序之上提供了包装器功能。这些包装器提供了与 PDO 相似的接口。您可以根据需要运行的查询类型和需要返回的结果类型,使用几种不同的方法运行查询。最基本的方法是 execute()
,它允许您运行完整的 SQL 查询
$statement = $connection->execute('UPDATE articles SET published = 1 WHERE id = 2');
对于参数化查询,请使用第二个参数
$statement = $connection->execute(
'UPDATE articles SET published = ? WHERE id = ?',
[1, 2]
);
没有任何类型提示信息,execute
将假定所有占位符都是字符串值。如果您需要绑定特定类型的数据,则可以在创建查询时使用其抽象类型名称
$statement = $connection->execute(
'UPDATE articles SET published_date = ? WHERE id = ?',
[new DateTime('now'), 2],
['date', 'integer']
);
这些方法允许您在应用程序中使用丰富的數據类型,并将它们正确地转换为 SQL 语句。创建查询的最后一个也是最灵活的方法是使用 查询构建器。这种方法允许您构建复杂且具有表现力的查询,而无需使用平台特定的 SQL。使用查询构建器时,只有在调用 execute()
方法或迭代查询时,才会将 SQL 发送到数据库服务器。迭代查询将首先执行它,然后开始迭代结果集
$query = $connection->selectQuery();
$query->select('*')
->from('articles')
->where(['published' => true]);
foreach ($query as $row) {
// Do something with the row.
}
注意
除了迭代 $query
之外,您还可以调用它的 all()
方法以获取结果。
此方法为您提供 UPDATE
查询的构建器
$query = $connection->updateQuery('articles')
->set(['published' => true])
->where(['id' => 2]);
$statement = $query->execute();
此方法为您提供 INSERT
查询的构建器
$query = $connection->insertQuery();
$query->into('articles')
->columns(['title'])
->values(['1st article']);
$statement = $query->execute();
此方法为您提供 DELETE
查询的构建器
$query = $connection->deleteQuery();
$query->delete('articles')
->where(['id' => 2]);
$statement = $query->execute();
连接对象为您提供了一些执行数据库事务的简单方法。执行事务的最基本方法是通过 begin()
、commit()
和 rollback()
方法,它们映射到它们的 SQL 等效方法
$connection->begin();
$connection->execute('UPDATE articles SET published = ? WHERE id = ?', [true, 2]);
$connection->execute('UPDATE articles SET published = ? WHERE id = ?', [false, 4]);
$connection->commit();
除了这个接口之外,连接实例还提供了transactional()
方法,它使处理begin/commit/rollback调用变得更加简单。
$connection->transactional(function ($connection) {
$connection->execute('UPDATE articles SET published = ? WHERE id = ?', [true, 2]);
$connection->execute('UPDATE articles SET published = ? WHERE id = ?', [false, 4]);
});
除了基本的查询之外,您还可以使用 查询构建器 或 表格对象 来执行更复杂的查询。transactional方法将执行以下操作:
调用begin
。
调用提供的闭包。
如果闭包引发异常,将发出回滚。原始异常将被重新抛出。
如果闭包返回false
,将发出回滚。
如果闭包成功执行,将提交事务。
当使用更低级的数据库API时,您通常会遇到语句对象。这些对象允许您操作驱动程序中的底层预处理语句。创建并执行查询对象后,或使用execute()
,您将拥有一个StatementInterface
实例。
使用execute()
执行查询后,可以使用fetch()
、fetchAll()
获取结果。
$statement->execute();
// Read one row.
$row = $statement->fetch('assoc');
// Read all rows.
$rows = $statement->fetchAll('assoc');
执行语句后,您可以获取受影响的行数。
$rowCount = $statement->rowCount();
如果您的查询不成功,可以使用errorCode()
和errorInfo()
方法获取相关错误信息。这些方法的工作方式与PDO提供的方法相同。
$code = $statement->errorCode();
$info = $statement->errorInfo();
在配置连接时,通过将log
选项设置为true
,可以启用查询日志记录。
启用查询日志记录后,查询将记录到 Cake\Log\Log
,使用'debug'级别和'queriesLog'范围。您需要配置一个记录器来捕获此级别和范围。将日志记录到stderr
在处理单元测试时很有用,而将日志记录到文件/syslog在处理网络请求时很有用。
use Cake\Log\Log;
// Console logging
Log::setConfig('queries', [
'className' => 'Console',
'stream' => 'php://stderr',
'scopes' => ['queriesLog']
]);
// File logging
Log::setConfig('queries', [
'className' => 'File',
'path' => LOGS,
'file' => 'queries.log',
'scopes' => ['queriesLog']
]);
注意
查询日志记录仅用于调试/开发目的。您不应该在生产环境中启用查询日志记录,因为它会对应用程序的性能产生负面影响。
默认情况下,CakePHP **不会** 在生成的SQL查询中引用标识符。这样做的原因是标识符引用有一些缺点:
性能开销 - 引用标识符比不引用要慢得多、复杂得多。
在大多数情况下没有必要 - 在遵循CakePHP约定的非遗留数据库中,没有理由引用标识符。
如果您使用的是需要标识符引用的遗留模式,则可以使用 配置 中的quoteIdentifiers
设置启用它。您也可以在运行时启用此功能。
$connection->getDriver()->enableAutoQuoting();
启用后,标识符引用会导致额外的查询遍历,将所有标识符转换为IdentifierExpression
对象。
注意
包含在QueryExpression对象中的SQL代码段不会被修改。
CakePHP的ORM使用数据库反射来确定您的应用程序包含的模式、索引和外键。由于此元数据很少更改,并且访问可能很昂贵,因此通常将其缓存。默认情况下,元数据存储在_cake_model_
缓存配置中。您可以使用数据源配置中的cacheMetatdata
选项定义自定义缓存配置。
'Datasources' => [
'default' => [
// Other keys go here.
// Use the 'orm_metadata' cache config for metadata.
'cacheMetadata' => 'orm_metadata',
]
],
您也可以使用cacheMetadata()
方法在运行时配置元数据缓存。
// Disable the cache
$connection->cacheMetadata(false);
// Enable the cache
$connection->cacheMetadata(true);
// Use a custom cache config
$connection->cacheMetadata('orm_metadata');
CakePHP还包含一个用于管理元数据缓存的CLI工具。有关更多信息,请参见 模式缓存工具 章节。
如果您想创建不选择数据库的连接,您可以省略数据库名称。
$dsn = 'mysql://root:password@localhost/';
您现在可以使用连接对象来执行创建/修改数据库的查询。例如,要创建一个数据库:
$connection->execute("CREATE DATABASE IF NOT EXISTS my_database");
注意
创建数据库时,最好设置字符集和排序规则参数。如果这些值缺失,数据库将设置其使用的任何系统默认值。