Yii2多数据库连接:根据登录用户ID运行时选择数据库

时间:2019-07-19 05:37:57

标签: yii2 yii2-advanced-app

这是我的情况。

我在“主”数据库中有使用我的应用程序的所有诊所的列表。在“主目录”中,有关每个诊所的信息在一个表中,该表中还包含用于数据库的数据库名称,用户名和密码的列。每个架构的结构都相同。

所有这些诊所将使用我目前在Yii2中开发的单一源代码。我需要的是在登录时自动选择相应的数据库,所有交易必须都在数据库中。

我尝试在会话中保存数据库名称。

$db_name = "main";

if( isset($_SESSION['db']) ){
    $db_name = $_SESSION['db'];
}
$config = [
    'components' => [
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=localhost;dbname='.$db_name,
            'username' => 'root',
            'password' => '',
            'charset' => 'utf8',
        ],
    ],
];

它不起作用,我无法在config / main.php中访问会话。

我无法执行解决方案,因为所有诊所都具有相同的SERVER_NAME。 Change DB connection Dynamically

2 个答案:

答案 0 :(得分:0)

如果您有一个“主”数据库,然后将主数据库连接记录用于第二个数据库: 最好将db2配置为NULL db连接,然后:

'db' => $db, // default...,
'db2' => [
    // Fill with null values
],

Yii::$app->db2->dsn= 'DSN';
Yii::$app->db2->username = 'username';
# password...

此外,首先关闭db2连接。 close()。请务必销毁

link 还有一个好方法。 Dynamic database connection

或尝试以下操作

'db2' => function () {
    if (!\Yii::$app->user->isGuest) {
        $db_name = \Yii::$app->user->getid();
    } else {
        $db_name = ..; params
    }

    return Yii::createObject([
        'class' => 'yii\db\Connection',
        'dsn' => 'mysql:host=localhost;dbname=' . $db_name,
        'username' => 'root',
        'password' => '',
        'charset' => 'utf8',
    ]);
},

然后:

public static function getDb()
{
    return Yii::$app->userDb;
}

当然,对于db(默认db),它可能不起作用。但是,如果经过测试..,请确保close()为先前的连接/

答案 1 :(得分:0)

我们有一个类似的配置,实际上我们有多个实例,一个实例可能具有一个主数据库以及一个或多个“子”数据库。主数据库有一个表,该表定义了子数据库,就像您的表一样。

我假设子数据库列在名为Children的表中。 在Children的模型中,我们有一些实用工具功能,我将在下面进行介绍。

子数据库中的表具有从class ChildActiveRecord extends \yii\db\ActiveRecord扩展的模型类

然后子数据库中的任何表都使用

class SomeChildTable extends ChildActiveRecord

ChildActiveRecord中的关键元素是getDb,它覆盖了Yii的ActiveRecord类中定义的函数。 getDb返回数据库连接。

Class ChildActiveRecord extends \yii\db\ActiveRecord {
  public static function getDb()
  {
    $childDb = Children::getChild(); // usually set via Children->setChild()
    // Does a connection already exist? Return it:
    if(array_key_exists( $childDb, Yii::$app->params['dbs'])) {
        return Yii::$app->params['dbs'][ $childDb ];
    }
    $child = Children::getChildDetails();
    $connection = new \yii\db\Connection([
        'dsn' => 'mysql:host=localhost;dbname=' . $child->dbName,
        'username' => $child->username,
        'password' => $child->password,
        'charset' => 'utf8',
    ]);
    Yii::$app->params['dbs'][ $childb ] = $connection; // cache for re-use
    return $connection;
  }
}

在我们的案例中,我们在配置文件中包含数据库用户和密码,以便可以对开发人员隐藏它们。

children表的模型类中:

Class Children extends \yii\db\ActiveRecord{
 public function setChild()
{
    Yii::$app->params['childdb'] = $this->dbname;
}
/**
 * returns child db name
 *
 * @return string|null
 */
public static function getChild()
{
    if( ! array_key_exists( 'childdb', Yii::$app->params ) ) return null;
    return Yii::$app->params['childdb'];
}

/**
 * @return Children|null
 */
public static function getChildDetails()
{
    $childdb = self::getChild();
    if( ! $childdb ) return null;
    $child = self::findOne( ['dbname'=>$childdb]);
    return $child;
}

在您的代码中,使用子数据库进行任何操作之前,您需要在Children表中找到子记录,例如

$child = Children::findOne([condition]);

然后设置子数据库:

$child->setChild();

之后,您可以使用常规Yii代码使用子数据库中的任何表。