数据库备份
This commit is contained in:
parent
027ba1acdb
commit
78bb8bccd7
@ -5,6 +5,7 @@ use catcher\base\CatchRequest as Request;
|
|||||||
use catcher\base\CatchController;
|
use catcher\base\CatchController;
|
||||||
use catcher\CatchResponse;
|
use catcher\CatchResponse;
|
||||||
use catcher\exceptions\FailedException;
|
use catcher\exceptions\FailedException;
|
||||||
|
use catcher\library\BackUpDatabase;
|
||||||
use think\facade\Console;
|
use think\facade\Console;
|
||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
use think\Paginator;
|
use think\Paginator;
|
||||||
@ -87,10 +88,10 @@ class DataDictionary extends CatchController
|
|||||||
* @throws FailedException
|
* @throws FailedException
|
||||||
* @return \think\response\Json
|
* @return \think\response\Json
|
||||||
*/
|
*/
|
||||||
public function backup(): \think\response\Json
|
public function backup(BackUpDatabase $backUpDatabase): \think\response\Json
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Console::call('backup:data', [trim(implode(',', \request()->post('data')), ','), '-z']);
|
$backUpDatabase->done(trim(implode(',', \request()->post('data')), ','));
|
||||||
}catch (\Exception $e) {
|
}catch (\Exception $e) {
|
||||||
throw new FailedException($e->getMessage());
|
throw new FailedException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@ declare (strict_types = 1);
|
|||||||
namespace catcher\command\Tools;
|
namespace catcher\command\Tools;
|
||||||
|
|
||||||
use catcher\CatchAdmin;
|
use catcher\CatchAdmin;
|
||||||
|
use catcher\facade\FileSystem;
|
||||||
|
use catcher\library\BackUpDatabase;
|
||||||
|
use catcher\library\Zip;
|
||||||
use think\console\Command;
|
use think\console\Command;
|
||||||
use think\console\Input;
|
use think\console\Input;
|
||||||
use think\console\input\Argument;
|
use think\console\input\Argument;
|
||||||
@ -20,7 +23,6 @@ class BackupCommand extends Command
|
|||||||
// 指令配置
|
// 指令配置
|
||||||
$this->setName('backup:data')
|
$this->setName('backup:data')
|
||||||
->addArgument('tables', Argument::REQUIRED, 'backup tables')
|
->addArgument('tables', Argument::REQUIRED, 'backup tables')
|
||||||
->addOption('zip', '-z',Option::VALUE_NONE, 'is need zip')
|
|
||||||
->setDescription('backup data you need');
|
->setDescription('backup data you need');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,158 +30,8 @@ class BackupCommand extends Command
|
|||||||
{
|
{
|
||||||
$tables = $this->input->getArgument('tables');
|
$tables = $this->input->getArgument('tables');
|
||||||
|
|
||||||
$isZip = $this->input->getOption('zip');
|
(new BackUpDatabase)->done($tables);
|
||||||
|
|
||||||
$this->generator(explode(',', $tables), CatchAdmin::backupDirectory());
|
|
||||||
|
|
||||||
if ($isZip) {
|
|
||||||
$this->zip();
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->info('succeed!');
|
$output->info('succeed!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @time 2019年09月30日
|
|
||||||
* @param $tables
|
|
||||||
* @param $format
|
|
||||||
* @param $path
|
|
||||||
* @return void
|
|
||||||
* @throws \think\db\exception\DbException
|
|
||||||
* @throws \think\db\exception\ModelNotFoundException
|
|
||||||
* @throws \think\db\exception\DataNotFoundException
|
|
||||||
*/
|
|
||||||
public function generator($tables, $path): void
|
|
||||||
{
|
|
||||||
foreach ($tables as $table) {
|
|
||||||
$this->table = $table;
|
|
||||||
|
|
||||||
$this->createDataFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建数据文件
|
|
||||||
*
|
|
||||||
* @time 2019年09月27日
|
|
||||||
* @param $format
|
|
||||||
* @return void
|
|
||||||
* @throws \think\db\exception\DbException
|
|
||||||
* @throws \think\db\exception\ModelNotFoundException
|
|
||||||
* @throws \think\db\exception\DataNotFoundException
|
|
||||||
*/
|
|
||||||
public function createDataFile(): void
|
|
||||||
{
|
|
||||||
$file = CatchAdmin::backupDirectory() . $this->table . '.sql';
|
|
||||||
|
|
||||||
$handle = fopen($file, 'wb+');
|
|
||||||
|
|
||||||
fwrite($handle, $begin = "BEGIN;\r\n", \strlen($begin));
|
|
||||||
$this->createClass($this->table, $handle);
|
|
||||||
fwrite($handle, $end = 'COMMIT;', \strlen($end));
|
|
||||||
|
|
||||||
fclose($handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建了临时模型
|
|
||||||
*
|
|
||||||
* @time 2019年09月27日
|
|
||||||
* @param $table
|
|
||||||
* @param $format
|
|
||||||
* @param $handle
|
|
||||||
* @return void
|
|
||||||
* @throws \think\db\exception\DbException
|
|
||||||
* @throws \think\db\exception\ModelNotFoundException
|
|
||||||
* @throws \think\db\exception\DataNotFoundException
|
|
||||||
*/
|
|
||||||
protected function createClass($table, $handle)
|
|
||||||
{
|
|
||||||
$this->setUnbuffered();
|
|
||||||
|
|
||||||
// 防止 IO 多次写入
|
|
||||||
$buffer = [];
|
|
||||||
|
|
||||||
// 记录中记录
|
|
||||||
$total = Db::table($table)->count();
|
|
||||||
|
|
||||||
$limit = 1000;
|
|
||||||
|
|
||||||
// 生成器减少内存
|
|
||||||
while ($total > 0) {
|
|
||||||
$items = Db::table($table)->limit($limit)->select();
|
|
||||||
|
|
||||||
$this->writeIn($handle, $items);
|
|
||||||
|
|
||||||
$total -= $limit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sql 文件格式
|
|
||||||
*
|
|
||||||
* @time 2019年09月27日
|
|
||||||
* @param $handle
|
|
||||||
* @param $data
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function writeIn($handle, $datas)
|
|
||||||
{
|
|
||||||
$values = '';
|
|
||||||
$sql = '';
|
|
||||||
foreach ($datas as $data) {
|
|
||||||
foreach ($data as $value) {
|
|
||||||
$values .= sprintf("'%s'", $value) . ',';
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= sprintf('INSERT INTO `%s` VALUE (%s);' . "\r\n", $this->table, rtrim($values, ','));
|
|
||||||
$values = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
fwrite($handle, $sql, strlen($sql));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置未缓存模式
|
|
||||||
*
|
|
||||||
* @time 2019年09月29日
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function setUnbuffered()
|
|
||||||
{
|
|
||||||
$connections = \config('database.connections');
|
|
||||||
|
|
||||||
$connections['mysql']['params'] = [
|
|
||||||
\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false
|
|
||||||
];
|
|
||||||
|
|
||||||
\config([
|
|
||||||
'connections' => $connections,
|
|
||||||
],'database.connections');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function zip()
|
|
||||||
{
|
|
||||||
if (extension_loaded('zip')) {
|
|
||||||
$files = glob(CatchAdmin::backupDirectory() . '*.sql');
|
|
||||||
$zip = new \ZipArchive();
|
|
||||||
$backupPath = runtime_path('database/');
|
|
||||||
CatchAdmin::makeDirectory($backupPath);
|
|
||||||
$zip->open($backupPath . 'backup.zip', \ZipArchive::CREATE);
|
|
||||||
$zip->addEmptyDir('backup');
|
|
||||||
foreach ($files as $file) {
|
|
||||||
$zip->addFile($file, 'backup/'. basename($file));
|
|
||||||
}
|
|
||||||
$zip->close();
|
|
||||||
|
|
||||||
foreach ($files as $file) {
|
|
||||||
unlink($file);
|
|
||||||
}
|
|
||||||
rmdir(CatchAdmin::backupDirectory());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
174
extend/catcher/library/BackUpDatabase.php
Normal file
174
extend/catcher/library/BackUpDatabase.php
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
namespace catcher\library;
|
||||||
|
|
||||||
|
use catcher\CatchAdmin;
|
||||||
|
use catcher\facade\FileSystem;
|
||||||
|
use think\facade\Db;
|
||||||
|
|
||||||
|
class BackUpDatabase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @time 2020年07月19日
|
||||||
|
* @param $tables
|
||||||
|
* @throws \think\db\exception\DataNotFoundException
|
||||||
|
* @throws \think\db\exception\DbException
|
||||||
|
* @throws \think\db\exception\ModelNotFoundException
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function done($tables)
|
||||||
|
{
|
||||||
|
$this->generator(explode(',', $tables));
|
||||||
|
|
||||||
|
$this->zip();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @time 2019年09月30日
|
||||||
|
* @param $tables
|
||||||
|
* @return void
|
||||||
|
* @throws \think\db\exception\DbException
|
||||||
|
* @throws \think\db\exception\ModelNotFoundException
|
||||||
|
* @throws \think\db\exception\DataNotFoundException
|
||||||
|
*/
|
||||||
|
protected function generator($tables): void
|
||||||
|
{
|
||||||
|
foreach ($tables as $table) {
|
||||||
|
$this->table = $table;
|
||||||
|
|
||||||
|
$this->createDataFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建数据文件
|
||||||
|
*
|
||||||
|
* @time 2019年09月27日
|
||||||
|
* @return void
|
||||||
|
* @throws \think\db\exception\DbException
|
||||||
|
* @throws \think\db\exception\ModelNotFoundException
|
||||||
|
* @throws \think\db\exception\DataNotFoundException
|
||||||
|
*/
|
||||||
|
public function createDataFile(): void
|
||||||
|
{
|
||||||
|
$file = CatchAdmin::backupDirectory() . $this->table . '.sql';
|
||||||
|
|
||||||
|
$handle = fopen($file, 'wb+');
|
||||||
|
|
||||||
|
fwrite($handle, $begin = "BEGIN;\r\n", \strlen($begin));
|
||||||
|
$this->createClass($this->table, $handle);
|
||||||
|
fwrite($handle, $end = 'COMMIT;', \strlen($end));
|
||||||
|
|
||||||
|
fclose($handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建了临时模型
|
||||||
|
*
|
||||||
|
* @time 2019年09月27日
|
||||||
|
* @param $table
|
||||||
|
* @param $handle
|
||||||
|
* @return void
|
||||||
|
* @throws \think\db\exception\DbException
|
||||||
|
* @throws \think\db\exception\ModelNotFoundException
|
||||||
|
* @throws \think\db\exception\DataNotFoundException
|
||||||
|
*/
|
||||||
|
protected function createClass($table, $handle)
|
||||||
|
{
|
||||||
|
$this->setUnbuffered();
|
||||||
|
|
||||||
|
// 防止 IO 多次写入
|
||||||
|
$buffer = [];
|
||||||
|
|
||||||
|
// 记录中记录
|
||||||
|
$total = Db::table($table)->count();
|
||||||
|
|
||||||
|
$limit = 1000;
|
||||||
|
|
||||||
|
// 生成器减少内存
|
||||||
|
while ($total > 0) {
|
||||||
|
$items = Db::table($table)->limit($limit)->select();
|
||||||
|
|
||||||
|
$this->writeIn($handle, $items);
|
||||||
|
|
||||||
|
$total -= $limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql 文件格式
|
||||||
|
*
|
||||||
|
* @time 2019年09月27日
|
||||||
|
* @param $handle
|
||||||
|
* @param $datas
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function writeIn($handle, $datas)
|
||||||
|
{
|
||||||
|
$values = '';
|
||||||
|
$sql = '';
|
||||||
|
foreach ($datas as $data) {
|
||||||
|
foreach ($data as $value) {
|
||||||
|
$values .= sprintf("'%s'", $value) . ',';
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= sprintf('INSERT INTO `%s` VALUE (%s);' . "\r\n", $this->table, rtrim($values, ','));
|
||||||
|
$values = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite($handle, $sql, strlen($sql));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置未缓存模式
|
||||||
|
*
|
||||||
|
* @time 2019年09月29日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function setUnbuffered()
|
||||||
|
{
|
||||||
|
$connections = \config('database.connections');
|
||||||
|
|
||||||
|
$connections['mysql']['params'] = [
|
||||||
|
\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false
|
||||||
|
];
|
||||||
|
|
||||||
|
\config([
|
||||||
|
'connections' => $connections,
|
||||||
|
],'database.connections');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件压缩
|
||||||
|
*
|
||||||
|
* @time 2020年07月19日
|
||||||
|
* @throws \Exception
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function zip()
|
||||||
|
{
|
||||||
|
$files = FileSystem::allFiles(CatchAdmin::backupDirectory());
|
||||||
|
|
||||||
|
$storePath = runtime_path('database/');
|
||||||
|
|
||||||
|
if (!FileSystem::isDirectory($storePath)) {
|
||||||
|
FileSystem::makeDirectory($storePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
(new Zip)->make($storePath . 'backup.zip')->addFiles($files)->close();
|
||||||
|
|
||||||
|
FileSystem::deleteDirectory(CatchAdmin::backupDirectory());
|
||||||
|
}
|
||||||
|
}
|
10
extend/catcher/library/Zip.php
Normal file
10
extend/catcher/library/Zip.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
Loading…
x
Reference in New Issue
Block a user