使用模型工厂的 MySQL 锁定等待超时

2022-08-30 18:38:11

我在测试类上的方法中生成了一个非常小的数据集,我尝试过在方法中生成数据,但它导致每个测试的锁定等待超时。将此代码移出方法并将其放入其自己的方法中会有所帮助。这意味着并非每个测试都抱怨锁。setUp()setUp()

我正在使用Laravel 5.2中的DatabaseTransactions特征,以便在运行每个测试用例之前重置数据库。

在我拥有的每个测试用例中,我都会调用以获取这样的模拟数据。

$data = self::getRandomCommunityWithAssociatedData();

实际方法只为创建的社区生成几个社区对象和用户对象。

public static function getRandomCommunityWithAssociatedData()
{
    self::$communities = factory(\Community::class, self::COMMUNITIES_TO_CREATE)->create()->each(function ($community) {
        self::$users[$community->id] = factory(User::class, self::USERS_TO_CREATE)->create()->each(function (\User $user) use ($community) {
            $user->community()->associate($community);
        });

        self::$admins[$community->id] = factory(User::class, 'superadmin', self::ADMINS_TO_CREATE)->create()->each(function (\User $admin) use ($community) {
            $admin->community()->associate($community);
        });
    });

    $community = self::$communities[mt_rand(0, count(self::$communities) - 1)];

    return ['community' => $community, 'users' => self::$users[$community->id], 'admins' => self::$admins[$community->id]];
}

该方法中使用了一些常量,它们用于确定要创建的每个对象的数量。目前,我正在为每个社区实例创建2个社区和3个用户和2个管理员。

锁定等待超时是不可预测的,一次运行它可能发生在第一个测试用例上,另一次运行它可能发生在第五个测试用例上。

我试图将MySQL等待锁定的时间增加到500秒,但我仍然得到超时。增加此时间确实不是一种选择,因为测试需要能够在所有环境中运行。

关于为什么在Laravel 5.2中使用具有如此小数据集的数据库事务特征时,我可能会得到这些锁定等待超时的任何想法?

1) UserEmailNotificationsTest::testActiveAdminReceivesNewCommentEmailNotification
Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction (SQL: insert into `communities` (`

执行的上述查询是在社区表上的简单插入,在此数据生成中没有复杂的子查询或类似内容。

已启用查询日志,结果。

       30 Query START TRANSACTION
       30 Query SAVEPOINT trans2
       30 Prepare   insert into `communities` (`viddler_id`, `domain`, `subdomain`, `active`, `max_seats`, `created_at`, `updated_at`, `assignment_seats`, `general_settings`, `access_settings`, `branding_settings`) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
       30 Execute   insert into `communities` (`viddler_id`, `domain`, `subdomain`, `active`, `max_seats`, `created_at`, `updated_at`, `assignment_seats`, `general_settings`, `access_settings`, `branding_settings`) values ('74', 'gaylord.com', 'qui', '1', '24', '2016-03-30 16:25:45', '2016-04-04 02:27:04', '23', 'a:11:{s:5:\"title\";s:0:\"\";s:11:\"description\";s:0:\"\";s:10:\"meta_title\";s:0:\"\";s:16:\"meta_description\";s:0:\"\";s:13:\"meta_keywords\";s:0:\"\";s:17:\"thumbnail_display\";s:0:\"\";s:18:\"group_nomenclature\";s:8:\"Channels\";s:13:\"home_template\";s:0:\"\";s:11:\"api_version\";s:1:\"2\";s:8:\"language\";s:2:\"en\";s:21:\"use_nested_navigation\";i:0;}', 'a:10:{s:12:\"restrictions\";s:10:\"Restricted\";s:17:\"auto_registration\";i:0;s:14:\"default_active\";i:0;s:12:\"oauth_google\";i:0;s:14:\"oauth_facebook\";i:0;s:14:\"oauth_linkedin\";i:0;s:16:\"oauth_reg_google\";i:0;s:18:\"oauth_reg_facebook\";i:0;s:18:\"oauth_reg_linkedin\";i:0;s:11:\"lti_enabled\";i:0;}', 'a:14:{s:13:\"contact_email\";s:0:\"\";s:17:\"contact_link_text\";s:0:\"\";s:9:\"logo_file\";s:0:\"\";s:14:\"carousel_items\";s:0:\"\";s:11:\"html_header\";s:0:\"\";s:16:\"footer_copyright\";s:45:\"© 2015 Viddler Inc. All Rights Reserved.\";s:19:\"footer_privacy_link\";s:37:\"http://www.viddler.com/privacy-policy\";s:17:\"footer_terms_link\";s:35:\"http://www.viddler.com/terms-of-use\";s:14:\"help_link_text\";s:4:\"Help\";s:9:\"help_link\";s:0:\"\";s:7:\"color_1\";s:7:\"#ffffff\";s:7:\"color_2\";s:7:\"#2C333C\";s:7:\"color_3\";s:7:\"#2C333C\";s:7:\"color_4\";s:7:\"#60a1d7\";}')
160404  9:30:25    30 Close stmt
       21 Query ROLLBACK
       21 Quit
       22 Query ROLLBACK
       22 Quit
       23 Query ROLLBACK
       23 Quit
       24 Query ROLLBACK
       24 Quit
       25 Query ROLLBACK
       25 Quit
       26 Query ROLLBACK
       26 Quit
       27 Query ROLLBACK
       27 Quit
       28 Query ROLLBACK
       28 Quit
       29 Query ROLLBACK
       29 Quit
       30 Query ROLLBACK
       30 Quit

答案 1

因此,增加锁定等待超时不是最佳做法。最佳做法是捕获错误并恢复

正式地说,这是你应该做的:

死锁和锁定等待超时在繁忙的服务器上都是正常的,应用程序必须意识到它们可能发生,并通过重试来处理它们。通过在事务期间对数据进行第一次更改和提交之间尽可能少地执行一些工作,可以降低它们的可能性,因此锁的保留时间尽可能短,行数尽可能少。有时,在不同事务之间拆分工作可能是实用和有帮助的。


答案 2

推荐