bitrix-database
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDirect Database Work
直接数据库操作
Baseline: main 23.0+. ORM is the first choice ( — prefer / , and ORM write APIs including batch / merge / before dropping to SQL). Direct SQL is needed for:
bitrix-ormquery()ConditionTreedeleteByFilter- Migrations/DDL in /
install/index.php,updater.php - Bulk operations (,
UPSERT, windows/CTE),REPLACE - Reports with /aggregates that are cumbersome to build via ORM,
GROUP BY - Working with multiple connections (analytical replica, Redis).
基准版本:main 23.0+。ORM是首选方案( — 在使用SQL之前,优先使用 / ,以及ORM写入API,包括批量操作/合并/)。在以下场景中需要使用直接SQL:
bitrix-ormquery()ConditionTreedeleteByFilter- /
install/index.php中的迁移/DDL操作,updater.php - 批量操作(、
UPSERT、窗口函数/CTE),REPLACE - 包含/聚合函数的报表,这类报表通过ORM构建较为繁琐,
GROUP BY - 多连接操作(分析副本、Redis)。
Connection
数据库连接
php
use Bitrix\Main\Application;
use Bitrix\Main\DB\Connection;
/** @var Connection $db */
$db = Application::getConnection(); // default
$db = Application::getConnection('default');
$analytics = Application::getConnection('analytics'); // additionalphp
use Bitrix\Main\Application;
use Bitrix\Main\DB\Connection;
/** @var Connection $db */
$db = Application::getConnection(); // 默认连接
$db = Application::getConnection('default');
$analytics = Application::getConnection('analytics'); // 额外连接Configuration in .settings.php
.settings.php.settings.php中的配置
php
'connections' => [
'value' => [
'default' => [
'className' => \Bitrix\Main\DB\MysqliConnection::class,
'host' => 'db',
'database' => 'bx',
'login' => 'bx',
'password' => '***',
'options' => \Bitrix\Main\DB\Connection::DEFERRED, // 2 — connect on first query
],
'analytics' => [
'className' => \Bitrix\Main\DB\PgsqlConnection::class,
'host' => 'pg',
'database' => 'analytics',
'login' => 'ro',
'password' => '***',
'options' => \Bitrix\Main\DB\Connection::DEFERRED,
],
'redis' => [
'className' => \Bitrix\Main\Data\RedisConnection::class,
'host' => 'redis',
'port' => 6379,
'persistent'=> true,
'serializer'=> \Redis::SERIALIZER_IGBINARY,
'compression' => \Redis::COMPRESSION_LZ4,
],
],
'readonly' => true,
],optionsConnection::PERSISTENT = 1Connection::DEFERRED = 23Classes:
- — MySQL (
\Bitrix\Main\DB\MysqliConnection).mysqli - — PostgreSQL.
\Bitrix\Main\DB\PgsqlConnection - ,
\Bitrix\Main\DB\MssqlConnection— rare.\Bitrix\Main\DB\OracleConnection - ,
\Bitrix\Main\Data\MemcacheConnection,MemcachedConnection.RedisConnection - — HandlerSocket (read-only, for high-load
\Bitrix\Main\Data\HsphpReadConnectionby primary key bypassing SQL).SELECT
php
'connections' => [
'value' => [
'default' => [
'className' => \Bitrix\Main\DB\MysqliConnection::class,
'host' => 'db',
'database' => 'bx',
'login' => 'bx',
'password' => '***',
'options' => \Bitrix\Main\DB\Connection::DEFERRED, // 2 — 首次查询时建立连接
],
'analytics' => [
'className' => \Bitrix\Main\DB\PgsqlConnection::class,
'host' => 'pg',
'database' => 'analytics',
'login' => 'ro',
'password' => '***',
'options' => \Bitrix\Main\DB\Connection::DEFERRED,
],
'redis' => [
'className' => \Bitrix\Main\Data\RedisConnection::class,
'host' => 'redis',
'port' => 6379,
'persistent'=> true,
'serializer'=> \Redis::SERIALIZER_IGBINARY,
'compression' => \Redis::COMPRESSION_LZ4,
],
],
'readonly' => true,
],optionsConnection::PERSISTENT = 1Connection::DEFERRED = 23相关类:
- — MySQL(基于
\Bitrix\Main\DB\MysqliConnection)。mysqli - — PostgreSQL。
\Bitrix\Main\DB\PgsqlConnection - 、
\Bitrix\Main\DB\MssqlConnection— 较少使用。\Bitrix\Main\DB\OracleConnection - 、
\Bitrix\Main\Data\MemcacheConnection、MemcachedConnection。RedisConnection - — HandlerSocket(只读,高负载场景下通过主键执行
\Bitrix\Main\Data\HsphpReadConnection,绕过SQL层)。SELECT
SELECT
查询操作(SELECT)
php
$rs = $db->query('SELECT ID, NAME FROM b_user WHERE ACTIVE = "Y"');
$rs = $db->query('SELECT ID FROM b_user', 10); // LIMIT 10
$rs = $db->query('SELECT ID FROM b_user', 0, 100); // LIMIT 0, 100
while ($row = $rs->fetch())
{
$id = (int)$row['ID'];
}
foreach ($rs as $row) { /* ... */ }
$id = $db->queryScalar('SELECT COUNT(*) FROM b_user WHERE ACTIVE = "Y"');- — values are processed through field converters (date →
fetch()).Bitrix\Main\Type\DateTime - — as received from the driver.
fetchRaw() - ,
$result->getSelectedRowsCount(),$result->getFields()(low-level$result->getResource()).mysqli_result
Important: cannot be "rewound" — if a second pass is needed, materialize it into an array.
Resultphp
$rs = $db->query('SELECT ID, NAME FROM b_user WHERE ACTIVE = "Y"');
$rs = $db->query('SELECT ID FROM b_user', 10); // 限制返回10条
$rs = $db->query('SELECT ID FROM b_user', 0, 100); // 从第0条开始,返回100条
while ($row = $rs->fetch())
{
$id = (int)$row['ID'];
}
foreach ($rs as $row) { /* ... */ }
$id = $db->queryScalar('SELECT COUNT(*) FROM b_user WHERE ACTIVE = "Y"');- — 返回值会经过字段转换器处理(日期转换为
fetch())。Bitrix\Main\Type\DateTime - — 直接返回驱动原始数据。
fetchRaw() - (获取查询行数)、
$result->getSelectedRowsCount()(获取字段信息)、$result->getFields()(底层$result->getResource()资源)。mysqli_result
注意:对象无法"回滚"遍历 — 若需二次遍历,需先将其转换为数组。
ResultCustom Converters
自定义转换器
php
$rs = $db->query('SELECT ID, ACTIVE, DATE_REGISTER FROM b_user');
$rs->setConverters(['DATE_REGISTER' => static fn ($v) => $v ? strtotime($v) : null]);
$rs->addFetchDataModifier(static function (array $row): array {
$row['ACTIVE_BOOL'] = $row['ACTIVE'] === 'Y';
return $row;
});php
$rs = $db->query('SELECT ID, ACTIVE, DATE_REGISTER FROM b_user');
$rs->setConverters(['DATE_REGISTER' => static fn ($v) => $v ? strtotime($v) : null]);
$rs->addFetchDataModifier(static function (array $row): array {
$row['ACTIVE_BOOL'] = $row['ACTIVE'] === 'Y';
return $row;
});INSERT/UPDATE/DELETE
增删改操作(INSERT/UPDATE/DELETE)
php
$id = $db->add('my_table', [
'NAME' => 'example',
'CONTENT' => $raw, // automatically escaped
]);
$lastId = $db->addMulti('my_table', [
['NAME' => 'a', 'CONTENT' => '1'],
['NAME' => 'b', 'CONTENT' => '2'],
]);
$db->queryExecute(
'UPDATE my_table SET NAME = "' . $db->getSqlHelper()->forSql($name) . '" WHERE ID = ' . (int)$id
);addaddMultiIMPORTANT: theparameter in$bindsdoes not create prepared statements — these are only placeholders for LOBs in some drivers. Protect against SQL injections viaquery/queryScalar/queryExecuteorSqlExpression.SqlHelper
php
$id = $db->add('my_table', [
'NAME' => 'example',
'CONTENT' => $raw, // 自动转义
]);
$lastId = $db->addMulti('my_table', [
['NAME' => 'a', 'CONTENT' => '1'],
['NAME' => 'b', 'CONTENT' => '2'],
]);
$db->queryExecute(
'UPDATE my_table SET NAME = "' . $db->getSqlHelper()->forSql($name) . '" WHERE ID = ' . (int)$id
);addaddMulti重要提示:中的query/queryScalar/queryExecute参数不会创建预编译语句 — 仅部分驱动中用于LOB类型的占位符。需通过$binds或SqlExpression防止SQL注入。SqlHelper
SqlHelper — Escaping and Utilities
SqlHelper — 转义与工具方法
php
$h = $db->getSqlHelper();
$h->quote('table.id'); // `table`.`id`
$h->forSql($userInput); // escapes quotes
$h->convertToDb($value); // 'v' | 'NULL' | '123'
$h->convertToDbString(null); // ''
$h->convertToDbString('long', 5); // 'long ' (truncated)
$h->convertToDbInteger('x'); // 0
$h->convertToDbInteger(1e10, 4); // 2147483647 — 4 byte limit
$h->convertToDbFloat(1.2345, 1); // '1.2'
$h->convertToDbDate(new \Bitrix\Main\Type\Date('01.01.2025')); // '2025-01-01'
$h->convertToDbDateTime(new \Bitrix\Main\Type\DateTime());
$h->getCurrentDateTimeFunction(); // NOW()
$h->addSecondsToDateTime(60, $h->quote('c')); // DATE_ADD(`c`, INTERVAL 60 SECOND)
$h->addDaysToDateTime(30); // DATE_ADD(NOW(), INTERVAL 30 DAY)
$h->getConcatFunction($h->quote('a'), "'-'", $h->quote('b'));
$h->getIsNullFunction($h->quote('a'), 0); // IFNULL(`a`, 0)
$h->getMatchFunction($h->quote('body'), $h->convertToDb('bitrix')); // MATCH ... AGAINSTSQL function arguments are not automatically escaped — pass them through / yourself.
quoteconvertToDbphp
$h = $db->getSqlHelper();
$h->quote('table.id'); // `table`.`id`
$h->forSql($userInput); // 转义引号
$h->convertToDb($value); // 转换为数据库兼容格式:'v' | 'NULL' | '123'
$h->convertToDbString(null); // ''
$h->convertToDbString('long', 5); // 'long ' (截断处理)
$h->convertToDbInteger('x'); // 0
$h->convertToDbInteger(1e10, 4); // 2147483647 — 4字节整数上限
$h->convertToDbFloat(1.2345, 1); // '1.2'
$h->convertToDbDate(new \Bitrix\Main\Type\Date('01.01.2025')); // '2025-01-01'
$h->convertToDbDateTime(new \Bitrix\Main\Type\DateTime());
$h->getCurrentDateTimeFunction(); // NOW()
$h->addSecondsToDateTime(60, $h->quote('c')); // DATE_ADD(`c`, INTERVAL 60 SECOND)
$h->addDaysToDateTime(30); // DATE_ADD(NOW(), INTERVAL 30 DAY)
$h->getConcatFunction($h->quote('a'), "'-'", $h->quote('b'));
$h->getIsNullFunction($h->quote('a'), 0); // IFNULL(`a`, 0)
$h->getMatchFunction($h->quote('body'), $h->convertToDb('bitrix')); // MATCH ... AGAINSTSQL函数的参数不会自动转义 — 需自行通过/处理。
quoteconvertToDbUPSERT (prepareMerge*
)
prepareMerge*UPSERT操作(prepareMerge*
)
prepareMerge*php
[$sql] = $h->prepareMerge(
'b_user_counter',
['USER_ID', 'SITE_ID', 'CODE'],
insertFields: ['USER_ID' => 1, 'SITE_ID' => 's1', 'CODE' => 'visits', 'CNT' => 1],
updateFields: ['CNT' => new \Bitrix\Main\DB\SqlExpression('?# + ?i', 'CNT', 1)],
);
$db->queryExecute($sql);There are also (multiple rows at once), (from subquery), (, splits batches for large bulks).
prepareMergeValuesprepareMergeSelectprepareMergeMultipleREPLACE INTOphp
[$sql] = $h->prepareMerge(
'b_user_counter',
['USER_ID', 'SITE_ID', 'CODE'],
insertFields: ['USER_ID' => 1, 'SITE_ID' => 's1', 'CODE' => 'visits', 'CNT' => 1],
updateFields: ['CNT' => new \Bitrix\Main\DB\SqlExpression('?# + ?i', 'CNT', 1)],
);
$db->queryExecute($sql);此外还有(批量处理多行)、(从子查询获取数据)、(,针对大量数据拆分批次)。
prepareMergeValuesprepareMergeSelectprepareMergeMultipleREPLACE INTOSqlExpression — Parameterized Queries
SqlExpression — 参数化查询
php
use Bitrix\Main\DB\SqlExpression;
$sql = new SqlExpression(
'SELECT * FROM ?# WHERE (ID = ?i OR ID > ?f) AND NAME = ?s AND CREATED > ?',
'b_user',
1,
1.23,
'admin',
new \Bitrix\Main\Type\Date('01.01.2025'),
);
$db->query($sql);
echo (string)$sql; // compiled SQLPlaceholders:
- — auto: strings, numbers,
?,Date/DateTime→null.NULL - — string.
?s - — integer.
?i - — float.
?f - — identifier (table/column name, wrapped in quotes).
?# - —
?vfor INSERT/UPDATE.VALUES(...)
For dates in / use — you'll get ; will give string representation in site format.
DateDateTime?'2025-01-01 00:00:00'?sphp
use Bitrix\Main\DB\SqlExpression;
$sql = new SqlExpression(
'SELECT * FROM ?# WHERE (ID = ?i OR ID > ?f) AND NAME = ?s AND CREATED > ?',
'b_user',
1,
1.23,
'admin',
new \Bitrix\Main\Type\Date('01.01.2025'),
);
$db->query($sql);
echo (string)$sql; // 编译后的SQL语句占位符说明:
- — 自动识别类型:字符串、数字、
?、Date/DateTime→null。NULL - — 字符串类型。
?s - — 整数类型。
?i - — 浮点数类型。
?f - — 标识符(表/列名,自动添加引号)。
?# - — INSERT/UPDATE中的
?v。VALUES(...)
对于/类型的日期,使用占位符会得到;使用则会返回站点格式的字符串。
DateDateTime?'2025-01-01 00:00:00'?sTransactions
事务操作
php
$db = Application::getConnection();
$db->startTransaction();
try {
$db->queryExecute('...');
$db->commitTransaction();
} catch (\Throwable $e) {
$db->rollbackTransaction();
throw $e;
}Keep transactions short. ORM operations inside a transaction are supported — use the same connection.
php
$db = Application::getConnection();
$db->startTransaction();
try {
$db->queryExecute('...');
$db->commitTransaction();
} catch (\Throwable $e) {
$db->rollbackTransaction();
throw $e;
}事务应保持简短。事务内支持ORM操作 — 需使用同一数据库连接。
SqlTracker
SqlTracker
Enable SQL query logging for debugging. Call , then to dump queries to a file in development:
startTracker()startFileLog($path)php
$tracker = \Bitrix\Main\Application::getConnection()->startTracker();
$tracker->startFileLog($_SERVER['DOCUMENT_ROOT'] . '/mysql_debug.sql');
// ... queries ...
$queries = $tracker->getQueries();
$tracker->stop();Use only in development (same pattern as kernel in ).
$DBDebugToFilestart.php启用SQL查询日志用于调试。调用,再调用可在开发环境中将查询日志写入文件:
startTracker()startFileLog($path)php
$tracker = \Bitrix\Main\Application::getConnection()->startTracker();
$tracker->startFileLog($_SERVER['DOCUMENT_ROOT'] . '/mysql_debug.sql');
// ... 执行查询 ...
$queries = $tracker->getQueries();
$tracker->stop();仅在开发环境中使用(与中的内核模式一致)。
start.php$DBDebugToFilePostgreSQL
PostgreSQL支持
PgsqlConnectionbitrix-postgresqlPgsqlConnectionbitrix-postgresqlafter_connect_d7.php
after_connect_d7.php
Place post-connect hooks in (charset, , DB timezone). Included by after a successful connect — see skill .
/local/php_interface/after_connect_d7.phpsql_modeConnectionPoolbitrix-project-structure可在中添加连接后钩子(如字符集、、数据库时区设置)。在连接成功后会加载该文件 — 详见技能。
/local/php_interface/after_connect_d7.phpsql_modeConnectionPoolbitrix-project-structure