PHP mysqli 인터페이스를 사용하여 MariaDB에 저장 프로시저를 호출하는 가장 좋은 방법은 무엇입니까?
8년 된 PHP/MySQL 웹 앱을 MySQL 대신 MariaDB를 사용하여 최신 서버 스택에 포팅하려고 합니다."packets of order" 오류로 인해 동일한 연결에서 둘 이상의 저장 프로시저를 실행할 수 없습니다.아래는 작동해야 하지만 작동하지 않는 코드입니다.여기서 제가 어디서 길을 잃었는지 또는 성공적인 대안이 무엇인지 누군가 지적해 줄 수 있습니까?
<?php
$host = "localhost";
$user = "mysqli_test";
$password = "";
$database = "mysqli_test";
function get_connection()
{
GLOBAL $host, $user, $password, $database;
$connection = new mysqli($host, $user, $password, $database);
if (! $connection || mysqli_connect_errno() )
printf("Connection failure: %s.\n", mysqli_connect_error());
return $connection;
}
// Minimum viable function: isolate necessary steps.
function get_person($connection, $first_name)
{
$query = "CALL Get_By_First_Name(?)";
if (($stmt = $connection->prepare($query))) // error here after first pass
{
$stmt->bind_param('s', $first_name);
if ($stmt->execute())
{
$stmt->store_result();
$stmt->bind_result($id, $fname, $lname, $pets);
while($stmt->fetch())
printf("%3d %20s %20s %2d.\n", $id, $fname, $lname, $pets);
$stmt->free_result();
while ($stmt->next_result()) // my suspected culprit
{
$stmt->store_result();
while ($stmt->fetch())
;
$stmt->free_result();
}
}
$stmt->close();
}
}
if ($conn = get_connection())
{
get_person($conn, "Samuel"); // it works the first time
get_person($conn, "Zelda"); // this time it fails
}
?>
PHP/mysqli 코드를 실행하면 C API를 사용하여 거의 동일한 C++ 코드가 정상적으로 작동하므로 문제가 시작되는 부분인 next_result() 함수를 사용하여 분리할 수 있습니다.C++ 코드에서 next_result()는 TRUE를 반환하여 준비된 문을 사용하여 저장 프로시저를 실행한 후 새 결과를 사용할 수 있음을 나타냅니다.PHP/mysqli 코드에서 next_result()는 false를 반환하며, 실제로 false 반환 값을 무시해도 새 결과를 생성하지 못합니다.
나는 더 많은 설명과 스크립트가 포함된 github 저장소를 만들었는데, 이 저장소는 당신의 컴퓨터에서 실행되어 관심 있는 사람이 있다면 오류를 복제할 수 있습니다.
가장 좋은 방법은 PHP의 저장 프로시저를 사용하지 않는 것입니다...항상 가능한 것은 아닙니다. 때로는 저장 프로시저가 필요하고 드문 경우에도 유용할 수 있습니다.그러나 가능하다면 MySQL 서버에 저장하는 대신 PHP 응용 프로그램으로 로직을 이동해 보십시오.이렇게 하면 훨씬 덜 번거롭습니다.
저장 프로시저를 올바르게 호출하는 방법을 알고 싶다면 PHP 설명서가 가장 좋습니다.저는 최근에 매뉴얼에 나와 있는 대부분의 예제를 개선했기 때문에 모범 사례를 반영하고 실제로 작동하는 것으로 알고 있습니다.mysqli 및 설명서를 사용하여 저장 프로시저를 읽습니다.
을 피하는 것이 좋습니다.mysqli::multi_query()
저장 프로시저가 기능이 존재하는 주된 이유임에도 불구하고.매개 변수를 바인딩하고 SQL 주입을 방지할 수 있도록 준비된 문을 사용하는 것이 좋습니다.
당신이 기억해야 할 중요한 것은CALL()
문은 빈 결과를 생성합니다.저장 프로시저도 결과 집합/세트를 생성하는 경우 이를 반복하고 각각을 가져와야 합니다.저장 프로시저의 문제는 얼마나 많은 결과 집합이 생성될지 절대로 확신할 수 없다는 것입니다.당신은 미지의 것을 어떻게 처리할 수 있습니까?
다음 예를 보십시오(사용자 코드이지만 일부 변경을 수행하고 오류 보고를 활성화했습니다).
function get_connection($host, $user, $password, $database): mysqli
{
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
return new mysqli($host, $user, $password, $database);
// you might want to set the correct charset (e.g. utf8mb4) here before returning
}
function get_person(mysqli $connection, $first_name): mysqli_result
{
$query = "CALL Get_By_First_Name(?)";
$stmt = $connection->prepare($query);
$stmt->bind_param('s', $first_name);
$stmt->execute();
/* We expect this SP to return the main result set,
which we want to return and then an empty result for CALL.
Get the result here and return immediately.
The prepared statement will be closed automatically once
we leave the scope and this will clean up the remaining result set.
*/
return $stmt->get_result();
}
$conn = get_connection($host, $user, $password, $database);
$res1 = get_person($conn, "Samuel");
$res2 = get_person($conn, "Zelda");
var_dump($res1->fetch_all(), $res2->fetch_all());
위 코드에서 저는 제가 호출하는 SP가 두 개의 결과 세트만 반환한다고 가정합니다.는 첫 않습니다.CALL()
두 번째 결과 집합은 문이 정리될 때 삭제됩니다.그렇지 않다면, 저는 전화를 해야 할 것입니다.mysqli_stmt::next_result()
페치될 까지 (" " " " " " " " (" " " " " " ( " " " )가 )mysqli::next_result()
!) 이렇게 하면 번거로운 저장 프로시저를 가장 쉽게 처리할 수 있습니다.
코드를 PDO로 변환했다고 해도 이것이 가장 간단한 방법일 것입니다.mysqli의 경우는 너무 복잡할 수 있으므로 솔루션을 과도하게 설계하지 않도록 주의해야 합니다.저장 프로시저가 커서를 사용하는 경우 PHP 7.4까지 PHP에 버그가 있었습니다.
언급URL : https://stackoverflow.com/questions/69368867/what-is-the-best-practice-for-calling-stored-procedures-using-the-php-mysqli-int
'programing' 카테고리의 다른 글
Enable-PSRemoting 후 원격 파워셸 세션을 생성할 수 없음 (0) | 2023.08.30 |
---|---|
명령줄에서 특정 인증서 저장소로 pfx 파일 가져오기 (0) | 2023.08.30 |
포트 3306에서 MySQL을 시작할 수 없음 (0) | 2023.08.30 |
실행 파일이 컴파일된 플랫폼을 확인하려면 어떻게 해야 합니까? (0) | 2023.08.30 |
mysqdump에서 생성된 /*!xxxxxx 문 */의 의미는 무엇입니까? (0) | 2023.08.30 |