我们已经准备好了,你呢?

2024我们与您携手共赢,为您的企业形象保驾护航!

快速入门:基本配置和使用、读写分离和数据库事务

由 6 年前创建,最后更新于 4 年前 版本号#

php读写分离_分离原理案例_php读写分离原理

简介 它可以非常轻松地连接到不同的数据库并对其执行 CRUD 操作,无论是使用本机 SQL、查询生成器还是 ORM。目前,支持四种类型的数据库系统:

应用程序的数据库配置位于 /.php 中(但数据库用户和密码等敏感信息位于 .env 文件中。如果你不知道 .env 是什么,你可能需要去这里了解更多信息 :)。在此文件中,你可以定义所有数据库连接并指定哪个连接是默认连接。此文件中提供了所有受支持的数据库系统的配置示例。

默认情况下,使用 MySQL 作为数据库引擎,环境已经设置好了样例配置(也就是说如果你作为开发环境,可以零配置使用),当然你也可以根据需要修改本地数据库的配置(修改 .env 中的数据库配置):

php读写分离原理_分离原理案例_php读写分离

配置

在项目根目录下使用touch /.命令创建新数据库后,可以使用数据库绝对路径配置环境变量指向新创建的数据库:

DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite

注:顾名思义,它是一个轻量级、符合 ACID 的关系数据库,包含在一个相对较小的 C 库中。与许多其他数据库管理系统不同,它不是客户端/服务器数据库引擎,而是集成到用户程序中。作为嵌入式数据库,它是应用程序(例如 Web 浏览器)在本地/客户端存储数据的常见选择。有关更多信息,请查看其官方网站:读写分离

有时您希望使用一个数据库连接进行查询,使用另一个数据库连接进行插入、更新和删除。在 SQL 2016 中实现这种读写分离非常简单。无论您使用本机 SQL、查询生成器还是 ORM,只要配置正确,总会使用适当的连接。

要了解如何配置读/写连接,请参考以下示例:

'mysql' => [
    'read' => [
        'host' => '192.168.1.1',
    ],
    'write' => [
        'host' => '196.168.1.2'
    ],
    'driver'    => 'mysql',
    'database'  => 'database',
    'username'  => 'root',
    'password'  => '',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
],

注意我们在配置数组中增加了两个新的键:read 和 write。这两个键对应的值有一个包含单个键“host”的数组,映射到它们的 IP 值分别是读连接和写连接。读/写连接的其他数据库配置项共用 mysql 的主数组配置。

如果我们想覆盖主数组中的配置,只需将相应的配置项放入 read 和 write 数组中即可。在此示例中,192.168.1.1 将用作“读取”连接,而 192.168.1.2 将用作“写入”连接。两个数据库连接的凭据(用户名/密码)、前缀、字符集和其他配置将共享 mysql 数组中的设置。同样,如果它们不同,则可以在 read 或 write 数组中分别配置它们。

对于大多数应用程序来说,读取次数多于写入次数。那么在这种情况下,如何配置多个读取连接和一个写入连接?你可以这样做:

'mysql' => [
    'driver' => 'mysql',
    'read' => [
        'host' => ['193.168.1.1', '194.168.1.1']
    ],
    'write' => [
        'host' => '196.168.1.2'
    ],
    //
]

在读取数据的时候会随机选择一个提供的IP地址进行连接,对实现原理感兴趣的同学可以查看底层源码。

注意:目前读写分离仅支持单个写连接。

选项

该选项是一个可选的配置值,可用于允许立即读取当前请求生命周期内写入数据库的记录。如果启用该选项,并且当前生命周期内发生“写入”操作,则所有后续的“读取”操作都将使用此“写入”连接(前提是它们在同一个请求生命周期内),这确保了同一个请求生命周期内写入的数据可以立即读取,从而避免主从延迟导致的数据不一致。是否启用此功能由您决定。

