1. A multi-tenant system contains multiple tenants, and each tenant has its own database configuration. The current requirement is to connect to the database by calling the multi-tenant system’s API and using the hostname, username, and password from the response, rather than configuring it as an application component, as shown in Figure 1.

2. Currently, it is configured as an application component in \common\config\base.php, as shown in Figure 2.

3. Enable Debug and check the Log Messages. The properties of the db component must be initialized (by calling the multi-tenant system’s API) before yii\db\Connection::open is executed, as shown in Figure 3.

4. Edit \common\config\base.php to configure the db component’s class as common\components\db\Connection, and comment out all environment variables.
'db'=>[
'class'=>'common\components\db\Connection',
// 'dsn' => env('DB_DSN'),
// 'username' => env('DB_USERNAME'),
// 'password' => env('DB_PASSWORD'),
// 'tablePrefix' => env('DB_TABLE_PREFIX'),
'charset' => 'utf8',
'enableSchemaCache' => YII_ENV_PROD,
],
5. Create \common\components\db\Connection.php, which extends \yii\db\Connection.
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/01/15
* Time: 16:18
*/
namespace common\components\db;
use Yii;
use yii\helpers\ArrayHelper;
/**
* 获取租户模块环境配置信息,存储至Redis,注册db组件
*
* @author Qiang Wang <shuijingwanwq@163.com>
* @since 1.0
*/
class Connection extends \yii\db\Connection
{
public function __construct($config = [])
{
// ... 配置生效前的初始化过程
$tenantConfig = [
'dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=cmcp-api',
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'tablePrefix' => env('DB_TABLE_PREFIX'),
];
if (!empty($config)) {
$config = ArrayHelper::merge($config, $tenantConfig);
}
parent::__construct($config);
}
}
6. Repeat step 3. The properties of the db component have already been initialized before yii\db\Connection::open is executed (host=localhost changed to host=127.0.0.1), as shown in Figure 4.

7. Now we need to call the multi-tenant system’s API and reassign $tenantConfig based on its response (Recommendation: This approach is only suitable for a single tenant. If there are multiple tenants, it is recommended that each tenant corresponds to a different connection component named based on the tenant ID, rather than mapping to the db connection component), as shown in Figure 5.

8. Now revert all changes and prepare to implement the simultaneous use of multiple databases (where each tenant corresponds to a different connection component named based on the tenant ID). Reference URL: https://github.com/yiichina/yii2/blob/master/docs/guide-zh-CN/db-active-record.md , as shown in Figure 6.

9. Create \common\components\db\ActiveRecord.php, which extends \yii\db\ActiveRecord, and override the [[yii\db\ActiveRecord::getDb()|getDb()]] method.
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/01/16
* Time: 10:31
*/
namespace common\components\db;
use Yii;
/**
* 获取租户模块环境配置信息,存储至Redis,注册数据库连接组件
*
* @author Qiang Wang <shuijingwanwq@163.com>
* @since 1.0
*/
class ActiveRecord extends \yii\db\ActiveRecord
{
/**
* Returns the database connection used by this AR class.
* By default, the "db" application component is used as the database connection.
* You may override this method if you want to use a different database connection.
* @return Connection the database connection used by this AR class.
*/
public static function getDb()
{
$tenantDb = new \yii\db\Connection([
'dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=cmcp-api',
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'tablePrefix' => env('DB_TABLE_PREFIX'),
'charset' => 'utf8',
'enableSchemaCache' => YII_ENV_PROD,
]);
return $tenantDb;
// return Yii::$app->getDb();
}
}
10. Edit \common\models\KeyStorageItem.php to extend common\components\db\ActiveRecord.
<?php
namespace common\models;
use Yii;
use yii\behaviors\TimestampBehavior;
use common\components\db\ActiveRecord;
/**
* This is the model class for table "key_storage_item".
*
* @property integer $key
* @property integer $value
*/
class KeyStorageItem extends ActiveRecord
{
}11. Edit \common\config\base.php and comment out the db component. Later, it is recommended to move the db component to the development environment to facilitate the use of Gii.
/*
'db'=>[
'class'=>'yii\db\Connection',
'dsn' => env('DB_DSN'),
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'tablePrefix' => env('DB_TABLE_PREFIX'),
'charset' => 'utf8',
'enableSchemaCache' => YII_ENV_PROD,
],
*/
12. Open http://frontend.cmcp-api.localhost/ , and an error occurs: Failed to instantiate component or class “db”. The reason is that the log target is a database table, as shown in Figure 7.

