Perl如何获取二维数组?Mojolicious查询数据库报fetch未执行错误
问题描述
我尝试在Perl中获取二维数组时遇到数据库错误,但调试过程中可以看到返回了正确的值。
相关代码如下:
my $worker_names = $self->glpi->db->query( 'select user_name from report_users' ); my @all = @{$worker_names->arrays->flatten->to_array}; if ($worker_name ne '') { @all = ( $worker_name ); } # name => [ public, privat, phabricator ] my $table; for my $user_name (@all) { $table->{$user_name}->[0] = '00 Stunden 00 Minuten'; $table->{$user_name}->[1] = '00 Stunden 00 Minuten'; $table->{$user_name}->[2] = '00 Stunden 00 Minuten'; } $glpi_hours->hashes->each( sub { my $row = $_[0]; $table->{$row->{'name'}}->[0] = $row->{'public_actiontime'}; $table->{$row->{'name'}}->[1] = $row->{'private_actiontime'}; }); $phabricator_hours->hashes->each( sub { my $row = $_[0]; $table->{$row->{'name'}}->[2] = $row->{'phab_time'}; });
收到的错误信息如下:
DBD::mysql::st fetchrow_hashref failed: fetch() without execute() at /var/www/perl5/perlbrew/perls/perl-5.28.3/lib/site_perl/5.28.3/Mojo/mysql/Results.pm line 55. # Fetch sql data 52 my $hash = $to->{type} eq 'hash'; 53 my $sql_data 54 = $to->{list} && $hash ? $self->sth->fetchall_arrayref({}) 55 : $to->{list} ? $self->sth->fetchall_arrayref 56 : $hash ? [$self->sth->fetchrow_hashref] 57 : [$self->sth->fetchrow_arrayref]; 58 59 # Optionally expand 60 if ($mode) {
我定位到问题出在my @all = @{$worker_names->arrays->flatten->to_array};这行代码,没有按照预期运行。我使用的开发框架为Mojolicious。
当我在浏览器中运行代码时,首先会出现上述错误,之后可以看到查询获取到的值已经存储在stash中。
解决方案
- 错误原因:
这个报错是Mojo::mysql的常见问题,本质是对已经消费完毕、处于关闭状态的结果集句柄再次执行读取操作,或者SQL执行失败后直接读取无效的结果集。 - 修复步骤:
- 先增加SQL执行错误判断,避免查询失败后直接操作结果集:
my $worker_names = $self->glpi->db->query('select user_name from report_users'); # 先判断查询是否出错 my $error = $self->glpi->db->error; die "数据库查询失败: $error->[1]" if $error;
- 调整结果集读取写法,Mojo::Collection的flatten方法可以直接返回展开的列表,不需要额外调用to_array再解引用,避免多余的结果集操作:
# 修改前 # my @all = @{$worker_names->arrays->flatten->to_array}; # 修改后 my @all = $worker_names->arrays->flatten->each;
- 检查后续代码逻辑,确保不会重复使用
$worker_names这个结果集对象。Mojo::mysql的Results对象属于一次性消费资源,调用arrays/hashes等方法读取完数据后,底层的数据库句柄就会被关闭,再次读取就会触发该报错。如果后续需要用到这份用户名数据,直接使用已经读取好的@all数组即可。
你看到报错后stash中仍有数据,是因为该错误默认以警告形式抛出,不会直接终止程序运行,后续的stash赋值逻辑仍会执行。
内容的提问来源于stack exchange,提问作者Dex
相关产品推荐
相关产品推荐

