数据库表名前缀(以及进程间共享表)

有些网络主机限制了客户只能拥有一个数据库,因此需要不能重复的表名。即使在这种情况下,管理员仍可以使用Drupal,甚至可以安多个Drupal,因为Drupal提供了表名前缀(table prefix)功能。

为了使用这项功能,你必须首先编辑脚本database/database.x,以创建带有你的前缀字串的数据库表。如果你要安装附加模块,你也需要修改数据库脚本里的INSERT和REPLACE语句来加上前缀(译注:Drupal 4.7模块自带的Install文件无需修改)。例如,改变以下格式的所有语句从:

CREATE TABLE access
INSERT INTO system VALUES 
('modules/filter.module','filter','module','',1,0,0);

变成

CREATE TABLE dr1_access
INSERT INTO dr1_system VALUES 
('modules/filter.module','filter','module','',1,0,0);

然后使用dr1_(举例)作为$db_prefix的值,写入到
sites/example.com/settings.php文件中。

你也可以使用脚本来自动完成这项工作,你可以同时更新多个站点,使用(bash shell)的命令行:

for F in '' prefix1 prefix2; do \
   for S in 'find ./modules --name \*mysql'; do \
      scripts/dbprefix.sh $F < $S | grep -v DROP |\
          mysql -h DBHOST -u DBUSER -pPASSWD DATABASE; \
      done;
   done

注意:不是所有数据库脚本都是以mysql结尾的,这里只是一个例子; '' 表示前缀为空的情况。