13. View the log component configuration in \common\config\base.php.
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
'db'=>[
'class' => 'yii\log\DbTarget',
'levels' => ['error', 'warning'],
'except'=>['yii\web\HttpException:*', 'yii\i18n\I18N\*'],
'prefix'=>function () {
$url = !Yii::$app->request->isConsoleRequest ? Yii::$app->request->getUrl() : null;
return sprintf('[%s][%s]', Yii::$app->id, $url);
},
'logVars'=>[],
'logTable'=>'{{%system_log}}'
]
],
],
14. The log component must be loaded during bootstrap. Therefore, if the database connection is dynamically configured, it is already too late for the bootstrap phase. Edit the log component configuration in \common\config\base.php to save log messages to a file.
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
'file'=>[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
'except' => ['yii\web\HttpException:*', 'yii\i18n\I18N\*'],
'prefix' => function () {
$url = !Yii::$app->request->isConsoleRequest ? Yii::$app->request->getUrl() : null;
return sprintf('[%s][%s]', Yii::$app->id, $url);
},
'logVars'=>[],
]
],
],
15. Open http://frontend.cmcp-api.localhost/ , and an error occurs: Unknown component ID: db, as shown in Figure 8.

16. In all model files under \common\models, replace use yii\db\ActiveRecord; with use common\components\db\ActiveRecord;, as shown in Figure 9.
Replace use yii\db\ActiveRecord; with use common\components\db\ActiveRecord;
Replace \yii\db\ActiveRecord with \common\components\db\ActiveRecord

17. Open http://frontend.cmcp-api.localhost/ , and an error occurs: Failed to instantiate component or class “db”. The reason is that the RBAC component uses a database table to store data, as shown in Figure 10.

18. Edit \common\config\base.php and comment out the RBAC component. Because its db property defaults to db, it needs to be dynamically adjusted to the database connection component corresponding to the tenant ID.
/*
'authManager' => [
'class' => 'yii\rbac\DbManager',
'itemTable' => '{{%rbac_auth_item}}',
'itemChildTable' => '{{%rbac_auth_item_child}}',
'assignmentTable' => '{{%rbac_auth_assignment}}',
'ruleTable' => '{{%rbac_auth_rule}}'
],
*/
19. Edit \common\components\db\ActiveRecord.php to register the database connection component and RBAC component via the [[yii\di\ServiceLocator::setComponents()]] method.
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/01/16
* Time: 10:31
*/
namespace common\components\db;
use Yii;
/**
* 获取租户模块环境配置信息,存储至Redis,注册数据库连接组件
*
* @author Qiang Wang <shuijingwanwq@163.com>
* @since 1.0
*/
class ActiveRecord extends \yii\db\ActiveRecord
{
/**
* Returns the database connection used by this AR class.
* By default, the "db" application component is used as the database connection.
* You may override this method if you want to use a different database connection.
* @return Connection the database connection used by this AR class.
*/
public static function getDb()
{
$tenantDb = 'defaultDb';
// 注册数据库连接组件、RBAC组件
Yii::$app->setComponents([
$tenantDb => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=cmcp-api',
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'tablePrefix' => env('DB_TABLE_PREFIX'),
'charset' => 'utf8',
'enableSchemaCache' => YII_ENV_PROD,
],
'authManager' => [
'class' => 'yii\rbac\DbManager',
'db' => $tenantDb,
'itemTable' => '{{%rbac_auth_item}}',
'itemChildTable' => '{{%rbac_auth_item_child}}',
'assignmentTable' => '{{%rbac_auth_assignment}}',
'ruleTable' => '{{%rbac_auth_rule}}'
],
]);
return Yii::$app->$tenantDb;
}
}
20. Repeat step 3. The properties of the db component have already been initialized before yii\db\Connection::open is executed (host=localhost changed to host=127.0.0.1), as shown in Figure 11.

