Laravel Database——数据库服务的启动与连接 | Laravel China 社区


本站和网页 https://learnku.com/articles/6087/laravel-database-the-startup-and-connection-of-database-services?order_by=vote_count& 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

Laravel Database——数据库服务的启动与连接 | Laravel China 社区
Laravel
话题列表
社区 Wiki
优质外文
招聘求职
Laravel 实战教程
社区文档
登录
注册
Laravel
首页
Laravel
Go
PHP
Vue.js
Python
Java
MySQL
Rust
LK
Elasticsearch
F2E 前端
Server
程序员
Database
DevTools
Computer Science
手机开发
AdonisJS
社区
Wiki
教程
Laravel 实战教程首页
《L01 Laravel 教程 - Web 开发实战入门》
《L02 Laravel 教程 - Web 开发实战进阶》
《L03 Laravel 教程 - 实战构架 API 服务器》
《L04 Laravel 教程 - 微信小程序从零到发布》
《L05 Laravel 教程 - 电商实战》
《L06 Laravel 教程 - 电商进阶》
《LX1 Laravel / PHP 扩展包视频教程》
《LX2 PHP 扩展包实战教程 - 从入门到发布》
《L07 Laravel 教程 - Laravel TDD 测试实战》
《LX3 Laravel 性能优化入门》
《LX4 Laravel / PHP 五分钟视频》
文档
社区文档首页
《Laravel 中文文档》
《Laravel 速查表》
《PHP 代码简洁之道》
《Laravel 编码技巧》
《Dcat Admin 中文文档》
《Laravel Nova 中文文档》
《Lumen 中文文档》
《Dingo API 中文文档》
《 Laravel 项目开发规范》
《构建 Laravel 开发环境》
登录
注册
微信登录
Laravel Database——数据库服务的启动与连接
58
27
12
leoyang 的个人博客
16564
12
创建于 5年前
更新于 4年前
前言
本文 GitBook 地址: https://www.gitbook.com/book/leoyang90/lar...
数据库是 laravel 及其重要的组成部分,大致的讲,laravel 的数据库功能可以分为两部分:数据库 DB、数据库 Eloquent Model。数据库的 Eloquent 是功能十分丰富的 ORM,让我们可以避免写繁杂的 sql 语句。数据库 DB 是比较底层的与 pdo 交互的功能,Eloquent 的底层依赖于 DB。本文将会介绍数据库 DB 中关于数据库服务的启动与连接部分。
在详细讲解数据库各个功能之前,我们先看看支撑着整个 laravel 数据库功能的框架:
DB 也就是 DatabaseManager,承担着数据库接口的工作,一切数据库相关的操作,例如查询、更新、插入、删除都可以通过 DB 这个接口来完成。但是,具体的调用 pdo API 的工作却不是由该类完成的,它仅仅是一个对外的接口而已。
ConnectionFactory 顾名思义专门为 DB 构造初始化 connector、connection 对象,
connector 负责数据库的连接功能,为保障程序的高效,laravel 将其包装成为闭包函数,并将闭包函数作为 connection 的一个成员对象,实现懒加载。
connection 负责数据库的具体功能,负责底层与 pdo API 的交互。
数据库服务的注册与启动
数据库服务也是一种服务提供者:Illuminate\Database\DatabaseServiceProvider
public function register()
Model::clearBootedModels();
$this->registerConnectionServices();
$this->registerEloquentFactory();
$this->registerQueueableEntityResolver();
我们先来看这个注册函数的第一句: Model::clearBootedModels()。这一句其实是为了 Eloquent 服务的启动做准备。数据库的 Eloquent Model 有一个静态的成员变量数组 $booted,这个静态数组存储了所有已经被初始化的数据库 model ,以便加载数据库模型时更加迅速。因此,在 Eloquent 服务启动之前需要初始化静态成员变量 $booted:
public static function clearBootedModels()
static::$booted = [];
static::$globalScopes = [];
接下来我们就开始看数据库服务的注册最重要的两部分:ConnectionServices 与 Eloquent.
ConnectionServices 注册
protected function registerConnectionServices()
$this->app->singleton('db.factory', function ($app) {
return new ConnectionFactory($app);
});
$this->app->singleton('db', function ($app) {
return new DatabaseManager($app, $app['db.factory']);
});
$this->app->bind('db.connection', function ($app) {
return $app['db']->connection();
});
可以看出,数据库服务向 IOC 容器注册了 db、db.factory 与 db.connection。
最重要的莫过于 db 对象,它有一个 Facade 是 DB, 我们可以利用 DB::connection() 来连接任意数据库,可以利用 DB::select() 来进行数据库的查询,可以说 DB 就是我们操作数据库的接口。
db.factory 负责为 DB 创建 connector 提供数据库的底层连接服务,负责为 DB 创建 connection 对象来进行数据库的查询等操作。
db.cønnection 是 laravel 用于与数据库 pdo 接口进行交互的底层类,可用于数据库的查询、更新、创建等操作。
Eloquent 注册
protected function registerEloquentFactory()
$this->app->singleton(FakerGenerator::class, function () {
return FakerFactory::create();
});
$this->app->singleton(EloquentFactory::class, function ($app) {
return EloquentFactory::construct(
$app->make(FakerGenerator::class), database_path('factories')
);
});
EloquentFactory 用于创建 Eloquent Model,用于全局函数 factory() 来创建数据库模型。
数据库服务的启动
public function boot()
Model::setConnectionResolver($this->app['db']);
Model::setEventDispatcher($this->app['events']);
数据库服务的启动主要设置 Eloquent Model 的 connection resolver,用于数据库模型 model 利用 db 来来连接数据库。
还有设置数据库事件的分发器 dispatcher,用于监听数据库的事件。
DatabaseManager——数据库的接口
如果我们想要使用任何数据库服务,首先要做的事情当然是利用用户名与密码来连接数据库。在 laravel 中,数据库的用户名与密码一般放在 .env 文件中或者放入 nginx 配置中,并且利用数据库的接口 DB 来与 pdo 进行交互,利用 pdo 来连接数据库。
DB 即是类 Illuminate\Database\DatabaseManager,首先我们来看看其构造函数:
public function __construct($app, ConnectionFactory $factory)
$this->app = $app;
$this->factory = $factory;
我们称 DB 为一个接口,或者是一个门面模式,是因为数据库操作,例如数据库的连接或者查询、更新等操作均不是 DB 的功能,数据库的连接使用类 Illuminate\Database\Connectors\Connector 完成,数据库的查询等操作由类 Illuminate\Database\Connection 完成,
因此,我们不必直接操作 connector 或者 connection,仅仅会操作 DB 即可。
那么 DB 是如何实现 connector 或者 connection 的功能的呢?关键还是这个 ConnectionFactory 类,这个工厂类专门为 DB 来生成 connection 对象,并将其放入 DB 的成员变量数组 $connections 中去。connection 中会包含 connector 对象来实现数据库的连接工作。
class DatabaseManager implements ConnectionResolverInterface
protected $app;
protected $factory;
protected $connections = [];
public function __call($method, $parameters)
return $this->connection()->$method(...$parameters);
魔术函数实现了 DB 与 connection 的无缝连接,任何对数据库的操作,例如 DB::select()、DB::table('user')->save(),都会被转移至 connection 中去。
connection 函数——获取数据库连接对象
public function connection($name = null)
list($database, $type) = $this->parseConnectionName($name);
$name = $name ?: $database;
if (! isset($this->connections[$name])) {
$this->connections[$name] = $this->configure(
$connection = $this->makeConnection($database), $type
);
return $this->connections[$name];
具体流程如下:
DB 的 connection 函数可以传入数据库的名字,也可以不传任何参数,此时会连接默认数据库,默认数据库的设置在 config/database 文件中。
connection 函数流程:
解析数据库名称与数据库类型,例如只读、写
若没有创建过与该数据库的连接,则开始创建数据库连接
返回数据库连接对象 connection
protected function parseConnectionName($name)
$name = $name ?: $this->getDefaultConnection();
return Str::endsWith($name, ['::read', '::write'])
? explode('::', $name, 2) : [$name, null];
public function getDefaultConnection()
return $this->app['config']['database.default'];
可以看出,若没有特别指定连接的数据库名称,那么就会利用文件 config/database 文件中设置的 default 数据库名称作为默认连接数据库名称。若数据库支持读写分离,那么还可以指定数据库的读写属性,例如 mysql::read。
makeConnection 函数——创建新的数据库连接对象
当框架从未连接过当前数据库的时候,就要对数据库进行连接操作,首先程序会调用 makeConnection 函数:
protected function makeConnection($name)
$config = $this->configuration($name);
if (isset($this->extensions[$name])) {
return call_user_func($this->extensions[$name], $config, $name);
if (isset($this->extensions[$driver = $config['driver']])) {
return call_user_func($this->extensions[$driver], $config, $name);
return $this->factory->make($config, $name);
可以看出,连接数据库仅仅需要两个步骤:获取数据库配置、利用 connection factory 获取 connection 对象。
获取数据库配置:
protected function configuration($name)
$name = $name ?: $this->getDefaultConnection();
$connections = $this->app['config']['database.connections'];
if (is_null($config = Arr::get($connections, $name))) {
throw new InvalidArgumentException("Database [$name] not configured.");
return $config;
也是非常简单,直接从配置文件中获取当前数据库的配置:
'connections' => [
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
'read' => [
'database' => env('DB_DATABASE', 'forge'),
],
'write' => [
'database' => env('DB_DATABASE', 'forge'),
],
],
],
$this->factory->make($config, $name) 函数向我们提供了数据库连接对象。
configure——连接对象读写配置
当我们从 connection factory 中获取到连接对象 connection 之后,我们就要根据传入的参数进行读写配置:
protected function configure(Connection $connection, $type)
$connection = $this->setPdoForType($connection, $type);
if ($this->app->bound('events')) {
$connection->setEventDispatcher($this->app['events']);
$connection->setReconnector(function ($connection) {
$this->reconnect($connection->getName());
});
return $connection;
setPdoForType 函数就是根据 type 来设置读写:
当我们需要 read 数据库连接时,我们将 read-pdo 设置为主 pdo。当我们需要 write 数据库连接时,我们将读写 pdo 都设置为 write-pdo:
protected function setPdoForType(Connection $connection, $type = null)
if ($type == 'read') {
$connection->setPdo($connection->getReadPdo());
} elseif ($type == 'write') {
$connection->setReadPdo($connection->getPdo());
return $connection;
ConnectionFactory——数据库连接对象工厂
make 函数——工厂接口
获取到了数据库的配置参数之后,就要利用 ConnectionFactory 来获取 connection 对象了:
public function make(array $config, $name = null)
$config = $this->parseConfig($config, $name);
if (isset($config['read'])) {
return $this->createReadWriteConnection($config);
return $this->createSingleConnection($config);
protected function parseConfig(array $config, $name)
return Arr::add(Arr::add($config, 'prefix', ''), 'name', $name);
在建立连接之前,要先向配置参数中添加默认的 prefix 属性与 name 属性。
接着,就要判断我们在配置文件中是否设置了读写分离。如果设置了读写分离,那么就会调用 createReadWriteConnection 函数,生成具有读、写两个功能的 connection;否则的话,就会调用 createSingleConnection 函数,生成普通的连接对象。
createSingleConnection 函数——制造数据库连接对象
createSingleConnection 函数是类 ConnectionFactory 的核心,用于生成新的数据库连接对象。
protected function createSingleConnection(array $config)
$pdo = $this->createPdoResolver($config);
return $this->createConnection(
$config['driver'], $pdo, $config['database'], $config['prefix'], $config
);
ConnectionFactory 也很简单,只做了两件事情:制造 pdo 连接的闭包函数、构造一个新的 connection 对象。
createPdoResolver——数据库连接器闭包函数
根据配置参数中是否含有 host,创建不同的闭包函数:
protected function createPdoResolver(array $config)
return array_key_exists('host', $config)
? $this->createPdoResolverWithHosts($config)
: $this->createPdoResolverWithoutHosts($config);
不带有 host 的 pdo 闭包函数:
protected function createPdoResolverWithoutHosts(array $config)
return function () use ($config) {
return $this->createConnector($config)->connect($config);
};
可以看出,不带有 pdo 的闭包函数非常简单,仅仅创建 connector 对象,利用 connector 对象进行数据库的连接。
带有 host 的 pdo 闭包函数:
protected function createPdoResolverWithHosts(array $config)
return function () use ($config) {
foreach (Arr::shuffle($hosts = $this->parseHosts($config)) as $key => $host) {
$config['host'] = $host;
try {
return $this->createConnector($config)->connect($config);
} catch (PDOException $e) {
if (count($hosts) - 1 === $key && $this->container->bound(ExceptionHandler::class)) {
$this->container->make(ExceptionHandler::class)->report($e);
throw $e;
};
protected function parseHosts(array $config)
$hosts = array_wrap($config['host']);
if (empty($hosts)) {
throw new InvalidArgumentException('Database hosts array is empty.');
return $hosts;
带有 host 的闭包函数相对比较复杂,首先程序会随机选择不同的数据库依次来建立数据库连接,若均失败,就会报告异常。
createConnector——创建连接器
程序会根据配置参数中 driver 的不同来创建不同的连接器,每个连接器都继承自 connector 类,用于连接数据库。
public function createConnector(array $config)
if (! isset($config['driver'])) {
throw new InvalidArgumentException('A driver must be specified.');
if ($this->container->bound($key = "db.connector.{$config['driver']}")) {
return $this->container->make($key);
switch ($config['driver']) {
case 'mysql':
return new MySqlConnector;
case 'pgsql':
return new PostgresConnector;
case 'sqlite':
return new SQLiteConnector;
case 'sqlsrv':
return new SqlServerConnector;
throw new InvalidArgumentException("Unsupported driver [{$config['driver']}]");
createConnection——创建连接对象
protected function createConnection($driver, $connection, $database, $prefix = '', array $config = [])
if ($resolver = Connection::getResolver($driver)) {
return $resolver($connection, $database, $prefix, $config);
switch ($driver) {
case 'mysql':
return new MySqlConnection($connection, $database, $prefix, $config);
case 'pgsql':
return new PostgresConnection($connection, $database, $prefix, $config);
case 'sqlite':
return new SQLiteConnection($connection, $database, $prefix, $config);
case 'sqlsrv':
return new SqlServerConnection($connection, $database, $prefix, $config);
throw new InvalidArgumentException("Unsupported driver [$driver]");
创建 pdo 闭包函数之后,会将该闭包函数放入 connection 对象当中去。以后我们利用 connection 对象进行查询或者更新数据库时,程序便会运行该闭包函数,与数据库进行连接。
createReadWriteConnection——创建读写连接对象
当配置文件中有 read、write 等配置项时,说明用户希望创建一个可以读写分离的数据库连接,此时:
protected function createReadWriteConnection(array $config)
$connection = $this->createSingleConnection($this->getWriteConfig($config));
return $connection->setReadPdo($this->createReadPdo($config));
protected function getWriteConfig(array $config)
return $this->mergeReadWriteConfig(
$config, $this->getReadWriteConfig($config, 'write')
);
protected function getReadWriteConfig(array $config, $type)
return isset($config[$type][0])
? $config[$type][array_rand($config[$type])]
: $config[$type];
protected function mergeReadWriteConfig(array $config, array $merge)
return Arr::except(array_merge($config, $merge), ['read', 'write']);
可以看出,程序先读出关于 write 数据库的配置,之后将其合并到总配置当中,删除关于 read 数据库的配置,然后进行 createSingleConnection 建立新的连接对象。
建立连接对象之后,再根据 read 数据库的配置,生成 read 数据库的 pdo 闭包函数,并调用 setReadPdo 将其设置为读库 pdo。
protected function createReadPdo(array $config)
return $this->createPdoResolver($this->getReadConfig($config));
protected function getReadConfig(array $config)
return $this->mergeReadWriteConfig(
$config, $this->getReadWriteConfig($config, 'read')
);
connector 连接
我们以 mysql 为例:
class MySqlConnector extends Connector implements ConnectorInterface
public function connect(array $config)
$dsn = $this->getDsn($config);
$options = $this->getOptions($config);
$connection = $this->createConnection($dsn, $config, $options);
if (! empty($config['database'])) {
$connection->exec("use `{$config['database']}`;");
$this->configureEncoding($connection, $config);
$this->configureTimezone($connection, $config);
$this->setModes($connection, $config);
return $connection;
getDsn——获取数据库连接DSN参数
protected function getDsn(array $config)
return $this->hasSocket($config)
? $this->getSocketDsn($config)
: $this->getHostDsn($config);
protected function hasSocket(array $config)
return isset($config['unix_socket']) && ! empty($config['unix_socket']);
protected function getSocketDsn(array $config)
return "mysql:unix_socket={$config['unix_socket']};dbname={$config['database']}";
protected function getHostDsn(array $config)
extract($config, EXTR_SKIP);
return isset($port)
? "mysql:host={$host};port={$port};dbname={$database}"
: "mysql:host={$host};dbname={$database}";
mysql 数据库的连接有两种:tcp连接与socket连接。
socket 连接更快,但是它要求应用程序与数据库在同一台机器,更普通的是使用 tcp 的方式连接数据库。框架根据配置参数来选择是采用 socket 还是 tcp 的方式连接数据库。
getOptions——pdo 属性设置
protected $options = [
PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_EMULATE_PREPARES => false,
];
public function getOptions(array $config)
$options = Arr::get($config, 'options', []);
return array_diff_key($this->options, $options) + $options;
pdo 的属性主要有以下几种:
PDO::ATTR_CASE 强制列名为指定的大小写。他的$value可为:
PDO::CASE_LOWER:强制列名小写。
PDO::CASE_NATURAL:保留数据库驱动返回的列名。
PDO::CASE_UPPER:强制列名大写。
PDO::ATTR_ERRMODE:错误报告。他的$value可为:
PDO::ERRMODE_SILENT: 仅设置错误代码。
PDO::ERRMODE_WARNING: 引发 E_WARNING 错误.
PDO::ERRMODE_EXCEPTION: 抛出 exceptions 异常。
PDO::ATTR_ORACLE_NULLS (在所有驱动中都可用,不仅限于Oracle): 转换 NULL 和空字符串。他的$value可为:
PDO::NULL_NATURAL: 不转换。
PDO::NULL_EMPTY_STRING: 将空字符串转换成 NULL 。
PDO::NULL_TO_STRING: 将 NULL 转换成空字符串。
PDO::ATTR_STRINGIFY_FETCHES: 提取的时候将数值转换为字符串。
PDO::ATTR_EMULATE_PREPARES 启用或禁用预处理语句的模拟。 有些驱动不支持或有限度地支持本地预处理。使用此设置强制PDO总是模拟预处理语句(如果为 TRUE ),或试着使用本地预处理语句(如果为 FALSE )。如果驱动不能成功预处理当前查询,它将总是回到模拟预处理语句上。 需要 bool 类型。
PDO::ATTR_AUTOCOMMIT:设置当前连接 Mysql 服务器的客户端的SQL语句是否自动执行,默认是自动提交.
PDO::ATTR_PERSISTENT:当前对Mysql服务器的连接是否是长连接.
createConnection——创建数据库连接
public function createConnection($dsn, array $config, array $options)
list($username, $password) = [
Arr::get($config, 'username'), Arr::get($config, 'password'),
];
try {
return $this->createPdoConnection(
$dsn, $username, $password, $options
);
} catch (Exception $e) {
return $this->tryAgainIfCausedByLostConnection(
$e, $dsn, $username, $password, $options
);
protected function createPdoConnection($dsn, $username, $password, $options)
if (class_exists(PDOConnection::class) && ! $this->isPersistentConnection($options)) {
return new PDOConnection($dsn, $username, $password, $options);
return new PDO($dsn, $username, $password, $options);
当 pdo 对象成功的建立起来后,说明我们已经与数据库成功地建立起来了一个连接,接下来我们就可以利用这个 pdo 对象进行查询或者更新等操作。
当创建 pdo 的时候抛出异常时:
protected function tryAgainIfCausedByLostConnection(Exception $e, $dsn, $username, $password, $options)
if ($this->causedByLostConnection($e)) {
return $this->createPdoConnection($dsn, $username, $password, $options);
throw $e;
protected function causedByLostConnection(Exception $e)
$message = $e->getMessage();
return Str::contains($message, [
'server has gone away',
'no connection to the server',
'Lost connection',
'is dead or not enabled',
'Error while sending',
'decryption failed or bad record mac',
'server closed the connection unexpectedly',
'SSL connection has been closed unexpectedly',
'Error writing data to the connection',
'Resource deadlock avoided',
]);
当判断出的异常是上面几种情况时,框架会再次尝试连接数据库。
configureEncoding——设置字符集与校对集
protected function configureEncoding($connection, array $config)
if (! isset($config['charset'])) {
return $connection;
$connection->prepare(
"set names '{$config['charset']}'".$this->getCollation($config)
)->execute();
protected function getCollation(array $config)
return ! is_null($config['collation']) ? " collate '{$config['collation']}'" : '';
如果配置参数中设置了字符集与校对集,程序会利用配置的参数对数据库进行相关设置。
所谓的字符集与校对集设置,可以参考mysql 中 character set 与 collation 的点滴理解
configureTimezone——设置时间区
protected function configureTimezone($connection, array $config)~
if (isset($config['timezone'])) {
$connection->prepare('set time_zone="'.$config['timezone'].'"')->execute();
setModes——设置 SQL_MODE 模式
protected function setModes(PDO $connection, array $config)
if (isset($config['modes'])) {
$this->setCustomModes($connection, $config);
} elseif (isset($config['strict'])) {
if ($config['strict']) {
$connection->prepare($this->strictMode())->execute();
} else {
$connection->prepare("set session sql_mode='NO_ENGINE_SUBSTITUTION'")->execute();
protected function setCustomModes(PDO $connection, array $config)
$modes = implode(',', $config['modes']);
$connection->prepare("set session sql_mode='{$modes}'")->execute();
protected function strictMode()
return "set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'";
以下内容参考:mysql的sql_mode设置简介:
SQL_MODE 直接理解就是:sql的运作模式。官方的说法是:sql_mode可以影响sql支持的语法以及数据的校验执行,这使得MySQL可以运行在不同的环境中以及和其他数据库一起运作。
想设置sql_mode有三种方式:
在命令行启动MySQL时添加参数 --sql-mode="modes"
在MySQL的配置文件(my.cnf或者my.ini)中添加一个配置sql-mode="modes"
运行时修改SQL mode可以通过以下命令之一:
SET GLOBAL sql_mode = 'modes';
SET SESSION sql_mode = 'modes';
几种常见的mode介绍
ONLY_FULL_GROUP_BY: 出现在 select 语句、HAVING 条件和 ORDER BY 语句中的列,必须是 GROUP BY 的列或者依赖于 GROUP BY 列的函数列。
NO_AUTO_VALUE_ON_ZERO: 该值影响自增长列的插入。默认设置下,插入0或 NULL 代表生成下一个自增长值。如果用户 希望插入的值为0,而该列又是自增长的,那么这个选项就有用了。
STRICT_TRANS_TABLES: 在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做限制
NO_ZERO_IN_DATE: 这个模式影响了是否允许日期中的月份和日包含0。如果开启此模式,2016-01-00是不允许的,但是0000-02-01是允许的。它实际的行为受到 strict mode 是否开启的影响1。
NO_ZERO_DATE: 设置该值,mysql 数据库不允许插入零日期。它实际的行为受到 strict mode 是否开启的影响2。
ERROR_FOR_DIVISION_BY_ZERO: 在 INSERT 或 UPDATE 过程中,如果数据被零除,则产生错误而非警告。如 果未给出该模式,那么数据被零除时 MySQL 返回 NULL
NO_AUTO_CREATE_USER: 禁止 GRANT 创建密码为空的用户
NO_ENGINE_SUBSTITUTION: 如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常
PIPES_AS_CONCAT: 将”||”视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似
ANSI_QUOTES: 启用 ANSI_QUOTES 后,不能用双引号来引用字符串,因为它被解释为识别符
本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由 Summer
于 5年前 加精
举报
leoyang
1.0k 声望
暂无个人描述~
58 人点赞
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
推荐文章:
更多推荐...
分享创造
如何找到你的第一份远程工作与海外外包-远程工作篇(放了个TS全栈教学的广告,不喜欢立删...)
33
21
1个月前
翻译
如何在 Laravel 中创建一个简单的事件流?
19
12
3个月前
博客
我是如何把网站图片cdn流量成本压到全网最低(之一)的
32
28
3个月前
博客
🎈 Slow Admin - 使用Laravel和Amis快速构建你的后台
25
35
3个月前
博客
用Go实现支持多种协议的抓包工具——Shermie-Proxy
22
33
5个月前
分享创造
大佬的收藏夹
75
21
5个月前
讨论数量: 12
高认可度评论:
leoyang
1.0k 声望
突然发现可以给自己点赞了:smiley:
5年前
评论
评论
举报
排序:
时间
投票
leoyang
1.0k 声望
突然发现可以给自己点赞了:smiley:
5年前
评论
评论
举报
景哥哥
课程读者
32 声望
图片挂了@leoyang
3年前
评论
评论
举报
mingyun
27 声望
图片都挂了
5年前
评论
评论
举报
leoyang
1.0k 声望
@mingyun 已经好啦
5年前
评论
评论
举报
萧潇
315 声望
感觉完全看Laravel的源码懂好难啊 大佬好厉害
5年前
评论
评论
举报
qloog
112 声望
必须给个 :+1:
5年前
评论
评论
举报
pickapig
0 声望
请问一下,如果想在获取读数据库失败的时候,重新选取其他的读库连接,这个功能应该怎么实现呢?
4年前
评论
评论
举报
景哥哥
课程读者
32 声望
我的基础比较差,这篇文章我已经看了至少十几遍了~~终于慢慢的清晰起来了,多谢分享
4年前
评论
评论
举报
majaja
2 声望
圖片又掛了 :sweat_smile:
3年前
评论
评论
举报
KaitoShy
0 声望
博主可以修一下图么?图挂了 :joy:
2年前
评论
评论
举报
郎中航
课程读者
185 声望
大佬牛逼
9个月前
评论
评论
举报
yzbfeng
44 声望
图挂了 www.gitbook.com/book/leoyang90/lar... 地址不可用
3个月前
评论
评论
举报
讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
<a href="javascript:;" class="mr-2 ui popover text-mute" data-html="黏贴或拖拽图片至输入框内皆可上传图片">
<a href="javascript:;" class="mr-2 ui popover text-mute hide-on-mobile" data-html="支持除了 H1~H6 以外的GitHub 兼容 Markdown">
支持 MD
帮助
关注本文
评论
leoyang
未填写
文章
86
粉丝
1168
喜欢
1297
收藏
561
排名:3
访问:79.8 万
关注
私信
所有博文
阅读模式
文章归档
2 篇
2018 年 10 月
10 篇
2018 年 9 月
16 篇
2018 年 8 月
6 篇
2018 年 7 月
11 篇
2018 年 6 月
3 篇
2018 年 1 月
4 篇
2017 年 12 月
1 篇
2017 年 11 月
7 篇
2017 年 10 月
4 篇
2017 年 9 月
8 篇
2017 年 8 月
6 篇
2017 年 7 月
8 篇
2017 年 5 月
最新文章
最受欢迎
4年前
Swoole 源码分析——Client 模块之 Recv
4年前
Swoole 源码分析——Client 模块之 Send
4年前
Swoole 源码分析——Client 模块之 Connect
4年前
Swoole 源码分析——进程管理 Swoole_Process
4年前
Swoole 源码分析——Async 异步事件系统 Swoole_Event
96
Laravel Queue——消息队列任务与分发源码剖析
82
Laravel 核心——IoC 服务容器
71
Laravel Exceptions——异常与错误处理
68
本专栏系列文章已经收录到 GitBook
60
PHP 自动加载功能原理解析
博客标签
php
laravel
swoole
https
openssl
ssl
社区赞助商
成为赞助商
社区赞助商
成为赞助商
关于 LearnKu
LearnKu 是终身编程者的修道场
做最专业、严肃的技术论坛
LearnKu 诞生的故事
资源推荐
《社区使用指南》
《文档撰写指南》
《LearnKu 社区规范》
《提问的智慧》
服务提供商
其他信息
成为版主
所有测验
联系站长(反馈建议)
粤ICP备18099781号-6
粤公网安备 44030502004330号
违法和不良信息举报
由 Summer 设计和编码 ❤
请登录
提交
忘记密码?
or
注册
第三方账号登录
微信登录
GitHub 登录
内容举报
匿名举报,为防止滥用,仅管理员可见举报者。
我要举报该,理由是:
垃圾广告:恶意灌水、广告、推广等内容
无意义内容:测试、灌水、文不对题、消极内容、文章品质太差等
违规内容:色情、暴利、血腥、敏感信息等
不友善内容:人身攻击、挑衅辱骂、恶意行为
科学上网:翻墙、VPN、Shadowsocks,政策风险,会被关站!
不懂提问:提问太随意,需要再做一遍《提问的智慧》测验
随意提问:提问没有发布在社区问答分类下
排版混乱:没有合理使用 Markdown 编写文章,未使用代码高亮
内容结构混乱:逻辑不清晰,内容混乱,难以阅读
标题随意:标题党、标题不释义
尊重版权:分享付费课程、破解软件(付费),侵犯作者劳动成果
其他理由:请补充说明
举报
取消