学园注:当然这只是分布式数据库系统中解决主从数据同步延迟的一个很基础的方案,对于流量不大的中小型网站可以做到,对于流量大、并发大的网站就做不到了。主从读写分离本来就是为了解决单点性能问题,这其实把问题引回来了,导致所有的读写都集中在写数据库上,对于高并发、频繁写入的场景,后果可能是灾难性的。不过话说回来,对于并发不多、写入操作不频繁的中小型网站,这个方法还是一个基本的解决方案。使用不同的数据库连接

当使用多个数据库连接时,可以通过 DB 上的方法访问不同的连接。传递给方法的名称对应于配置文件/.php 中设置的连接:

$users = DB::connection('read')->select(...);

您甚至可以指定数据库和连接名称,以 :::: 分隔

$users = DB::connection('mysql::read')->select(...);

您还可以使用连接实例上的方法访问底层本机 PDO 实例:

$pdo = DB::connection('read')->getPdo();

运行本机 SQL 查询 配置数据库连接后,您可以使用 DB 运行查询。DB 为每个操作提供了方法: 、 、 和 。

运行查询

要运行基本查询,您可以使用 DB 方法:

 $users]);
    }
}

传递给方法的第一个参数是原生的 SQL 语句,第二个参数需要与查询参数绑定,通常这些是 where 子句约束中的值。参数绑定可以避免 SQL 注入攻击(输入参数验证由实现者控制,用户不能传递任意查询参数)。

该方法以数组的形式返回结果集,数组中的每个结果都是一个 PHP 对象:

您可以像这样访问结果值:

foreach ($users as $user) {
    echo $user->name;
}

使用命名绑定

除了使用 ? 占位符来表示参数绑定之外,还可以使用命名绑定来执行查询:

$results = DB::select('select * from users where id = :id', ['id' => 1]);

运行插入语句

使用 DB 方法执行插入语句。与 类似,此方法将原始 SQL 语句作为第一个参数,将参数绑定作为第二个参数:

DB::insert('insert into users (id, name) values (?, ?)', [1, '学院君']);

运行更新语句

该方法用于更新数据库中现有的记录。此方法返回受更新语句影响的行数:

$affected = DB::update('update users set votes = 100 where name = ?', ['学院君']);

运行删除语句

该方法用于删除数据库中的现有记录。例如,此语句返回已删除的行数:

$deleted = DB::delete('delete from users');

注意:使用and语句时需要非常小心,因为如果不仔细设置条件,后果可能是不可挽回的。例如,没有条件的语句会删除数据表中的所有记录!这些都是我们面前的血的教训。运行一般语句

有些数据库语句不返回任何值,比如添加新表、修改表、删除表等,对于这种类型的操作,可以使用DB 方法:

DB::statement('drop table users');

监听查询事件如果你想获取应用程序中执行的每条 SQL 语句,可以使用方法,这对于查询日志记录和调试非常有用。你可以在服务提供者中注册一个查询监听器:

sql
            // $query->bindings
            // $query->time
        });
    }
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

要在数据库事务中运行一系列操作,可以使用 DB 的方法。使用这些方法时,您无需手动回滚或提交:如果事务闭包中抛出异常,则事务将自动回滚;如果闭包执行成功,则事务将自动提交:

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);
    DB::table('posts')->delete();
});

处理死锁

数据库死锁是指两个或多个数据库操作相互依赖,其中一方需要等待另一方退出才能获得资源。但是如果双方都没有提前退出,就会发生死锁。死锁是数据库事务很容易导致的副作用。为此,该方法接收一个可选参数作为第二个参数,用于定义发生死锁时事务的最大重试次数。如果尝试次数超过指定值,则会抛出异常:

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);    
    DB::table('posts')->delete();
}, 5);

手动使用交易

如果您希望手动启动事务以更好地控制回滚和提交,则可以使用 DB 外观方法:

DB::beginTransaction();

您可以通过以下方式回滚事务:

DB::rollBack();

最后,您可以通过该方法提交交易:

DB::commit();

注意:使用 DB 外观的事务方法也可以用于控制查询生成器和 ORM 中的事务,我们很快就会看到。

快速入门:基本配置和使用、读写分离和数据库事务