21. In Postman, send a GET request to http://www.cmcp-api.localhost/v1/pages , and receive a 200 response, as shown in Figure 12.

22. Open the URL: http://backend.cmcp-api.localhost/ , and an error occurs: Unknown component ID: db, as shown in Figure 13.

23. Edit \backend\models\SystemLog.php to extend \common\components\db\ActiveRecord, as shown in Figure 14.
Replace \yii\db\ActiveRecord with \common\components\db\ActiveRecord

24. Open the URL: http://backend.cmcp-api.localhost/ , and receive a 200 response.
25. Now we need to call the multi-tenant system’s API and use its response to directly initialize the database connection and RBAC, based on the already installed Yii 2 HTTP client extension, as shown in Figure 15.

26. Edit \.env.dist and \.env to add the multi-tenant related configuration.
# Multi-tenant
# ----
TENANT_HOST_INFO = http://wjdev.chinamcloud.com:8600 # HOME URL
TENANT_BASE_URL = /interface # BASE URL
TENANT_APP_NAME = cmcpapi # Module English name
TENANT_SECRET = 94030d307b160f04b88592cb9bebdd4c # Module Secret
27. Edit \common\config\bootstrap.php to set aliases.
Yii::setAlias('@tenantUrl', env('TENANT_HOST_INFO') . env('TENANT_BASE_URL'));
28. Configure the client via application components. Edit \common\config\web.php, as shown in Figure 16.
'tenantHttp' => [
'class' => 'yii\httpclient\Client',
'baseUrl' => Yii::getAlias('@tenantUrl'),
'transport' => 'yii\httpclient\CurlTransport'
],

29. Log the HTTP requests sent and analyze their execution by configuring the log. Edit \common\config\base.php, as shown in Figure 17.
'httpRequest'=>[
'class' => 'yii\log\FileTarget',
'logFile' => '@runtime/logs/http-request.log',
'categories' => ['yii\httpclient\*'],
]

30. The yii2 HTTP client extension provides a debug panel that integrates with the yii debug module and displays executed HTTP requests. Enable the debug panel, as shown in Figure 18.
$config['modules']['debug'] = [
'class' => 'yii\debug\Module',
'allowedIPs' => ['127.0.0.1', '::1', '192.168.33.1', '172.17.42.1', '172.17.0.1', '192.168.99.1'],
'panels' => [
'httpclient' => [
'class' => 'yii\httpclient\debug\HttpClientPanel',
],
],
];

31. After refreshing the page, check the log panel. A new HTTP Client section appears, as shown in Figure 19.

32. Create \common\logics\http\tenant\Env.php. The http directory indicates that the model data within this directory originates from HTTP requests; the tenant directory indicates models related to the multi-tenant system; and Env.php represents the environment configuration model.
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/01/17
* Time: 15:20
*/
namespace common\logics\http\tenant;
use Yii;
use yii\base\Model;
use yii\web\ServerErrorHttpException;
/**
* 多租户的模块环境配置
*
* @author Qiang Wang <shuijingwanwq@163.com>
* @since 1.0
*/
class Env extends Model
{
public $app_name;
public $secret;
public $tenant_id;
public function attributeLabels()
{
return [
'app_name' => \Yii::t('model/http/tenant/env', 'App Name'),
'secret' => \Yii::t('model/http/tenant/env', 'Secret'),
'tenant_id' => \Yii::t('model/http/tenant/env', 'Tenant ID'),
];
}
/**
* 返回租户模块环境配置信息
*
* @return array|false
*
* 格式如下:
*
* 租户模块环境配置信息
* [
* 'message' => '', //说明
* 'data' => [], //数据
* ]
*
* 失败(将错误保存在 [[yii\base\Model::errors]] 属性中)
* false
*
* @throws ServerErrorHttpException 如果响应状态码不等于20x
*/
public function getTenantEnv()
{
$this->app_name = env('TENANT_APP_NAME');
$this->secret = env('TENANT_SECRET');
/* 租户ID后续从请求参数中获取 */
$this->tenant_id = 'default';
$response = Yii::$app->tenantHttp->createRequest()
->setMethod('get')
->setUrl('getTenantEnvs')
->setData([
'appname' => $this->app_name,
'secret' => $this->secret,
'tenantid1' => $this->tenant_id,
])
->send();
// 检查响应状态码是否等于20x
if ($response->isOk) {
// 检查业务逻辑是否成功
if ($response->data['returnCode'] === 0) {
return ['message' => $response->data['returnDesc'], 'data' => $response->data['returnData']];
} else {
$this->addError('tenant_id', $response->data['returnDesc']);
return false;
}
} else {
throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '20005'), ['statusCode' => $response->getStatusCode()])));
}
}
}
33. Create language pack files: \common\messages\en\model\http\tenant\env.php and \common\messages\zh\model\http\tenant\env.php, as shown in Figure 20.
\common\messages\en\model\http\tenant\env.php
return [
'App Name' => 'English name of the module',
'Secret' => 'Secret module in multi-tenant system',
'Tenant ID' => 'Tenant ID',
];
\common\messages\zh\model\http\tenant\env.php
return [
'App Name' => '模块英文名称',
'Secret' => '模块Secret',
'Tenant ID' => '租户ID',
];

