我正在尝试使用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本身没有报告任何错误 - 它只返回零行。
编辑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(默认值)时,两个查询都能正常工作。
在较短的查询中,我尝试添加绑定变量,连接到几个表,一个组,但它继续正常工作。两者之间的某个位置是导致其失败的点或术语。