2014-02-08 2 views
1

가이드 here에 따라 perl 코드에 DBI 연결 처리 서브 루틴을 배치하려고했습니다. 내가 블록을 넣을 수있는 합리적인 장소라고 생각했기 때문에 내가 나중에 DBI 연결에 문제가 생기면 남은 부분 (오히려 길다)을 통과하기 전에 실패 할 것이다. 실행 그러나 내가 예상되는 오류 얻을 때BEGIN 블록의 DBI 연결 및 정의되지 않은 값

BEGIN { 
     my $dbh; 
     use constant { 
       my_host => 'database=MYDB;host=MYHOST', 
       my_user => 'USER', 
       my_pass => 'PASSWORD' 
     }; 

     sub get_db_handle { 
       unless (defined ($dbh)) { 
       my $dbh = DBI->connect(
           ('DBI:mysql:' . my_host), 
           my_user, my_pass, 
           {PrintError => 0, AutoCommit => 0} 
           ) or die $DBI::errstr; 
     } 
     return $dbh; 
     } 
} 

... 
     # Everything works fine without it being in the BEGIN 
     my $db = get_db_handle(); 
     my $sth = $db->prepare($sql); 

는 :

Can't call method "prepare" on an undefined value

이 해결하기 위해이 나는 DBI 바로 use constant 값을 선언 한 후 연결 문자열 실행하고 작동하지만,이하지 않는 것 최선의 접근 방식이며 저자는이 구현에 대한 추가 정보를 게시하지 않았습니다.

DBI 처리기와 하위 처리기를 만들어서 살펴 봐야 할 일반적인 방법이 있습니까? 아니면 위의 사용을 허용하는 defined 문에 대한 더 나은 접근법이 있습니까? 방법?

+1

언급 한 오류 외에도 실제로 당신이 BEGIN에 연결하려고 시도했지만 의미가 없다고 생각합니다. – ikegami

+1

Yup은 BEGIN 중에 연결하지만 가능한 경우 get_db_handle을 사용합니다. – MattSizzle

+1

왜 파일 맨위가 아닌'BEGIN' 블록에'get_db_handle'을 선언하고 싶은지 모르겠습니다. 연결 시도는 서브 루틴 호출시에만 계속됩니다. – Borodin

답변

2

$dbh이라는 두 개의 변수를 선언하고 있습니다. 기존 변수를 사용하려면 my $dbh 대신 $dbh을 사용하십시오. 또한


, 당신은 실제로 당신이 원하는대로 컴파일시에 연결을 시도하지 않으며, 당신은 prepare 성공 여부를 확인하는 것을 잊었다. 고정 :

use constant { 
    MY_HOST => 'database=MYDB;host=MYHOST', 
    MY_USER => 'USER', 
    MY_PASS => 'PASSWORD', 
}; 

{ 
    my $dbh; 

    sub get_db_handle { 
     $dbh ||= DBI->connect(
      'DBI:mysql:' . MY_HOST, 
      MY_USER, MY_PASS, 
      { PrintError => 0, AutoCommit => 0 }, 
     ) 
      or die $DBI::errstr; 

     return $dbh; 
    } 
} 

# Make sure DB errors are discovered early. 
BEGIN { get_db_handle(); } 

... 

my $dbh = get_db_handle(); 
my $sth = $dbh->prepare($sql) 
    or die $DBI::errstr; 

당신이 RaiseError => 1를 사용하는 경우

, 이것은
use constant { 
    MY_HOST => 'database=MYDB;host=MYHOST', 
    MY_USER => 'USER', 
    MY_PASS => 'PASSWORD', 
}; 

{ 
    my $dbh; 

    sub get_db_handle { 
     return $dbh ||= DBI->connect(
      'DBI:mysql:' . MY_HOST, 
      MY_USER, MY_PASS, 
      { RaiseError => 1, PrintError => 0, AutoCommit => 0 }, 
     ); 
    } 
} 

# Make sure DB errors are discovered early. 
BEGIN { get_db_handle(); } 

... 

my $dbh = get_db_handle(); 
my $sth = $dbh->prepare($sql); 

는하지만, 활성화 트랜잭션이 핸들을 캐시 할 수 있습니다 얼마나 많은 의미 확실하지

단축 할 수있다.

+0

도움에 감사드립니다. 감사합니다 :) – MattSizzle

5

제거 my $dbh 2 차은 :

sub get_db_handle { 
       unless (defined ($dbh)) { 
       $dbh = DBI->connect(# <- no "my" here 
           ('DBI:mysql:' . my_host), 
           my_user, my_pass, 
           {PrintError => 0, AutoCommit => 0} 
           ) or die $DBI::errstr; 
     } 
3

문제는 당신이 BEGIN 블록 내부 $dbh 변수를 선언 한 것입니다.

없는 새로운 $dbh 선언하는 경우, 정의 된 외측unless$dbh 여부 검사, 그것을 데이터베이스에 핸들을 할당하고 멀리 던진다.

서브 루틴은 바깥 쪽$dbh의 값을 반환합니다. 항상 undef입니다.

해결 방법은 connect 문 시작 부분에서 my을 제거하는 것입니다. 동일한 변수가 어디에서나 참조됩니다.