34. Edit the language pack files \api\messages\en\error.php and \api\messages\zh\error.php.
\api\messages\en\error.php
20005 => 'Multitenant HTTP request failed with status code: {statusCode}',
20006 => 'Multitenant HTTP request failed: {firstErrors}',
\api\messages\zh\error.php
20005 => '多租户HTTP请求失败,状态码:{statusCode}',
20006 => '多租户HTTP请求失败:{firstErrors}',
35. Copy \api\messages\en\app.php, \api\messages\en\error.php, \api\messages\zh\app.php, and \api\messages\zh\error.php to \common\messages\en\app.php, \common\messages\en\error.php, \common\messages\zh\app.php, and \common\messages\zh\error.php. Edit:
\common\messages\zh\error.php
return [
20000 => 'error',
20005 => '多租户HTTP请求失败,状态码:{statusCode}',
20006 => '多租户HTTP请求失败:{firstErrors}',
];
36. Edit \common\components\db\ActiveRecord.php. The database configuration information is sourced from the tenant environment configuration API.
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/01/16
* Time: 10:31
*/
namespace common\components\db;
use Yii;
use common\logics\http\tenant\Env;
use yii\web\ServerErrorHttpException;
/**
* 获取租户模块环境配置信息,存储至Redis,注册数据库连接组件
*
* @author Qiang Wang <shuijingwanwq@163.com>
* @since 1.0
*/
class ActiveRecord extends \yii\db\ActiveRecord
{
/**
* Returns the database connection used by this AR class.
* By default, the "db" application component is used as the database connection.
* You may override this method if you want to use a different database connection.
* @return Connection the database connection used by this AR class.
*/
public static function getDb()
{
$env = new Env();
$tenantEnv = $env->getTenantEnv();
if ($tenantEnv === false) {
if ($env->hasErrors()) {
foreach ($env->getFirstErrors() as $message) {
$firstErrors = $message;
}
throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '20006'), ['firstErrors' => $firstErrors])));
} elseif (!$env->hasErrors()) {
throw new ServerErrorHttpException('Multi-tenant HTTP requests fail for unknown reasons.');
}
}
$tenantDb = $tenantEnv['data']['tenantid'] . 'Db';
// 注册数据库连接组件、RBAC组件
Yii::$app->setComponents([
$tenantDb => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=' .$tenantEnv['data']['db_info']['host'] . ';port=3306;dbname=' . $tenantEnv['data']['db_info']['database'] . '',
'username' => $tenantEnv['data']['db_info']['login'],
'password' => $tenantEnv['data']['db_info']['password'],
'tablePrefix' => $tenantEnv['data']['db_info']['prefix'],
'charset' => 'utf8',
'enableSchemaCache' => YII_ENV_PROD,
],
'authManager' => [
'class' => 'yii\rbac\DbManager',
'db' => $tenantDb,
'itemTable' => '{{%rbac_auth_item}}',
'itemChildTable' => '{{%rbac_auth_item_child}}',
'assignmentTable' => '{{%rbac_auth_assignment}}',
'ruleTable' => '{{%rbac_auth_rule}}'
],
]);
return Yii::$app->$tenantDb;
}
}
37. In Postman, send a GET request to http://www.cmcp-api.localhost/v1/pages , and receive a 200 response, as shown in Figure 21.