由 6 年前创建,最后更新于 4 年前 版本号#

php读写分离_分离原理案例_php读写分离原理

简介 它可以非常轻松地连接到不同的数据库并对其执行 CRUD 操作,无论是使用本机 SQL、查询生成器还是 ORM。目前,支持四种类型的数据库系统:

应用程序的数据库配置位于 /.php 中(但数据库用户和密码等敏感信息位于 .env 文件中。如果你不知道 .env 是什么,你可能需要去这里了解更多信息 :)。在此文件中,你可以定义所有数据库连接并指定哪个连接是默认连接。此文件中提供了所有受支持的数据库系统的配置示例。

默认情况下,使用 MySQL 作为数据库引擎,环境已经设置好了样例配置(也就是说如果你作为开发环境,可以零配置使用),当然你也可以根据需要修改本地数据库的配置(修改 .env 中的数据库配置):

php读写分离原理_分离原理案例_php读写分离

配置

在项目根目录下使用touch /.命令创建新数据库后,可以使用数据库绝对路径配置环境变量指向新创建的数据库:

DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite

注:顾名思义,它是一个轻量级、符合 ACID 的关系数据库,包含在一个相对较小的 C 库中。与许多其他数据库管理系统不同,它不是客户端/服务器数据库引擎,而是集成到用户程序中。作为嵌入式数据库,它是应用程序(例如 Web 浏览器)在本地/客户端存储数据的常见选择。有关更多信息,请查看其官方网站:读写分离

有时您希望使用一个数据库连接进行查询,使用另一个数据库连接进行插入、更新和删除。在 SQL 2016 中实现这种读写分离非常容易。无论您使用本机 SQL、查询生成器还是 ORM,只要配置正确,就会始终使用适当的连接。

要了解如何配置读/写连接,请参考以下示例:

'mysql' => [
    'read' => [
        'host' => '192.168.1.1',
    ],
    'write' => [
        'host' => '196.168.1.2'
    ],
    'driver'    => 'mysql',
    'database'  => 'database',
    'username'  => 'root',
    'password'  => '',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
],

注意我们在配置数组中增加了两个新的键:read 和 write。这两个键对应的值有一个包含单个键“host”的数组,映射到它们的 IP 值分别是读连接和写连接。读/写连接的其他数据库配置项共用 mysql 的主数组配置。

如果我们想覆盖主数组中的配置,只需将相应的配置项放入 read 和 write 数组中即可。在此示例中,192.168.1.1 将用作“读取”连接,192.168.1.2 将用作“写入”连接。两个数据库连接的凭据(用户名/密码)、前缀、字符集和其他配置将共享 mysql 数组中的设置。同样,如果它们不同,则可以在 read 或 write 数组中分别配置它们。

对于大多数应用程序来说,读取次数多于写入次数。那么在这种情况下,如何配置多个读取连接和一个写入连接?你可以这样做:

'mysql' => [
    'driver' => 'mysql',
    'read' => [
        'host' => ['193.168.1.1', '194.168.1.1']
    ],
    'write' => [
        'host' => '196.168.1.2'
    ],
    //
]

在读取数据的时候会随机选择一个提供的IP地址进行连接,对实现原理感兴趣的同学可以查看底层源码。

注意:目前读写分离仅支持单个写连接。

选项

该选项是一个可选的配置值,可用于允许立即读取当前请求生命周期内写入数据库的记录。如果启用该选项,并且当前生命周期内发生“写入”操作,则所有后续的“读取”操作都将使用此“写入”连接(前提是它们在同一个请求生命周期内),这确保了同一个请求生命周期内写入的数据可以立即读取,从而避免主从延迟导致的数据不一致。是否启用此功能由您决定。

学园注:当然这只是分布式数据库系统中解决主从数据同步延迟的一个很基础的方案,对于流量不大的中小型网站可以做到,对于流量大、并发大的网站就做不到了。主从读写分离本来就是为了解决单点性能问题,这其实把问题引回来了,导致所有的读写都集中在写数据库上,对于高并发、频繁写入的场景,后果可能是灾难性的。不过话说回来,对于并发不多、写入操作不频繁的中小型网站,这个方法还是一个基本的解决方案。使用不同的数据库连接

