如果在长查询中使用自定义函数,则PHP / PDO MySQL会断开连接

时间:2014-09-16 22:44:31

标签: php mysql laravel pdo

我正在尝试使用Laraval的流畅查询构建器运行查询。该查询包括SELECT部分​​中的自定义函数。它适用于非常简单的查询,但在较大的查询中,自定义查询的存在会导致连接被删除。

这是一个有效的简单查询:

    $query = DB::connection('crm')
        ->table('contacts')
        ->where('id', '=', '6eb31b38-b813-5d5c-d33d-52ab2498835b')
        ->addSelect('id', 'first_name', 'last_name')
        ->addSelect(DB::raw('my_contact_emails(id, 1) as email'))
        ;
    $row = $query->first();

my_contact_emails()数据库函数将为contact.id提取一个或多个电子邮件,作为单个以逗号分隔的字符串。我对这个较小的查询没有任何问题。

我还有一个更大的查询,它连接了大约12个表,并且返回了大约20列。只要不使用自定义函数,它也可以正常工作。一旦我添加自定义函数,如上面较小的查询所示,MySQL数据库会将此错误报告给其日志,并且连接已关闭:

  

140916 23:25:55 [警告]中止连接2625770到db:'my_db'   用户:'my_user'主持人:'my.server.co.uk'(阅读时出错   通讯包)

这是使用Laravel PDO,全面整理了utf8_general_ci(所有表格,所有列,Laravel数据库驱动程序)。

如果我接受查询构建器生成的查询,并将其粘贴到PHPmyAdmin中,那么它可以正常工作。 MySQL Workbench也是如此。但是使用Laravel 4.2 PDO驱动程序,可以在数据库服务器上看到此错误。 Laravel本身没有报告任何错误 - 它只返回零行。

  • MySQL 5.5.39
  • PHP 5.4.32
  • Laravel 4.2
  • PDO-MySQL驱动程序5.1.59

编辑1: 编辑2: 编辑3: 删除了这些编辑(4和5覆盖它)

编辑4:

Laravel在创建PDO对象时设置了许多选项。这是一个:

PDO::ATTR_EMULATE_PREPARES => false

这就是导致SELECT子句中的自定义数据库函数废弃数据库连接的原因。如果我将其设置为true或将其注释掉,则查询可以正常工作。我将调查此PDO选项的用途以及导致此问题的原因。

因此,如果我理解正确,将PDO :: ATTR_EMULATE_PREPARES重置为false将始终首先转到MySQL驱动程序以准备语句。在我的情况下,某种程度上无法正确准备语句,然后MySQL在尝试执行语句时失败。我的解决方案是模拟prepare(将其设置为true),这(我认为)意味着PDO将构建完整的SQL语句而不是MySQL数据库。当我更全面地了解正在发生的事情,为什么它会失败,为什么模拟使它看起来有效,以及真正完成以使其发挥作用时,我会将此作为答案发布。

编辑5:这是两个查询,显示丢失的连接发生或未发生。我正在使用一个简单的PDO prepare()/ execute()/ fetchAll(),因此Laracel不在循环中。在构建查询之后,所有Laravel贡献的是PDO::ATTR_EMULATE_PREPARES设置。

在两个查询中,选择部分是:

SELECT my_contact_emails(c.id, 1) as email

简短查询如下所示:

FROM contacts as c limit 10

较长的查询如下所示:

from `contacts` as `c` 
inner join `contacts_cstm` as `cc` on `cc`.`id_c` = `c`.`id` 
inner join `sw_bookings_contacts_c` as `bc` on `bc`.`sw_booking50e1ontacts_idb` = `c`.`id` and `bc`.`deleted` = ? 
inner join `sw_bookings` as `b` on `bc`.`sw_booking50a3ookings_ida` = `b`.`id` and `b`.`deleted` = ? 
inner join `sw_bookings_cstm` as `b_cstm` on `b_cstm`.`id_c` = `b`.`id` 
inner join `sw_bookingsw_expedition_c` as `be` on `be`.`sw_bookinga016ookings_idb` = `b`.`id` and `be`.`deleted` = ? 
inner join `sw_expedition` as `e` on `be`.`sw_booking29d8edition_ida` = `e`.`id` and `e`.`deleted` = ? and `e`.`status` = ? 
inner join `erp_erplookup` as `el_type` on `el_type`.`contact_type` = `cc`.`type_c` and `el_type`.`deleted` = ? and `el_type`.`lookup_type` = ? 
left join `erp_erplookup` as `erp_l` on `erp_l`.`salutation` = `c`.`salutation` and `erp_l`.`deleted` = ? and `erp_l`.`lookup_type` = ? 
left join `sw_country_regions` as `crs` on `crs`.`id` = `c`.`primary_address_state` and `crs`.`deleted` = ? 
left join `sw_country_regions_cstm` as `crs_cstm` on `crs_cstm`.`id_c` = `crs`.`id` 
left join `sw_country_regions` as `cr` on `c`.`primary_address_state` = `cr`.`code` 
left join `sw_country_regions_cstm` as `crc` on `crc`.`id_c` = `cr`.`id` 
left join `accounts_contacts_1_c` as `ac1c` on `ac1c`.`accounts_ccb6contacts_idb` = `c`.`id` 
left join `accounts` as `student_of` on `student_of`.`id` = `ac1c`.`accounts_cd3b9ccounts_ida` 
left join `accounts_cstm` as `student_of_c` on `student_of_c`.`id_c` = `student_of`.`id` 
left join `sw_bookings_accounts_c` as `ba` on `ba`.`sw_booking9ce7ookings_ida` = `b`.`id` and `ba`.`deleted` = ? 
left join `accounts` as `booked_account` on `booked_account`.`id` = `ba`.`sw_booking6ef1ccounts_idb` and `booked_account`.`deleted` = ? 
left join `accounts_cstm` as `booked_account_c` on `booked_account_c`.`id_c` = `booked_account`.`id` 
where `b`.`booking_type` in (?, ?, ?, ?, ?) 
and `b_cstm`.`booking_status_c` in (?) 
and `c`.`deleted` = ? 
and `cc`.`type_c` in (?, ?, ?, ?) 
and (`b`.`booking_type` != ? or (`b`.`booking_type` = ? 
and `b_cstm`.`invoice_party_c` = ?)) 
and LEAST(DATEDIFF(CURDATE(), c.date_modified), DATEDIFF(CURDATE(), b.date_modified)) <= ? 
group by `c`.`id` 
limit 10
# Welcome to SugarCRM!
带有绑定数组的

[0,0,0,0,"ACTIVE",0,"contact_type",0,"salutation",0,0,0,"RESEARCH","DISS","PREMED","MASTERS",
"SCHOOL","CONFIRMED",0,"Volunteer","Masters","Student","School","SCHOOL","SCHOOL","individual",28]

PDO::ATTR_EMULATE_PREPARES设置为false时,短查询将起作用,而长查询将丢弃数据库连接。当PDO::ATTR_EMULATE_PREPARES设置为true(默认值)时,两个查询都能正常工作。

在较短的查询中,我尝试添加绑定变量,连接到几个表,一个组,但它继续正常工作。两者之间的某个位置是导致其失败的点或术语。

0 个答案:

没有答案