38. In Postman, send a GET request to the multi-tenant environment configuration API with one incorrect parameter, as shown in Figure 22.

39. Edit \.env. The value of TENANT_APP_NAME is incorrect.
TENANT_APP_NAME = cmcpapi1 # Module English name
40. In Postman, send a GET request to http://www.cmcp-api.localhost/v1/pages , and receive a 500 response, as shown in Figure 23.

41. Checking the logs, I found that the API application and the backend application made 8 and 139 requests to the multi-tenant API, respectively. The backend reported an error: Unable to send log via yii\log\FileTarget: Exception (Database Exception) ‘yii\db\Exception’ with message ‘SQLSTATE[HY000] [1040] Too many connections’ , as shown in Figures 24 and 25.

![The backend reported an error: Unable to send log via yii\log\FileTarget: Exception (Database Exception) 'yii\db\Exception' with message 'SQLSTATE[HY000] [1040] Too many connections'](https://media.shuijingwanwq.com/2018/01/25-1.png)
42. Check whether the database connection component and RBAC component have already been registered; if they have, there is no need to overwrite them. Edit \common\components\db\ActiveRecord.php, as shown in Figure 26.
// 检查数据库连接组件、RBAC组件是否被注册
if (!(Yii::$app->has($tenantDb) && Yii::$app->has('authManager'))) {
// 注册数据库连接组件、RBAC组件
Yii::$app->setComponents([
$tenantDb => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=' . $tenantEnv['data']['db_info']['host'] . ';port=3306;dbname=' . $tenantEnv['data']['db_info']['database'] . '',
'username' => $tenantEnv['data']['db_info']['login'],
'password' => $tenantEnv['data']['db_info']['password'],
'tablePrefix' => $tenantEnv['data']['db_info']['prefix'],
'charset' => 'utf8',
'enableSchemaCache' => YII_ENV_PROD,
],
'authManager' => [
'class' => 'yii\rbac\DbManager',
'db' => $tenantDb,
'itemTable' => '{{%rbac_auth_item}}',
'itemChildTable' => '{{%rbac_auth_item_child}}',
'assignmentTable' => '{{%rbac_auth_assignment}}',
'ruleTable' => '{{%rbac_auth_rule}}'
],
]);
}

43. The backend application error ‘SQLSTATE[HY000] [1040] Too many connections’ has been resolved, as shown in Figure 27.
![The backend application error 'SQLSTATE[HY000] [1040] Too many connections' has been resolved.](https://media.shuijingwanwq.com/2018/01/27-1.png)
44. At this point, the dynamic configuration of the database connection—with configuration properties sourced from the multi-tenant system—has been largely implemented. Next, I should implement caching for the multi-tenant system’s responses, because a single request can trigger up to hundreds of HTTP requests to the multi-tenant system, with each HTTP request taking an average of about 100ms, as shown in Figure 28.

45. Enable Schema caching (only in the production environment) and cache it in Redis. Edit \.env.dist and \.env, as shown in Figure 29.
YII_ENV = prod
# Redis
# ----
REDIS_HOSTNAME = localhost # Hostname/IP address
REDIS_PORT = 6379 # Port
#REDIS_PASSWORD = # Password
REDIS_DATABASE = 0 # Database
# Redis cache
# ----
REDIS_CACHE_KEY_PREFIX = ca: # Unique key prefix

46. Edit \common\config\base.php to configure the Redis connection and the cache component within the application configuration.
'redisCache' => [
'class' => 'yii\redis\Cache',
'keyPrefix' => env('REDIS_CACHE_KEY_PREFIX'), // 唯一键前缀
],
'redis' => [
'class' => 'yii\redis\Connection',
'hostname' => env('REDIS_HOSTNAME'),
'port' => env('REDIS_PORT'),
'password' => env('REDIS_PASSWORD'),
'database' => env('REDIS_DATABASE'),
],
47. Enable Schema caching in the database connection. Edit \common\components\db\ActiveRecord.php.
// 检查数据库连接组件、RBAC组件是否被注册
if (!(Yii::$app->has($tenantDb) && Yii::$app->has('authManager'))) {
// 注册数据库连接组件、RBAC组件
Yii::$app->setComponents([
$tenantDb => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=' . $tenantEnv['data']['db_info']['host'] . ';port=3306;dbname=' . $tenantEnv['data']['db_info']['database'] . '',
'username' => $tenantEnv['data']['db_info']['login'],
'password' => $tenantEnv['data']['db_info']['password'],
'tablePrefix' => $tenantEnv['data']['db_info']['prefix'],
'charset' => 'utf8',
'enableSchemaCache' => YII_ENV_PROD,
'schemaCache' => 'redisCache',
],
'authManager' => [
'class' => 'yii\rbac\DbManager',
'db' => $tenantDb,
'itemTable' => '{{%rbac_auth_item}}',
'itemChildTable' => '{{%rbac_auth_item_child}}',
'assignmentTable' => '{{%rbac_auth_assignment}}',
'ruleTable' => '{{%rbac_auth_rule}}'
],
]);
}
48. After running the backend application, check the data in Redis. The structure of the database tables has been cached, as shown in Figure 30.