当使用多个数据库连接时,可以通过 DB 上的方法访问不同的连接。传递给方法的名称对应于配置文件/.php 中设置的连接:

$users = DB::connection('read')->select(...);

您甚至可以指定数据库和连接名称,以 :::: 分隔

$users = DB::connection('mysql::read')->select(...);

您还可以使用连接实例上的方法访问底层本机 PDO 实例:

$pdo = DB::connection('read')->getPdo();

运行本机 SQL 查询 配置数据库连接后,您可以使用 DB 运行查询。DB 为每个操作提供了方法: 、 、 和 。

运行查询

要运行基本查询,您可以使用 DB 方法:

 $users]);
    }
}

传递给方法的第一个参数是原生的 SQL 语句,第二个参数需要与查询参数绑定,通常这些是 where 子句约束中的值。参数绑定可以避免 SQL 注入攻击(输入参数验证由实现者控制,用户不能传递任意查询参数)。

该方法以数组的形式返回结果集,数组中的每个结果都是一个 PHP 对象:

您可以像这样访问结果值:

foreach ($users as $user) {
    echo $user->name;
}

使用命名绑定

除了使用 ? 占位符来表示参数绑定之外,还可以使用命名绑定来执行查询:

$results = DB::select('select * from users where id = :id', ['id' => 1]);

运行插入语句

使用 DB 方法执行插入语句。与 类似,此方法将原始 SQL 语句作为第一个参数,将参数绑定作为第二个参数:

DB::insert('insert into users (id, name) values (?, ?)', [1, '学院君']);

运行更新语句

该方法用于更新数据库中现有的记录。此方法返回受更新语句影响的行数:

$affected = DB::update('update users set votes = 100 where name = ?', ['学院君']);

运行删除语句

该方法用于删除数据库中的现有记录。例如,此语句返回已删除的行数:

$deleted = DB::delete('delete from users');

注意:使用and语句时需要非常小心,因为如果不仔细设置条件,后果可能是不可挽回的。例如,没有条件的语句会删除数据表中的所有记录!这些都是我们面前的血的教训。运行一般语句

有些数据库语句不返回任何值,比如添加新表、修改表、删除表等,对于这种类型的操作,可以使用DB 方法:

DB::statement('drop table users');

监听查询事件如果你想获取应用程序中执行的每条 SQL 语句,可以使用方法,这对于查询日志记录和调试非常有用。你可以在服务提供者中注册一个查询监听器:

sql
            // $query->bindings
            // $query->time
        });
    }
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

要在数据库事务中运行一系列操作,可以使用 DB 的方法。使用这些方法时,您无需手动回滚或提交:如果事务闭包中抛出异常,则事务将自动回滚;如果闭包执行成功,则事务将自动提交:

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);
    DB::table('posts')->delete();
});

处理死锁

数据库死锁是指两个或多个数据库操作相互依赖,其中一方需要等待另一方退出才能获得资源。但是如果双方都没有提前退出,就会发生死锁。死锁是数据库事务容易导致的副作用。为此,该方法接收一个可选参数作为第二个参数,用于定义发生死锁时事务的最大重试次数。如果尝试次数超过指定值,则会抛出异常:

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);    
    DB::table('posts')->delete();
}, 5);

手动使用交易

如果您希望手动启动事务以更好地控制回滚和提交,则可以使用 DB 外观方法:

DB::beginTransaction();

您可以通过以下方式回滚事务:

DB::rollBack();

最后,您可以通过该方法提交交易:

DB::commit();

注意:使用 DB 外观的事务方法也可以用于控制查询生成器和 ORM 中的事务,我们很快就会看到。

快速入门:基本配置和使用、读写分离和数据库事务

由 6 年前创建,最后更新于 4 年前 版本号#

php读写分离_分离原理案例_php读写分离原理