这里还有一个PHP脚本,用于为/drupal/sites/*下的所有站点创建所有数据库表,可以在DRUPAL-4-6下工作,访问数据库表创建脚本问题以获取更多信息。

如果你想在多个站点间共享用户,你需要按照下面的格式设置$db_prefix变量:

<?php
$db_prefix
= array(
 
'default' => 'thissite_',   
 
'authmap' => 'shared_',
 
'profile_fields' => 'shared_',
 
'profile_values' => 'shared_',
 
'role' => 'shared_',
 
'sequences' => 'shared_',
 
'sessions' => 'shared_',
 
'users' => 'shared_',
 
'users_roles' => 'shared_',
 
'users_uid_seq' => 'shared_', // 用于pgsql
);
?>

请访问共享表以及数据库间共享表一节获取更多信息。

多个数据库间共享公共表

多个数据库间共享公共表
[仅在mysql上测试过]把多个Drupal安装在不同的数据库中,但是仍然共享共用的表,这是可以做到的,只需要指定数据库名作为前缀的一部分,例如

$db_prefix = array(
    "default" => "slave1.", // slave1安装的默认数据库
    "users" => "master.",
    "sessions" => "master.",
    "authmap" => "master.",
    "sequences" => "master."
    "profile_fields" => "master.",
    "profile_values" => "master.",
);

上面的例子中,slave1以及master为数据库名。
如果你共享的是users表,你应该还需要共享一系列的表(虽然我不太清楚)。如果你不是想共享用户表,只想共享翻译,那么共享locale表就足够了。

进程间共享表

表名前缀可以选择性的只应用到某些表上,这样多个Drupal安装就可以共享共用的表。一个有趣的应用是共享分类表(vocabularies, term_date),另一个有趣的用法是在多个Drupal安装间共享users表。

为了使用这项功能,先安装两个Drupal到同一数据库中,并使用不同的数据库前缀。在这个例子中,一个前缀为“master_”,另一个为"slave1_"。然后编辑"slave1_"安装的conf.php文件,让一些表指向"master_",实现用户共享,如下:

$db_prefix = array(
    "default" => "slave1_", // slave1_安装的默认表前缀
    "users" => "master_",
    "sessions" => "master_",
    "authmap" => "master_",
    "sequences" => "master_"
    "profile_fields" => "master_",
    "profile_values" => "master_",
);

注意:下面的表含有的数据属于每个站点特有,因此不能被共享:

  • cache
  • variable

在PostgreSQL中使用模式作为前缀

本页讨论了使用PostgreSQL的模式(Schema)作为前缀的用法。“普通”前缀可以和MySQL一样的用法,所以这里不再讨论。

PostgreSQL有种叫“模式”的机制(http://www.postgresql.org/docs/current/static/ddl-schemas.html)。有时非常方便,但如果你不知道那是什么,你可能实际上不需要它们并可以不用读下去了。

模式在Drupal中可以被用作前缀,也就是说,在多站点安装中,每个站点可以存在于自己的模式中,并且共享的表可以存在于一个“共享”模式中(或者甚至可以是公共模式)。

这儿有个问题:Drupal的升级会失败。很不幸,但是没办法,因为“普通”前缀和模式前缀是不兼容的。如果你对详细情况感兴趣,请访问http://drupal.org/node/40034。

不过也不用担心,可以通过小小的修改更新脚本(update.php和updates.inc)来简单的修正这个问题。问题来自CREATE [UNIQUE] INDEXALTER TABLE .... DROP/ADD CONSTRAINT语句,当使用模式作前缀时,会执行下面的查询:

CREATE INDEX prefix.search_total_word_idx ON prefix.search_total(word)
ALTER TABLE prefix.boxes DROP CONSTRAINT prefix.boxes_title_key
ALTER TABLE test.contact ADD CONSTRAINT test.contact_category_key UNIQUE (category)

必须从索引名和约束名前面移除前缀,也就是它们必须改为:

CREATE INDEX search_total_word_idx ON prefix.search_total(word)
ALTER TABLE prefix.boxes DROP CONSTRAINT boxes_title_key
ALTER TABLE test.contact ADD CONSTRAINT contact_category_key UNIQUE (category)

你只需要搜索CREATE  INDEX,CREATE UNIQUE  INDEXADD/DROP CONSTRAINT语句并移除索引/约束名外面的{}就可以了。

最好的方式是运行升级测试,你可以看到错误查询的列表,然后你就可以很简单的修改它们了。

其它注释:你不能使用prefix.sh来为表加上前缀,这会产生错误的CREATE [UNIQUE] INDEX 查询。这点同样可以简单的被修正,只需要修改:

s/^CREATE INDEX \(.*\) ON /CREATE INDEX $PREFIX\\1 ON $PREFIX/;
s/^CREATE UNIQUE INDEX \(.*\) ON /CREATE UNIQUE INDEX $PREFIX\\1 ON
$PREFIX/;

为:
s/^CREATE INDEX \(.*\) ON /CREATE INDEX \\1 ON $PREFIX/;
s/^CREATE UNIQUE INDEX \(.*\) ON /CREATE UNIQUE INDEX \\1 ON $PREFIX/;

一种可选方法
如果你打算用这种方法来解决,下面是你需要做的:

1.添加下面的语句到database.pgsql文件的顶部:

CREATE SCHEMA schemaname;
SET search_path TO schemaname;

2.编辑drupal/includes/database.pgsql.inc,替换函数db_connect()为:
<?php
function db_connect($url) {
 
$url = parse_url($url);
 
$db_and_schema = explode(".",substr($url['path'], 1));
 
$conn_string = ' user='. $url['user'] .' dbname='.
$db_and_schema['0']  .'  password='$url['pass']  .  '  host='  .
strtr($url['host'],'+','/');
 
$conn_string .= isset($url['port']) ? ' port=' . $url['port'] : '';
 
$connection = pg_connect($conn_string) or die(pg_last_error());
  if(!empty(
$db_and_schema['1'])) pg_query('SET search_path TO
'
.$db_and_schema['1']);
  return
$connection;
}
?>

3.最后,在你的seeting.php文件里使用类似的db_url:
$db_url = 'pgsql://user:password@+tmp/dbname.schemaname';

  • 没有进行彻底的测试,但是我的可以工作(在4.6.3上)。
  • 这也解决了无法指定一个Unix socket作为主机的问题——在pg_connect()里/tmp被替换成了+tmp

。[=red]
[/]

Define shared variables for all sites

暂缺

原文:http://drupal.org/node/70472