mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-07-01 15:32:48 +08:00
feat(command): 新增数据库调试命令行工具集
This commit is contained in:
9
app/common/command/tools/db/ToolsDbCount.php
Normal file
9
app/common/command/tools/db/ToolsDbCount.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\command\tools\db;
|
||||
|
||||
use base\common\command\tools\db\ToolsDbCountBase;
|
||||
|
||||
class ToolsDbCount extends ToolsDbCountBase
|
||||
{
|
||||
}
|
||||
9
app/common/command/tools/db/ToolsDbDesc.php
Normal file
9
app/common/command/tools/db/ToolsDbDesc.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\command\tools\db;
|
||||
|
||||
use base\common\command\tools\db\ToolsDbDescBase;
|
||||
|
||||
class ToolsDbDesc extends ToolsDbDescBase
|
||||
{
|
||||
}
|
||||
9
app/common/command/tools/db/ToolsDbExecute.php
Normal file
9
app/common/command/tools/db/ToolsDbExecute.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\command\tools\db;
|
||||
|
||||
use base\common\command\tools\db\ToolsDbExecuteBase;
|
||||
|
||||
class ToolsDbExecute extends ToolsDbExecuteBase
|
||||
{
|
||||
}
|
||||
9
app/common/command/tools/db/ToolsDbInfo.php
Normal file
9
app/common/command/tools/db/ToolsDbInfo.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\command\tools\db;
|
||||
|
||||
use base\common\command\tools\db\ToolsDbInfoBase;
|
||||
|
||||
class ToolsDbInfo extends ToolsDbInfoBase
|
||||
{
|
||||
}
|
||||
9
app/common/command/tools/db/ToolsDbQuery.php
Normal file
9
app/common/command/tools/db/ToolsDbQuery.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\command\tools\db;
|
||||
|
||||
use base\common\command\tools\db\ToolsDbQueryBase;
|
||||
|
||||
class ToolsDbQuery extends ToolsDbQueryBase
|
||||
{
|
||||
}
|
||||
9
app/common/command/tools/db/ToolsDbTable.php
Normal file
9
app/common/command/tools/db/ToolsDbTable.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\command\tools\db;
|
||||
|
||||
use base\common\command\tools\db\ToolsDbTableBase;
|
||||
|
||||
class ToolsDbTable extends ToolsDbTableBase
|
||||
{
|
||||
}
|
||||
79
extend/base/common/command/tools/db/ToolsDbCountBase.php
Normal file
79
extend/base/common/command/tools/db/ToolsDbCountBase.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace base\common\command\tools\db;
|
||||
|
||||
use base\common\service\ToolsDbServiceBase;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
|
||||
class ToolsDbCountBase extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('tools:db:count')
|
||||
->setDescription('统计表记录数')
|
||||
->addArgument('table', null, '表名')
|
||||
->addOption('where', null, Option::VALUE_OPTIONAL, 'WHERE 条件')
|
||||
->addOption('connection', null, Option::VALUE_OPTIONAL, '指定数据库连接配置')
|
||||
->addOption('help', 'h', Option::VALUE_NONE, '显示帮助信息');
|
||||
}
|
||||
|
||||
protected function execute($input, $output)
|
||||
{
|
||||
if ($input->getOption('help')) {
|
||||
$service = new ToolsDbServiceBase();
|
||||
$service->showHelp('tools:db:count', $output);
|
||||
return;
|
||||
}
|
||||
|
||||
$service = new ToolsDbServiceBase();
|
||||
|
||||
if (!$service->checkDebugMode($output)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$connection = $service->getDbConnection($input);
|
||||
$service->setConnection($connection);
|
||||
|
||||
$tableName = $input->getArgument('table');
|
||||
if (empty($tableName)) {
|
||||
$output->error('请提供表名');
|
||||
return;
|
||||
}
|
||||
|
||||
$fullTableName = $service->getFullTableName($tableName);
|
||||
$where = $input->getOption('where');
|
||||
|
||||
try {
|
||||
$startTime = microtime(true);
|
||||
|
||||
$query = Db::connect($connection)->table($fullTableName);
|
||||
|
||||
if ($where) {
|
||||
$query->whereRaw($where);
|
||||
}
|
||||
|
||||
$count = $query->count();
|
||||
|
||||
$endTime = microtime(true);
|
||||
$executionTime = round(($endTime - $startTime) * 1000, 2);
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('<info>表名:' . $fullTableName . '</info>');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>记录数:</info>' . $count);
|
||||
$output->writeln('<info>执行时间:</info>' . $executionTime . 'ms');
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('');
|
||||
} catch (\Exception $e) {
|
||||
$output->error('统计失败:' . $e->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
114
extend/base/common/command/tools/db/ToolsDbDescBase.php
Normal file
114
extend/base/common/command/tools/db/ToolsDbDescBase.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace base\common\command\tools\db;
|
||||
|
||||
use base\common\service\ToolsDbServiceBase;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
|
||||
class ToolsDbDescBase extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('tools:db:desc')
|
||||
->setDescription('显示表结构信息')
|
||||
->addArgument('table', null, '表名')
|
||||
->addOption('show-index', null, Option::VALUE_NONE, '显示索引信息')
|
||||
->addOption('connection', null, Option::VALUE_OPTIONAL, '指定数据库连接配置')
|
||||
->addOption('help', 'h', Option::VALUE_NONE, '显示帮助信息');
|
||||
}
|
||||
|
||||
protected function execute($input, $output)
|
||||
{
|
||||
if ($input->getOption('help')) {
|
||||
$service = new ToolsDbServiceBase();
|
||||
$service->showHelp('tools:db:desc', $output);
|
||||
return;
|
||||
}
|
||||
|
||||
$service = new ToolsDbServiceBase();
|
||||
|
||||
if (!$service->checkDebugMode($output)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$connection = $service->getDbConnection($input);
|
||||
$service->setConnection($connection);
|
||||
|
||||
$tableName = $input->getArgument('table');
|
||||
if (empty($tableName)) {
|
||||
$output->error('请提供表名');
|
||||
return;
|
||||
}
|
||||
|
||||
$fullTableName = $service->getFullTableName($tableName);
|
||||
$showIndex = $input->getOption('show-index');
|
||||
|
||||
try {
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('<info>表结构:' . $fullTableName . '</info>');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('');
|
||||
|
||||
$columns = Db::connect($connection)->query("SHOW FULL COLUMNS FROM `$fullTableName`");
|
||||
|
||||
if (empty($columns)) {
|
||||
$output->writeln('表不存在或无字段');
|
||||
$output->writeln('');
|
||||
return;
|
||||
}
|
||||
|
||||
$tableData = [];
|
||||
foreach ($columns as $column) {
|
||||
$tableData[] = [
|
||||
'字段名' => $column['Field'],
|
||||
'类型' => $column['Type'],
|
||||
'是否为空' => $column['Null'] === 'YES' ? '是' : '否',
|
||||
'键' => $column['Key'],
|
||||
'默认值' => $column['Default'] ?? 'NULL',
|
||||
'额外' => $column['Extra'] ?? '',
|
||||
'注释' => $column['Comment'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
$service->formatTableOutput($tableData, $output);
|
||||
|
||||
if ($showIndex) {
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>' . str_repeat('-', 60) . '</comment>');
|
||||
$output->writeln('<info>索引信息</info>');
|
||||
$output->writeln('<comment>' . str_repeat('-', 60) . '</comment>');
|
||||
$output->writeln('');
|
||||
|
||||
$indexes = Db::connect($connection)->query("SHOW INDEX FROM `$fullTableName`");
|
||||
|
||||
if (!empty($indexes)) {
|
||||
$indexData = [];
|
||||
foreach ($indexes as $index) {
|
||||
$indexData[] = [
|
||||
'索引名' => $index['Key_name'],
|
||||
'列名' => $index['Column_name'],
|
||||
'唯一' => $index['Non_unique'] == 0 ? '是' : '否',
|
||||
'索引类型' => $index['Index_type'],
|
||||
'顺序' => $index['Seq_in_index'],
|
||||
];
|
||||
}
|
||||
$service->formatTableOutput($indexData, $output);
|
||||
} else {
|
||||
$output->writeln('无索引');
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('');
|
||||
} catch (\Exception $e) {
|
||||
$output->error('获取表结构失败:' . $e->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
103
extend/base/common/command/tools/db/ToolsDbExecuteBase.php
Normal file
103
extend/base/common/command/tools/db/ToolsDbExecuteBase.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace base\common\command\tools\db;
|
||||
|
||||
use base\common\service\ToolsDbServiceBase;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
|
||||
class ToolsDbExecuteBase extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('tools:db:execute')
|
||||
->setDescription('执行 SQL 非查询语句(INSERT/UPDATE/DELETE)')
|
||||
->addArgument('sql', null, 'SQL 执行语句')
|
||||
->addOption('force', null, Option::VALUE_NONE, '跳过确认直接执行')
|
||||
->addOption('transaction', null, Option::VALUE_NONE, '在事务中执行(失败自动回滚)')
|
||||
->addOption('connection', null, Option::VALUE_OPTIONAL, '指定数据库连接配置')
|
||||
->addOption('help', 'h', Option::VALUE_NONE, '显示帮助信息');
|
||||
}
|
||||
|
||||
protected function execute($input, $output)
|
||||
{
|
||||
if ($input->getOption('help')) {
|
||||
$service = new ToolsDbServiceBase();
|
||||
$service->showHelp('tools:db:execute', $output);
|
||||
return;
|
||||
}
|
||||
|
||||
$service = new ToolsDbServiceBase();
|
||||
|
||||
if (!$service->checkDebugMode($output)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$connection = $service->getDbConnection($input);
|
||||
$service->setConnection($connection);
|
||||
|
||||
$sql = $input->getArgument('sql');
|
||||
if (empty($sql)) {
|
||||
$output->error('请提供 SQL 执行语句');
|
||||
return;
|
||||
}
|
||||
|
||||
$force = $input->getOption('force');
|
||||
$useTransaction = $input->getOption('transaction');
|
||||
|
||||
if (preg_match('/^\s*SELECT\s+/i', $sql)) {
|
||||
$output->error('不支持 SELECT 语句,请使用 tools:db:query 执行查询');
|
||||
return;
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>准备执行的 SQL:</comment>');
|
||||
$output->writeln($sql);
|
||||
$output->writeln('');
|
||||
|
||||
if (!$force) {
|
||||
$confirm = $output->confirm($input, '<question>确定要执行此 SQL 语句吗?</question> ');
|
||||
if (!$confirm) {
|
||||
$output->writeln('<comment>操作已取消</comment>');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$startTime = microtime(true);
|
||||
|
||||
if ($useTransaction) {
|
||||
Db::connect($connection)->startTrans();
|
||||
try {
|
||||
$affectedRows = Db::connect($connection)->execute($sql);
|
||||
Db::connect($connection)->commit();
|
||||
} catch (\Exception $e) {
|
||||
Db::connect($connection)->rollback();
|
||||
throw $e;
|
||||
}
|
||||
} else {
|
||||
$affectedRows = Db::connect($connection)->execute($sql);
|
||||
}
|
||||
|
||||
$endTime = microtime(true);
|
||||
$executionTime = round(($endTime - $startTime) * 1000, 2);
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>执行成功</info>');
|
||||
$output->writeln('影响行数:' . $affectedRows);
|
||||
$output->writeln('执行时间:' . $executionTime . 'ms');
|
||||
$output->writeln('');
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln('');
|
||||
$output->error('执行失败:' . $e->getMessage());
|
||||
if ($useTransaction) {
|
||||
$output->writeln('<comment>事务已回滚</comment>');
|
||||
}
|
||||
$output->writeln('');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
101
extend/base/common/command/tools/db/ToolsDbInfoBase.php
Normal file
101
extend/base/common/command/tools/db/ToolsDbInfoBase.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace base\common\command\tools\db;
|
||||
|
||||
use base\common\service\ToolsDbServiceBase;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
use think\facade\Config;
|
||||
|
||||
class ToolsDbInfoBase extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('tools:db:info')
|
||||
->setDescription('显示数据库连接信息和表列表')
|
||||
->addOption('with-count', null, Option::VALUE_NONE, '显示每个表的记录数')
|
||||
->addOption('connection', null, Option::VALUE_OPTIONAL, '指定数据库连接配置')
|
||||
->addOption('help', 'h', Option::VALUE_NONE, '显示帮助信息');
|
||||
}
|
||||
|
||||
protected function execute($input, $output)
|
||||
{
|
||||
if ($input->getOption('help')) {
|
||||
$service = new ToolsDbServiceBase();
|
||||
$service->showHelp('tools:db:info', $output);
|
||||
return;
|
||||
}
|
||||
|
||||
$service = new ToolsDbServiceBase();
|
||||
|
||||
if (!$service->checkDebugMode($output)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$connection = $service->getDbConnection($input);
|
||||
$service->setConnection($connection);
|
||||
$withCount = $input->getOption('with-count');
|
||||
|
||||
try {
|
||||
$config = Config::get('database.connections.' . $connection);
|
||||
|
||||
if (!$config) {
|
||||
$output->error('数据库连接配置不存在:' . $connection);
|
||||
return;
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('<info>数据库连接信息</info>');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>连接名称:</info>' . $connection);
|
||||
$output->writeln('<info>数据库类型:</info>' . ($config['type'] ?? 'unknown'));
|
||||
$output->writeln('<info>主机地址:</info>' . ($config['hostname'] ?? 'unknown'));
|
||||
$output->writeln('<info>数据库名:</info>' . ($config['database'] ?? 'unknown'));
|
||||
$output->writeln('<info>端口:</info>' . ($config['hostport'] ?? 'unknown'));
|
||||
$output->writeln('<info>字符集:</info>' . ($config['charset'] ?? 'unknown'));
|
||||
$output->writeln('<info>表前缀:</info>' . ($config['prefix'] ?? ''));
|
||||
$output->writeln('');
|
||||
|
||||
$output->writeln('<comment>' . str_repeat('-', 60) . '</comment>');
|
||||
$output->writeln('<info>表列表</info>');
|
||||
$output->writeln('<comment>' . str_repeat('-', 60) . '</comment>');
|
||||
$output->writeln('');
|
||||
|
||||
$tables = Db::connect($connection)->getTables();
|
||||
|
||||
if (empty($tables)) {
|
||||
$output->writeln('无表');
|
||||
$output->writeln('');
|
||||
return;
|
||||
}
|
||||
|
||||
$prefix = $config['prefix'] ?? '';
|
||||
|
||||
foreach ($tables as $table) {
|
||||
$shortName = $table;
|
||||
if ($prefix && str_starts_with($table, $prefix)) {
|
||||
$shortName = substr($table, strlen($prefix));
|
||||
}
|
||||
|
||||
if ($withCount) {
|
||||
$count = Db::connect($connection)->table($table)->count();
|
||||
$output->writeln('<info>' . str_pad($shortName, 40) . '</info>' . $count . ' 条记录');
|
||||
} else {
|
||||
$output->writeln('<info>' . $shortName . '</info>');
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('');
|
||||
} catch (\Exception $e) {
|
||||
$output->error('获取信息失败:' . $e->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
90
extend/base/common/command/tools/db/ToolsDbQueryBase.php
Normal file
90
extend/base/common/command/tools/db/ToolsDbQueryBase.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace base\common\command\tools\db;
|
||||
|
||||
use base\common\service\ToolsDbServiceBase;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
|
||||
class ToolsDbQueryBase extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('tools:db:query')
|
||||
->setDescription('执行 SQL 查询语句(SELECT)并显示结果')
|
||||
->addArgument('sql', null, 'SQL 查询语句')
|
||||
->addOption('format', null, Option::VALUE_OPTIONAL, '输出格式,可选值:table(默认)、json', 'table')
|
||||
->addOption('limit', null, Option::VALUE_OPTIONAL, '限制显示行数')
|
||||
->addOption('connection', null, Option::VALUE_OPTIONAL, '指定数据库连接配置')
|
||||
->addOption('help', 'h', Option::VALUE_NONE, '显示帮助信息');
|
||||
}
|
||||
|
||||
protected function execute($input, $output)
|
||||
{
|
||||
if ($input->getOption('help')) {
|
||||
$service = new ToolsDbServiceBase();
|
||||
$service->showHelp('tools:db:query', $output);
|
||||
return;
|
||||
}
|
||||
|
||||
$service = new ToolsDbServiceBase();
|
||||
|
||||
if (!$service->checkDebugMode($output)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$connection = $service->getDbConnection($input);
|
||||
$service->setConnection($connection);
|
||||
|
||||
$sql = $input->getArgument('sql');
|
||||
if (empty($sql)) {
|
||||
$output->error('请提供 SQL 查询语句');
|
||||
return;
|
||||
}
|
||||
|
||||
$format = $input->getOption('format') ?: 'table';
|
||||
$limit = $input->getOption('limit');
|
||||
|
||||
if (!preg_match('/^\s*SELECT\s+/i', $sql)) {
|
||||
$output->error('仅支持 SELECT 语句,请使用 tools:db:execute 执行其他 SQL 语句');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$startTime = microtime(true);
|
||||
|
||||
$query = Db::connect($connection)->query($sql);
|
||||
|
||||
$endTime = microtime(true);
|
||||
$executionTime = round(($endTime - $startTime) * 1000, 2);
|
||||
|
||||
if (!is_array($query)) {
|
||||
$query = [];
|
||||
}
|
||||
|
||||
if ($limit && is_numeric($limit)) {
|
||||
$query = array_slice($query, 0, (int)$limit);
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
|
||||
if ($format === 'json') {
|
||||
$service->formatJsonOutput($query, $output);
|
||||
} else {
|
||||
$service->formatTableOutput($query, $output);
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>查询成功</info>');
|
||||
$output->writeln('影响行数:' . count($query));
|
||||
$output->writeln('执行时间:' . $executionTime . 'ms');
|
||||
$output->writeln('');
|
||||
} catch (\Exception $e) {
|
||||
$output->error('查询失败:' . $e->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
105
extend/base/common/command/tools/db/ToolsDbTableBase.php
Normal file
105
extend/base/common/command/tools/db/ToolsDbTableBase.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace base\common\command\tools\db;
|
||||
|
||||
use base\common\service\ToolsDbServiceBase;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
|
||||
class ToolsDbTableBase extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('tools:db:table')
|
||||
->setDescription('使用查询构建器操作表')
|
||||
->addArgument('table', null, '表名')
|
||||
->addOption('where', null, Option::VALUE_OPTIONAL, 'WHERE 条件')
|
||||
->addOption('field', null, Option::VALUE_OPTIONAL, '查询字段,多个用逗号分隔')
|
||||
->addOption('limit', null, Option::VALUE_OPTIONAL, '限制行数')
|
||||
->addOption('order', null, Option::VALUE_OPTIONAL, '排序,如 "id DESC"')
|
||||
->addOption('count', null, Option::VALUE_NONE, '只统计数量')
|
||||
->addOption('connection', null, Option::VALUE_OPTIONAL, '指定数据库连接配置')
|
||||
->addOption('help', 'h', Option::VALUE_NONE, '显示帮助信息');
|
||||
}
|
||||
|
||||
protected function execute($input, $output)
|
||||
{
|
||||
if ($input->getOption('help')) {
|
||||
$service = new ToolsDbServiceBase();
|
||||
$service->showHelp('tools:db:table', $output);
|
||||
return;
|
||||
}
|
||||
|
||||
$service = new ToolsDbServiceBase();
|
||||
|
||||
if (!$service->checkDebugMode($output)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$connection = $service->getDbConnection($input);
|
||||
$service->setConnection($connection);
|
||||
|
||||
$tableName = $input->getArgument('table');
|
||||
if (empty($tableName)) {
|
||||
$output->error('请提供表名');
|
||||
return;
|
||||
}
|
||||
|
||||
$fullTableName = $service->getFullTableName($tableName);
|
||||
|
||||
$where = $input->getOption('where');
|
||||
$field = $input->getOption('field');
|
||||
$limit = $input->getOption('limit');
|
||||
$order = $input->getOption('order');
|
||||
$count = $input->getOption('count');
|
||||
|
||||
try {
|
||||
$startTime = microtime(true);
|
||||
|
||||
$query = Db::connect($connection)->table($fullTableName);
|
||||
|
||||
if ($field) {
|
||||
$query->field($field);
|
||||
}
|
||||
|
||||
if ($where) {
|
||||
$query->whereRaw($where);
|
||||
}
|
||||
|
||||
if ($order) {
|
||||
$query->orderRaw($order);
|
||||
}
|
||||
|
||||
if ($count) {
|
||||
$result = $query->count();
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>表名:' . $fullTableName . '</info>');
|
||||
$output->writeln('记录数:' . $result);
|
||||
$output->writeln('');
|
||||
} else {
|
||||
if ($limit && is_numeric($limit)) {
|
||||
$query->limit((int)$limit);
|
||||
}
|
||||
|
||||
$result = $query->select()->toArray();
|
||||
|
||||
$endTime = microtime(true);
|
||||
$executionTime = round(($endTime - $startTime) * 1000, 2);
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>表名:' . $fullTableName . '</info>');
|
||||
$service->formatTableOutput($result, $output);
|
||||
$output->writeln('');
|
||||
$output->writeln('影响行数:' . count($result));
|
||||
$output->writeln('执行时间:' . $executionTime . 'ms');
|
||||
$output->writeln('');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$output->error('查询失败:' . $e->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
276
extend/base/common/service/ToolsDbServiceBase.php
Normal file
276
extend/base/common/service/ToolsDbServiceBase.php
Normal file
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
|
||||
namespace base\common\service;
|
||||
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
use think\facade\Env;
|
||||
use think\facade\Config;
|
||||
use think\Exception;
|
||||
|
||||
class ToolsDbServiceBase
|
||||
{
|
||||
protected $connection = 'main';
|
||||
|
||||
public function setConnection(string $connection): void
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
public function getConnection(): string
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
public function checkDebugMode(Output $output): bool
|
||||
{
|
||||
if (!Env::get('APP_DEBUG', false)) {
|
||||
$output->error('数据库操作命令仅在开发者模式下可用,请检查 APP_DEBUG 配置');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDbConnection(Input $input): string
|
||||
{
|
||||
return $input->getOption('connection') ?: Config::get('database.default', 'main');
|
||||
}
|
||||
|
||||
public function getTablePrefix(): string
|
||||
{
|
||||
$connection = $this->connection;
|
||||
return Config::get('database.connections.' . $connection . '.prefix', '');
|
||||
}
|
||||
|
||||
public function getFullTableName(string $tableName): string
|
||||
{
|
||||
$prefix = $this->getTablePrefix();
|
||||
if ($prefix && !str_starts_with($tableName, $prefix)) {
|
||||
return $prefix . $tableName;
|
||||
}
|
||||
return $tableName;
|
||||
}
|
||||
|
||||
public function formatTableOutput(array $data, Output $output): void
|
||||
{
|
||||
if (empty($data)) {
|
||||
$output->writeln('无数据');
|
||||
return;
|
||||
}
|
||||
|
||||
$columns = array_keys($data[0]);
|
||||
$columnWidths = [];
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$maxLen = strlen($column);
|
||||
foreach ($data as $row) {
|
||||
$valueLen = strlen((string)$row[$column]);
|
||||
if ($valueLen > $maxLen) {
|
||||
$maxLen = $valueLen;
|
||||
}
|
||||
}
|
||||
$columnWidths[$column] = $maxLen + 2;
|
||||
}
|
||||
|
||||
$separator = '+';
|
||||
foreach ($columnWidths as $width) {
|
||||
$separator .= str_repeat('-', $width) . '+';
|
||||
}
|
||||
|
||||
$output->writeln($separator);
|
||||
|
||||
$header = '|';
|
||||
foreach ($columns as $column) {
|
||||
$header .= ' ' . str_pad($column, $columnWidths[$column] - 1) . '|';
|
||||
}
|
||||
$output->writeln($header);
|
||||
$output->writeln($separator);
|
||||
|
||||
foreach ($data as $row) {
|
||||
$line = '|';
|
||||
foreach ($columns as $column) {
|
||||
$value = $row[$column] ?? '';
|
||||
if (is_null($value)) {
|
||||
$value = 'NULL';
|
||||
}
|
||||
$line .= ' ' . str_pad((string)$value, $columnWidths[$column] - 1) . '|';
|
||||
}
|
||||
$output->writeln($line);
|
||||
}
|
||||
|
||||
$output->writeln($separator);
|
||||
}
|
||||
|
||||
public function formatJsonOutput(array $data, Output $output): void
|
||||
{
|
||||
$output->writeln(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
public function showHelp(string $command, Output $output): void
|
||||
{
|
||||
$helpTexts = [
|
||||
'tools:db:query' => [
|
||||
'title' => '数据库查询命令 - tools:db:query',
|
||||
'description' => '执行 SQL 查询语句(SELECT)并显示结果',
|
||||
'usage' => 'php think tools:db:query <SQL语句> [选项]',
|
||||
'options' => [
|
||||
'--format=table' => '输出格式,可选值:table(默认)、json',
|
||||
'--limit=N' => '限制显示行数',
|
||||
'--connection=main' => '指定数据库连接配置',
|
||||
'-h, --help' => '显示帮助信息',
|
||||
],
|
||||
'examples' => [
|
||||
'php think tools:db:query "SELECT * FROM ul_system_admin"' => '查询所有管理员',
|
||||
'php think tools:db:query "SELECT id, username, nickname FROM ul_system_admin" --limit 10' => '查询前10条记录',
|
||||
'php think tools:db:query "SELECT * FROM ul_system_admin WHERE status = 1" --format=json' => 'JSON格式输出',
|
||||
],
|
||||
'notes' => [
|
||||
'支持 SELECT 语句',
|
||||
'自动显示执行时间和结果行数',
|
||||
'支持多数据库连接',
|
||||
],
|
||||
],
|
||||
'tools:db:execute' => [
|
||||
'title' => '数据库执行命令 - tools:db:execute',
|
||||
'description' => '执行 SQL 非查询语句(INSERT/UPDATE/DELETE)',
|
||||
'usage' => 'php think tools:db:execute <SQL语句> [选项]',
|
||||
'options' => [
|
||||
'--force' => '跳过确认直接执行',
|
||||
'--transaction' => '在事务中执行(失败自动回滚)',
|
||||
'--connection=main' => '指定数据库连接配置',
|
||||
'-h, --help' => '显示帮助信息',
|
||||
],
|
||||
'examples' => [
|
||||
'php think tools:db:execute "UPDATE ul_system_admin SET status = 1 WHERE id = 1"' => '更新管理员状态',
|
||||
'php think tools:db:execute "UPDATE ul_system_admin SET status = 1 WHERE id = 1" --transaction' => '在事务中执行',
|
||||
'php think tools:db:execute "UPDATE ul_system_admin SET status = 1 WHERE id = 1" --force' => '强制执行(跳过确认)',
|
||||
],
|
||||
'notes' => [
|
||||
'支持 INSERT、UPDATE、DELETE 语句',
|
||||
'默认需要用户确认',
|
||||
'使用 --force 可跳过确认',
|
||||
'使用 --transaction 可在事务中执行',
|
||||
],
|
||||
],
|
||||
'tools:db:table' => [
|
||||
'title' => '表查询命令 - tools:db:table',
|
||||
'description' => '使用查询构建器操作表',
|
||||
'usage' => 'php think tools:db:table <表名> [选项]',
|
||||
'options' => [
|
||||
'--where=条件' => 'WHERE 条件',
|
||||
'--field=字段' => '查询字段,多个用逗号分隔',
|
||||
'--limit=N' => '限制行数',
|
||||
'--order=排序' => '排序,如 "id DESC"',
|
||||
'--count' => '只统计数量',
|
||||
'--connection=main' => '指定数据库连接配置',
|
||||
'-h, --help' => '显示帮助信息',
|
||||
],
|
||||
'examples' => [
|
||||
'php think tools:db:table system_admin --where "status=1" --limit 10' => '查询表数据',
|
||||
'php think tools:db:table system_admin --field "id,username,nickname"' => '查询指定字段',
|
||||
'php think tools:db:table system_admin --order "id DESC" --limit 5' => '排序查询',
|
||||
'php think tools:db:table system_admin --count' => '统计记录数',
|
||||
],
|
||||
'notes' => [
|
||||
'表名不需要带前缀(会自动添加)',
|
||||
'支持查询构建器所有常用方法',
|
||||
'自动处理表前缀',
|
||||
],
|
||||
],
|
||||
'tools:db:info' => [
|
||||
'title' => '数据库信息命令 - tools:db:info',
|
||||
'description' => '显示数据库连接信息和表列表',
|
||||
'usage' => 'php think tools:db:info [选项]',
|
||||
'options' => [
|
||||
'--connection=main' => '指定数据库连接配置',
|
||||
'--with-count' => '显示每个表的记录数',
|
||||
'-h, --help' => '显示帮助信息',
|
||||
],
|
||||
'examples' => [
|
||||
'php think tools:db:info' => '显示数据库基本信息',
|
||||
'php think tools:db:info --with-count' => '显示表记录数',
|
||||
],
|
||||
'notes' => [
|
||||
'显示数据库连接信息',
|
||||
'显示所有表列表',
|
||||
'使用 --with-count 可显示记录数',
|
||||
],
|
||||
],
|
||||
'tools:db:desc' => [
|
||||
'title' => '表结构命令 - tools:db:desc',
|
||||
'description' => '显示表结构信息',
|
||||
'usage' => 'php think tools:db:desc <表名> [选项]',
|
||||
'options' => [
|
||||
'--connection=main' => '指定数据库连接配置',
|
||||
'--show-index' => '显示索引信息',
|
||||
'-h, --help' => '显示帮助信息',
|
||||
],
|
||||
'examples' => [
|
||||
'php think tools:db:desc system_admin' => '显示表结构',
|
||||
'php think tools:db:desc system_admin --show-index' => '显示索引信息',
|
||||
],
|
||||
'notes' => [
|
||||
'表名不需要带前缀(会自动添加)',
|
||||
'显示字段类型、默认值、是否为空、注释',
|
||||
'使用 --show-index 可显示索引信息',
|
||||
],
|
||||
],
|
||||
'tools:db:count' => [
|
||||
'title' => '统计命令 - tools:db:count',
|
||||
'description' => '统计表记录数',
|
||||
'usage' => 'php think tools:db:count <表名> [选项]',
|
||||
'options' => [
|
||||
'--connection=main' => '指定数据库连接配置',
|
||||
'--where=条件' => 'WHERE 条件',
|
||||
'-h, --help' => '显示帮助信息',
|
||||
],
|
||||
'examples' => [
|
||||
'php think tools:db:count system_admin' => '统计所有记录',
|
||||
'php think tools:db:count system_admin --where "status=1"' => '统计符合条件的记录',
|
||||
],
|
||||
'notes' => [
|
||||
'表名不需要带前缀(会自动添加)',
|
||||
'只显示记录数量',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
if (!isset($helpTexts[$command])) {
|
||||
$output->writeln('帮助信息不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
$help = $helpTexts[$command];
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('<info>' . $help['title'] . '</info>');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>描述:</info>');
|
||||
$output->writeln(' ' . $help['description']);
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>用法:</info>');
|
||||
$output->writeln(' ' . $help['usage']);
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>选项:</info>');
|
||||
foreach ($help['options'] as $option => $desc) {
|
||||
$output->writeln(' <info>' . str_pad($option, 30) . '</info>' . $desc);
|
||||
}
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>示例:</info>');
|
||||
foreach ($help['examples'] as $example => $desc) {
|
||||
$output->writeln(' ' . $desc);
|
||||
$output->writeln(' <info>' . $example . '</info>');
|
||||
}
|
||||
$output->writeln('');
|
||||
$output->writeln('<info>注意事项:</info>');
|
||||
foreach ($help['notes'] as $note) {
|
||||
$output->writeln(' - ' . $note);
|
||||
}
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>' . str_repeat('=', 60) . '</comment>');
|
||||
$output->writeln('');
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,12 @@
|
||||
namespace think;
|
||||
|
||||
use app\common\command\admin\MigrateFileData;
|
||||
use app\common\command\tools\db\ToolsDbCount;
|
||||
use app\common\command\tools\db\ToolsDbDesc;
|
||||
use app\common\command\tools\db\ToolsDbExecute;
|
||||
use app\common\command\tools\db\ToolsDbInfo;
|
||||
use app\common\command\tools\db\ToolsDbQuery;
|
||||
use app\common\command\tools\db\ToolsDbTable;
|
||||
use app\common\command\Test;
|
||||
use app\common\event\AdminLoginSuccess\LogEvent;
|
||||
use app\common\event\AdminLoginType\DemoEvent;
|
||||
@@ -51,7 +57,13 @@ class UlthonAdminService extends Service
|
||||
// 绑定命令行
|
||||
$this->commands([
|
||||
Test::class,
|
||||
MigrateFileData::class
|
||||
MigrateFileData::class,
|
||||
ToolsDbQuery::class,
|
||||
ToolsDbExecute::class,
|
||||
ToolsDbTable::class,
|
||||
ToolsDbInfo::class,
|
||||
ToolsDbDesc::class,
|
||||
ToolsDbCount::class,
|
||||
]);
|
||||
|
||||
// 绑定标识容器
|
||||
|
||||
Reference in New Issue
Block a user