简介 它可以非常轻松地连接到不同的数据库并对其执行 CRUD 操作,无论是使用本机 SQL、查询生成器还是 ORM。目前,支持四种类型的数据库系统:

应用程序的数据库配置位于 /.php 中(但数据库用户和密码等敏感信息位于 .env 文件中。如果你不知道 .env 是什么,你可能需要去这里了解更多信息 :)。在此文件中,你可以定义所有数据库连接并指定哪个连接是默认连接。此文件中提供了所有受支持的数据库系统的配置示例。

默认情况下,使用 MySQL 作为数据库引擎,环境已经设置好了样例配置(也就是说如果你作为开发环境,可以零配置使用),当然你也可以根据需要修改本地数据库的配置(修改 .env 中的数据库配置):

php读写分离原理_分离原理案例_php读写分离

配置

在项目根目录下使用touch /.命令创建新数据库后,可以使用数据库绝对路径配置环境变量指向新创建的数据库:

DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite

注:顾名思义,它是一个轻量级、符合 ACID 的关系数据库,包含在一个相对较小的 C 库中。与许多其他数据库管理系统不同,它不是客户端/服务器数据库引擎,而是集成到用户程序中。作为嵌入式数据库,它是应用程序(例如 Web 浏览器)在本地/客户端存储数据的常见选择。有关更多信息,请查看其官方网站:读写分离

有时您希望使用一个数据库连接进行查询,使用另一个数据库连接进行插入、更新和删除。在 SQL 2016 中实现这种读写分离非常简单。无论您使用本机 SQL、查询生成器还是 ORM,只要配置正确,总会使用适当的连接。

要了解如何配置读/写连接,请参考以下示例:

'mysql' => [
    'read' => [
        'host' => '192.168.1.1',
    ],
    'write' => [
        'host' => '196.168.1.2'
    ],
    'driver'    => 'mysql',
    'database'  => 'database',
    'username'  => 'root',
    'password'  => '',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
],

注意我们在配置数组中增加了两个新的键:read 和 write。这两个键对应的值有一个包含单个键“host”的数组,映射到它们的 IP 值分别是读连接和写连接。读/写连接的其他数据库配置项共用 mysql 的主数组配置。

如果我们想覆盖主数组中的配置,只需将相应的配置项放入 read 和 write 数组中即可。在此示例中,192.168.1.1 将用作“读取”连接,而 192.168.1.2 将用作“写入”连接。两个数据库连接的凭据(用户名/密码)、前缀、字符集和其他配置将共享 mysql 数组中的设置。同样,如果它们不同,则可以在 read 或 write 数组中分别配置它们。

对于大多数应用程序来说,读取次数多于写入次数。那么在这种情况下,如何配置多个读取连接和一个写入连接?你可以这样做:

'mysql' => [
    'driver' => 'mysql',
    'read' => [
        'host' => ['193.168.1.1', '194.168.1.1']
    ],
    'write' => [
        'host' => '196.168.1.2'
    ],
    //
]

在读取数据的时候会随机选择一个提供的IP地址进行连接,对实现原理感兴趣的同学可以查看底层源码。

注意:目前读写分离仅支持单个写连接。

选项

该选项是一个可选的配置值,可用于允许立即读取当前请求生命周期内写入数据库的记录。如果启用该选项,并且当前生命周期内发生“写入”操作,则所有后续的“读取”操作都将使用此“写入”连接(前提是它们在同一个请求生命周期内),这确保了同一个请求生命周期内写入的数据可以立即读取,从而避免主从延迟导致的数据不一致。是否启用此功能由您决定。

学园注:当然这只是分布式数据库系统中解决主从数据同步延迟的一个很基础的方案,对于流量不大的中小型网站可以做到,对于流量大、并发大的网站就做不到了。主从读写分离本来就是为了解决单点性能问题,这其实把问题引回来了,导致所有的读写都集中在写数据库上,对于高并发、频繁写入的场景,后果可能是灾难性的。不过话说回来,对于并发不多、写入操作不频繁的中小型网站,这个方法还是一个基本的解决方案。使用不同的数据库连接