49. Implement caching for the multi-tenant system’s responses. Edit \common\logics\http\tenant\Env.php. After running the backend application, check the data in Redis. The response data from the multi-tenant system has been cached, as shown in Figure 31.
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/01/17
* Time: 15:20
*/
namespace common\logics\http\tenant;
use Yii;
use yii\base\Model;
use yii\web\ServerErrorHttpException;
/**
* 多租户的模块环境配置
*
* @author Qiang Wang <shuijingwanwq@163.com>
* @since 1.0
*/
class Env extends Model
{
public $app_name;
public $secret;
public $tenant_id;
public function attributeLabels()
{
return [
'app_name' => \Yii::t('model/http/tenant/env', 'App Name'),
'secret' => \Yii::t('model/http/tenant/env', 'Secret'),
'tenant_id' => \Yii::t('model/http/tenant/env', 'Tenant ID'),
];
}
/**
* 返回租户模块环境配置信息
*
* @return array|false
*
* 格式如下:
*
* 租户模块环境配置信息
* [
* 'message' => '', //说明
* 'data' => [], //数据
* ]
*
* 失败(将错误保存在 [[yii\base\Model::errors]] 属性中)
* false
*
* @throws ServerErrorHttpException 如果响应状态码不等于20x
*/
public function getTenantEnv()
{
/* 租户ID后续从请求参数中获取 */
$this->tenant_id = 'default';
// 设置多租户数据的缓存键
$redisCache = Yii::$app->redisCache;
$tenantKey = 'tenant:' . $this->tenant_id;
// 从缓存中取回多租户数据
$tenantData = $redisCache[$tenantKey];
if ($tenantData === false) {
$this->app_name = env('TENANT_APP_NAME');
$this->secret = env('TENANT_SECRET');
$response = Yii::$app->tenantHttp->createRequest()
->setMethod('get')
->setUrl('getTenantEnv')
->setData([
'appname' => $this->app_name,
'secret' => $this->secret,
'tenantid' => $this->tenant_id,
])
->send();
// 检查响应状态码是否等于20x
if ($response->isOk) {
// 检查业务逻辑是否成功
if ($response->data['returnCode'] === 0) {
$tenantData = ['message' => $response->data['returnDesc'], 'data' => $response->data['returnData']];
// 将多租户数据存放到缓存供下次使用
$redisCache[$tenantKey] = $tenantData;
return $tenantData;
} else {
$this->addError('tenant_id', $response->data['returnDesc']);
return false;
}
} else {
throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '20005'), ['statusCode' => $response->getStatusCode()])));
}
} else {
return $tenantData;
}
}
}

50. After clearing Redis, a single request only triggers 1 HTTP request to the multi-tenant system, as shown in Figure 32.

51. By default, data in the cache will persist permanently unless it is forcibly removed by certain cache eviction policies (for example, if the cache space is full, the oldest data will be removed). Next, I plan to implement an interface to clear the corresponding cached data, so that when the multi-tenant system’s data changes, the interface can be called to clear the relevant cache.
