首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Laravel 数据库连接配置和读写分离

Laravel 数据库连接配置和读写分离

作者头像
学院君
发布于 2021-01-08 07:53:54
发布于 2021-01-08 07:53:54
6.5K00
代码可运行
举报
文章被收录于专栏:学院君的专栏学院君的专栏
运行总次数:0
代码可运行

今天开始讲如何在 Laravel 中操作数据库,Laravel 为我们提供了多种工具实现对数据库的增删改查,在我们使用 Laravel 提供的这些数据库工具之前,首先要连接到数据库。

数据库的连接配置文件位于 config/database.php,和很多其他 Laravel 配置一样,你可以为数据库配置多个「连接」,然后决定将哪个「连接」作为默认连接。

基本配置

默认情况下,Laravel 为支持的每一种数据库定义了一个连接配置项:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'connections' => [

    'sqlite' => [
        'driver' => 'sqlite',
        'database' => env('DB_DATABASE', database_path('database.sqlite')),
        'prefix' => '',
    ],

    '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', ''),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
    ],

    'pgsql' => [
        'driver' => 'pgsql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '5432'),
        'database' => env('DB_DATABASE', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        'charset' => 'utf8',
        'prefix' => '',
        'schema' => 'public',
        'sslmode' => 'prefer',
    ],

    'sqlsrv' => [
        'driver' => 'sqlsrv',
        'host' => env('DB_HOST', 'localhost'),
        'port' => env('DB_PORT', '1433'),
        'database' => env('DB_DATABASE', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        'charset' => 'utf8',
        'prefix' => '',
    ],

],

包括 SQLiteMySQL、PostgresSQL、SQL Server,一般我们默认使用的都是 MySQL:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'default' => env('DB_CONNECTION', 'mysql'),

当然,默认数据库连接、数据库名称以及数据库用户名和密码等敏感信息都保存到 .env 文件中了,然后通过 env 辅助函数读取:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

我们平时修改数据库连接信息的话修改这里就好了,默认配置值是针对 Homestead 开发环境配置的,如果你使用的是 Homestead 作为开发环境的话,开箱即用,不用做任何修改,如果不是的话则需要根据自己的环境做修改,比如学院君使用的是 Laradock,配置信息如下(数据库名称、用户名、密码以自己的环境为准,不要照搬):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravel57
DB_USERNAME=root
DB_PASSWORD=root

做好以上配置后,你就可以在 Laravel 项目中连接上 MySQL 数据库了。

配置多个数据库连接

有时候,我们的应用用到的不止一个数据库,或者做项目迁移的时候要做新老数据库之间的数据迁移,这个时候我们就可以配置多个数据库连接,如果我们的新老数据库使用的都是 MySQL 的话,可以在 config/database.phpconnections 配置项中新增一个 MySQL 连接:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'mysql_old' => [
    'driver' => 'mysql',
    'host' => env('DB_HOST_OLD', '127.0.0.1'),
    'port' => env('DB_PORT_OLD', '3306'),
    'database' => env('DB_DATABASE_OLD', 'forge'),
    'username' => env('DB_USERNAME_OLD', 'forge'),
    'password' => env('DB_PASSWORD_OLD', ''),
    'unix_socket' => env('DB_SOCKET_OLD', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

然后在 .env 中新增对应配置项:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
DB_CONNECTION_OLD=mysql
DB_HOST_OLD=mysql
DB_PORT_OLD=3306
DB_DATABASE_OLD=laravel56
DB_USERNAME_OLD=root
DB_PASSWORD_OLD=root

接下来,我们要怎样连上这个实例呢?默认情况下,我们在通过 Laravel 提供的数据库工具(DB 门面、查询构建器、Eloquent模型)连接数据库的时候,都没有显式指定连接,因为我们在配置文件中指定了默认的连接 mysql。所以要连接上其它连接很简单,在查询的时候指定这个新的连接就好了,如果你使用的是 DB 门面执行原生 SQL 查询,可以这么连接老的数据库:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$users = DB::connection('mysql_old')->select(...);
DB::connection('mysql_old')->insert(...);

如果你使用的是查询构建器进行数据库操作,可以这么指定(和原生操作一样):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$users = DB::connection('mysql_old')->table('users')->where(...)->get();
DB::connection('mysql_old')->table('users')->insert(...);

如果你使用的 Eloquent 模型类,可以在对应模型类中设置 $connection 属性:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected $connection = 'mysql_old';

这样,在模型类上执行查询、插入等操作时都会使用这个 mysql_old 数据库连接。

配置数据库读写分离连接

理论上来说,配置数据库读写分离连接也属于配置多个数据库连接的范畴,但是由于是一个比较特殊又很常见的使用场景,所以我们单独来讨论,Laravel 也对此进行了单独支持。

随着应用访问量的增长,对数据库进行读写分离可以有效的提升应用整体性能,关于数据库层面的读写分离配置不属于本教程讨论范畴,我们这里只讨论从应用层面如何在 Laravel 项目中配置读写分离连接。Laravel 框架数据库底层代码对数据库读写分离进行了支持,所以我们需要遵循底层实现进行读写分离配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'mysql' => [
    'driver' => 'mysql',
    'read' => [
        'host' => env('DB_HOST_READ', '127.0.0.1'),
    ],
    'write' => [
        'host' => env('DB_HOST_WRITE', '127.0.0.1')
    ],
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

read 项配置的是「读」连接,write 项配置的是「写」连接。然后在 .env 中新增 DB_HOST_READDB_HOST_WRITE 配置项。当然,对于 Web 应用而言,大多是读多写少,所以你还可以配置多个 read 主机,Laravel 底层的负载均衡机制是随机从配置的 IP 中挑一个连接:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'read' => [
    'host' => [env('DB_HOST_READ_1'), env('DB_HOST_READ_2')],
],

有的人会问,如果我们读写数据库的用户名、密码不一样咋办?好办,上面这种配置默认读写连接使用的用户名密码一样,那我们在读写配置项中分别独立配置就好了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'mysql' => [
    'driver' => 'mysql',
    'read' => [
        'host' => env('DB_HOST_READ', '127.0.0.1'),
        'username' => env('DB_USERNAME_READ', 'forge'),
        'password' => env('DB_PASSWORD_READ', ''),
    ],
    'write' => [
        'host' => env('DB_HOST_WRITE', '127.0.0.1'),
        'username' => env('DB_USERNAME_WRITE', 'forge'),
        'password' => env('DB_PASSWORD_WRITE', ''),
    ],
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

其他公共配置项也是同理,不再赘述。

针对读写分离数据库的连接,Laravel 数据库底层会自动判断,如果是查询语句会使用读连接,如果是数据库插入、更新、删除等操作会使用写连接。

读写分离本地模拟测试

我们可以在本地简单模拟测试下读写分离配置,我们使用同一个数据库主机,不同的数据库来进行读写分离,在数据库中创建一个新的数据库用作写数据库,并将其配置到 config/database.php

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'mysql' => [
   'driver' => 'mysql',
   'read' => [
       'host' => env('DB_HOST_READ', '127.0.0.1'),
       'database' => env('DB_DATABASE', 'db_read'),
   ],
   'write' => [
       'host' => env('DB_HOST_WRITE', '127.0.0.1'),
       'database' => env('DB_DATABASE_WRITE', 'db_write'),
   ],
   'port' => env('DB_PORT', '3306'),
   'username' => env('DB_USERNAME', 'root'),
   'password' => env('DB_PASSWORD', ''),
   'unix_socket' => env('DB_SOCKET', ''),
   'charset' => 'utf8mb4',
   'collation' => 'utf8mb4_unicode_ci',
   'prefix' => '',
   'strict' => true,
   'engine' => null,
],

然后我们在命令行运行 php artisan migrate,就会将数据库迁移应用到写数据库,因为数据库更新也属于写操作,所以此时自动判读使用写连接。

然后我们通过 Tinker 插入一条记录(插入属于写操作,自动使用写连接):

然后你会在写数据库中看到这条记录,读数据库中没有,接下来,我们运行一条查询语句(查询属于读操作,自动使用读连接):

此时,由于我们并没有配置读写数据库之间的数据同步,所以只能查出来我们在上一篇教程中在读数据库中插入的记录。所以在 Laravel 中实现读写分离还是很方便的,我们只需要做好配置就好了,剩下的框架帮我们完成。

当然,和多个数据库连接类似,你也可以在使用时显式进行指定,以查询构建器为例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
DB::connection('read')->table('users')->where(...)->get();
DB::connection('write')->table('users')->insert(...);

如果通过 Eloquent 模型类调用的话,还可以这么指定:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
User::on('read')->where(...)->get();
User::onWriteConnection()->save();

注:关于数据库的各种增删改查操作,后面会一一介绍。

读写分离配置中的 `sticky` 配置项

在读写分离配置中,我们注意到新增了一个 sticky 配置项,这个是用来干嘛的呢?

我们配置数据库读写分离的时候,会配置读数据库(从库)从写数据库(主库)同步数据,由于不同主机之间数据同步是需要时间的,虽然这个时间很短,但是对于并发量很大的应用,还是可能出现写入写数据库的数据不能立即从读数据库读取到的情况,sticky 配置项在这个时候就派上用场了。如果该配置项设置为 true 的话,在同一个请求生命周期中,写入的数据会被立刻读取到,底层原理其实就是读操作也从写数据库读取,因为写数据库始终是最新数据,从而避免主从同步延迟导致的数据不一致。

其它配置项

除了上面提到的数据库连接配置外,config/database.php 配置文件中还有一些其它配置项,你可以通过 migrations 配置项自定义数据库迁移表的名称,默认是 migrations

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'migrations' => 'migrations',

还可以通过 redis 配置项配置 Redis 作为 NoSQL 数据库的连接配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'redis' => [

    'client' => 'predis',

    'default' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_DB', 0),
    ],

    'cache' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_CACHE_DB', 1),
    ],

],

你可以看到 Redis 也支持多个连接,一个默认连接和一个用作缓存的 cache 连接。这一思想在 Laravel 配置中无处不在,很多服务都支持配置多个连接提供不同的驱动,比如 Session 支持文件、数据表等连接,缓存支持 Memcached、Redis 等连接,队列支持数据库、Beanstalkd 等连接。你可以为它们定义多个连接,然后指定一个默认连接,这样做的好处是,当某个连接出现问题,或者你想切换到其它实现,只需动动手指头修改下配置文件中的默认配置项就好了,极大的提高了系统的可维护性。

注:关于 Redis 我们会在后面单独讲,这里不做深入讨论。

本系列教程首发在学院君网站(xueyuanjun.com),你可以点击页面左下角阅读原文链接查看最新更新的教程。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 极客书房 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
内置于浏览器中的国际化API[每日前端夜话0xBA]
你的程序很有可能需要支持多种语言。其中包括对语言敏感的日期处理。一个广受欢迎的库Moment.js【https://www.npmjs.com/package/moment】有助于实现这一目标,它的功能之一是国际化。其源代码【https://github.com/moment/moment/blob/develop/locale/en-gb.js】中包含对许多不同语言的本地化。现在这可能已经不是最好的方法了,因为我们有 ECMAScript 国际化 API。
疯狂的技术宅
2019/09/10
1.7K0
内置于浏览器中的国际化API[每日前端夜话0xBA]
91.HarmonyOS NEXT 应用国际化与本地化指南:打造全球化应用
通过合理的国际化和本地化策略,可以使应用更好地适应全球市场。在实际开发中,要注意平衡功能完整性和性能表现,确保良好的用户体验。
全栈若城
2025/03/16
2320
Javascript 字符串与文本格式化
JavaScript中的 String 类型用于表示文本型的数据. 它是由无符号整数值(16bit)作为元素而组成的集合. 字符串中的每个元素在字符串中占据一个位置. 第一个元素的index值是0, 下一个元素的index值是1, 以此类推. 字符串的长度就是字符串中所含的元素个数.你可以通过String字面值或者String对象两种方式创建一个字符串。
acc8226
2022/05/17
9490
什么,你还在用 momentJs 处理相对时间
我想,下面这段代码,你是不是在开发中常常这样使用来计算距离现在过去了多长时间: import moment from 'moment' // 61k (gzipped:19.k) function
前端修罗场
2023/10/07
3840
什么,你还在用 momentJs 处理相对时间
你不知道的JavaScript APIs
这个APi 可以让我们知道用户何时离开了页面。准确地说,只要页面的可见性状态发生变化,无论是用户最小化、最大化窗口还是切换标签,该API都会触发一个事件 visibilitychange 。
前端小智@大迁世界
2022/10/28
9670
JS魔法堂:不完全国际化&本地化手册 之 理論篇
前言  最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求——国际化&本地化。熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已。趁着这个机会好好学习整理一下,为后面的技术选型做准备。  本篇将阐述国际化和本地化的概念,以及其中一个很重要的概念——Language tag(也叫Language code 或 Culture)。 何为国际化?  国际化我认为就是应用支持多语言和文化习俗(数字、货币、日期和字符比较算法等),而本地化则是应用能识别用户所属文化习俗自动适
^_^肥仔John
2018/01/18
8950
105.精读《What's new in javascript》
2019 年 Google I/O 介绍了一些激动人心的 JS 新特性,这些特性有些已经被主流浏览器实现,并支持 polyfill,有些还在草案阶段。
黄子毅
2022/03/14
6100
AI辅助开发实践 :前端国际化(i18n)在多语言供应链平台中的完整方案
我们的供应链系统需要服务来自不同国家和地区的用户。前端作为用户直接交互的界面,其国际化(i18n)支持程度直接影响用户体验和操作效率。一个完善的国际化方案不仅涉及文本翻译,还包括日期、货币、数字格式的本地化处理,以及从右到左(RTL)语言布局支持等复杂考虑。
叶一一
2025/09/21
3350
AI辅助开发实践 :前端国际化(i18n)在多语言供应链平台中的完整方案
JS魔法堂:不完全国际化&本地化手册 之 拓展篇
前言  最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求——国际化&本地化。熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已。趁着这个机会好好学习整理一下,为后面的技术选型做准备。  本篇作为系列的最后一篇,打算和大家一起看看HTTP的Content Negotiation机制和更多关于本地化的应用方向。 Content Negotiation(内容协同)  记得第一次接触国际化和本地化时是指服务端根据请求头字段Accept-Language获取languag
^_^肥仔John
2018/01/18
5660
JS魔法堂:不完全国际化&本地化手册 之 拓展篇
用CodeBuddy重构老旧的JavaScript工具类
友友们,早上好。今天继续AI工具实战系列。我将分享最近几个月使用ai工具用于工作的那些事。既是一次知识的分享,又是一次自我的一次总结,也希望自己的一些使用经验可以帮助到大家。下面正文开始。
china马斯克
2025/09/14
1680
用CodeBuddy重构老旧的JavaScript工具类
一起来看看 Node.js v14.x LTS 中的这些新功能
作者简介:五月君,Software Designer,公众号「Nodejs技术栈」作者。 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时。在 2020 年 10 月 27 日 Node.js v14.15.0 LTS 版已发布,即长期支持版本,其中包含了很多很棒的新功能,以下内容也是基于笔者在日常 Node.js 工作和学习中所总结的,可能不全,同时也欢迎补充,有些功能之前也曾单独写过文章来介绍,接下让我们一起看看都有哪些新的变化?
五月君
2021/02/24
1.1K0
一起来看看 Node.js v14.x LTS 中的这些新功能
记一次平淡无奇的性能优化
甘特图的主要作用是项目管理,可以用图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间,如下图
玖柒的小窝
2021/09/24
5410
记一次平淡无奇的性能优化
为什么到了时间你的活动还没开始——探究Date对象
假设有一个活动,原计划定的是12月25日早上8点开始,结果苹果用户到了早上8点却看见活动按钮还是灰色的,而且PC、安卓都是正常。这种情况如果发生,首先往哪个方向考虑呢?
lhyt
2019/09/08
1.8K0
JavaScript原生实战手册 · 日期处理完全指南:不再依赖Moment.js
在Web开发中,日期处理无处不在。从社交媒体的"3分钟前",到电商网站的订单时间,再到日历应用的日程安排,几乎每个项目都需要处理日期格式化、时间计算、相对时间显示等功能。很多开发者因为JavaScript原生Date对象的"难用"而选择了Moment.js或date-fns等库,但其实我们完全可以用原生JavaScript打造一个功能强大、使用简单的日期处理工具。
前端达人
2025/10/09
1450
JavaScript原生实战手册 · 日期处理完全指南:不再依赖Moment.js
HarmonyOS NEXT实战:千分分隔符工具
##HarmonyOS Next实战##HarmonyOS SDK应用服务##教育##
中雨
2025/06/25
1500
Node.js v19,它来了!详解 6 大特性
通译自:6 Major Features of Node.js 19. Details of Node.js 19 new features… | by Jennifer Fu | Oct, 2022 | Better Programming
掘金安东尼
2022/11/30
1K0
Node.js v19,它来了!详解 6 大特性
Java国际化/本地化实战
开发一个支持多国语言的Web应用程序,要求系统能够根据客户端的系统的语言类型返回对应的界面:英文的操作系统返回英文界面,而中文的操作系统则返回中文界面——这便是典型的i18n国际化问题。
JavaEdge
2020/05/27
2.6K0
Java国际化/本地化实战
JavaScript ES2021最值得期待的新特性解析
每年,JavaScript 的更新都会添加新特性。今年发布的是 ES2020 或称 ES11,预计 ES2021 或称 ES12 将于 2021 年中发布。添加到 JavaScript 的新特性都会经历四个阶段。在本文中,我将讨论已经进入第四阶段且已添加到谷歌 Chrome V8 引擎中的新特性。
深度学习与Python
2020/11/06
8990
JavaScript ES2021最值得期待的新特性解析
你不知道的JavaScript APIs
这是一个鲜为人知的 web API,在JS现状调查[1]中,它的认知度排名倒数第四。它可以让你知道用户何时离开了页面。准确地说,只要页面的可见性状态发生变化,无论是用户最小化、最大化窗口还是切换标签页,该API都会触发一个事件。
chuckQu
2022/11/28
1.2K0
你不知道的JavaScript APIs
【JS】201-JavaScript 日期权威指南
在内部,日期以1970年1月1日(UTC)以来的毫秒数表示。这个日期很重要,因为就计算机而言,这就是一切开始的地方。
pingan8787
2019/07/23
3.1K0
【JS】201-JavaScript 日期权威指南
推荐阅读
相关推荐
内置于浏览器中的国际化API[每日前端夜话0xBA]
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档