当使用多个数据库连接时,可以通过 DB 上的方法访问不同的连接。传递给方法的名称对应于配置文件/.php 中设置的连接:

$users = DB::connection('read')->select(...);

您甚至可以指定数据库和连接名称,以 :::: 分隔

$users = DB::connection('mysql::read')->select(...);

您还可以使用连接实例上的方法访问底层本机 PDO 实例:

$pdo = DB::connection('read')->getPdo();

运行本机 SQL 查询 配置数据库连接后,您可以使用 DB 运行查询。DB 为每个操作提供了方法: 、 、 和 。

运行查询

要运行基本查询,您可以使用 DB 方法:

 $users]);
    }
}

传递给方法的第一个参数是原生的 SQL 语句,第二个参数需要与查询参数绑定,通常这些是 where 子句约束中的值。参数绑定可以避免 SQL 注入攻击(输入参数验证由实现者控制,用户不能传递任意查询参数)。

该方法以数组的形式返回结果集,数组中的每个结果都是一个 PHP 对象:

您可以像这样访问结果值:

foreach ($users as $user) {
    echo $user->name;
}

使用命名绑定

除了使用 ? 占位符来表示参数绑定之外,还可以使用命名绑定来执行查询:

$results = DB::select('select * from users where id = :id', ['id' => 1]);

运行插入语句

使用 DB 方法执行插入语句。与 类似,此方法将原始 SQL 语句作为第一个参数,将参数绑定作为第二个参数:

DB::insert('insert into users (id, name) values (?, ?)', [1, '学院君']);

运行更新语句

该方法用于更新数据库中现有的记录。此方法返回受更新语句影响的行数:

$affected = DB::update('update users set votes = 100 where name = ?', ['学院君']);

运行删除语句

该方法用于删除数据库中的现有记录。例如,此语句返回已删除的行数:

$deleted = DB::delete('delete from users');

注意:使用and语句时需要非常小心,因为如果不仔细设置条件,后果可能是不可挽回的。例如,没有条件的语句会删除数据表中的所有记录!这些都是我们面前的血的教训。运行一般语句

有些数据库语句不返回任何值,比如添加新表、修改表、删除表等,对于这种类型的操作,可以使用DB 方法:

DB::statement('drop table users');

监听查询事件如果你想获取应用程序中执行的每条 SQL 语句,可以使用方法,这对于查询日志记录和调试非常有用。你可以在服务提供者中注册一个查询监听器:

sql
            // $query->bindings
            // $query->time
        });
    }
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

要在数据库事务中运行一系列操作,可以使用 DB 的方法。使用这些方法时,您无需手动回滚或提交:如果事务闭包中抛出异常,则事务将自动回滚;如果闭包执行成功,则事务将自动提交:

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);
    DB::table('posts')->delete();
});

处理死锁

数据库死锁是指两个或多个数据库操作相互依赖,其中一方需要等待另一方退出才能获得资源。但是如果双方都没有提前退出,就会发生死锁。死锁是数据库事务容易导致的副作用。为此,该方法接收一个可选参数作为第二个参数,用于定义发生死锁时事务的最大重试次数。如果尝试次数超过指定值,则会抛出异常:

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);    
    DB::table('posts')->delete();
}, 5);

手动使用交易

如果您希望手动启动事务以更好地控制回滚和提交,则可以使用 DB 外观方法:

DB::beginTransaction();

您可以通过以下方式回滚事务:

DB::rollBack();

最后,您可以通过该方法提交交易:

DB::commit();

注意:使用 DB 外观的事务方法也可以用于控制查询生成器和 ORM 中的事务,我们很快就会看到。

二维码
扫一扫在手机端查看

本文链接:https://by928.com/1463.html     转载请注明出处和本文链接!请遵守 《网站协议》
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。

项目经理在线

我们已经准备好了,你呢?

2020我们与您携手共赢,为您的企业形象保驾护航!

在线客服
联系方式

热线电话

13761152229

上班时间

周一到周五

公司电话

二维码
微信
线