>  기사  >  백엔드 개발  >  PDO 대 MySQLi: PHP 데이터베이스 API의 전투

PDO 대 MySQLi: PHP 데이터베이스 API의 전투

藏色散人
藏色散人원래의
2019-03-22 10:56:302815검색

PDO 대 MySQLi: PHP 데이터베이스 API의 전투

소개

사용 mysql_#🎜 🎜 PHP 5.5부터 메소드가 더 이상 사용되지 않고 PHP 7부터 제거되었으므로 # 확장의 시대는 끝났습니다. 그러나 인터넷에는 초보자가 복사/붙여넣기하고 공유 호스팅 플랫폼에서 이전 버전의 PHP와 함께 사용할 수 있는 오래된 튜토리얼이 여전히 가득합니다.

PHP에서 MySQL 또는 MariaDB를 사용하는 경우 이제 MySQLi 또는 PDO 옵션이 제공됩니다. 전자는 개선된 버전일 뿐이며 절차적 및 OOP를 지원하고 준비된 명령문을 추가하는 반면, 후자는 지원하는 12개 데이터베이스 드라이버 모두에 대해 통합 API를 사용할 수 있는 추상화 계층입니다. MySQL은 PHP 세계에서 가장 인기 있는 데이터베이스이지만.

이론적으로 존재하는 모든 데이터베이스 유형에 대해 공급업체별 API를 가질 필요는 없습니다. 하나의 데이터베이스를 사용하는 것이 훨씬 더 간단하기 때문입니다. 여기에는 확실히 많은 진실이 있지만 문제는

PDO_MYSQL에는 MySQLi이 제공하는 모든 최신 및 뛰어난 기능이 없다는 것입니다. 솔직히 왜 이런 일이 일어나는지 이해가 되지 않습니다. 이렇게 하면 공급업체별 API를 사용할 이유가 완전히 없어지기 때문입니다. 그럼에도 불구하고 대부분의 사람들은 이러한 추가 기능이 필요하지 않다고 생각하지만 확실히 필요한 사람들도 있습니다.

PDO의 장점

1. 유용한 획득 방법

2. Execute

3. 변수 유형을 자동으로 감지하는 기능(실제로 서버로 전송되면 모든 것이 문자열로 처리되지만 올바른 유형으로 변환됩니다. 이는 100% 전처리에서 수행됩니다. 명령문에서는 유효하지만 시뮬레이션 모드와 같은 일부 극단적인 경우에는 유효하지 않음)

4. 준비된 명령문을 사용하여 결과를 자동으로 버퍼링하는 옵션 제공

#🎜🎜 #5. 명명된 매개변수(PDO에서 시뮬레이션 모드를 끄는 것은 동일한 이름을 한 번만 사용할 수 있기 때문에 쓸모가 없습니다) 🎜🎜#1. 비동기 쿼리

2. 동일한 값으로 행을 업데이트하는 것과 같습니다(PDO의 생성자 설정으로 수행할 수 있으며 나중에 변경할 수 없음)

3. 올바른 데이터베이스 종료 방법4. 한 번(PDO에서 시뮬레이션 모드가 켜져 있으면 괜찮습니다)

5. 영구 연결을 사용하여 자동으로 삭제

코드의 차이점

PDO와 MySQLi는 매우 유사하지만 구문이 약간 다릅니다. MySQLi는 기존 PHP snake_case 규칙을 따르는 반면 PDO는 camelCase를 사용합니다. 또한 MySQLi의 메소드는 객체 속성으로 사용되는 반면 PDO는 함수에 대한 전통적인 구문을 사용합니다.

PDO와 MySQLi 모두 준비된 명령문을 사용하려면 두 가지 별도의 방법을 사용해야 하므로 상황이 복잡해집니다. 그러나 PDO를 사용하면 전용 바인딩 기능을 사용할 필요가 없습니다.

예를 들어 공급업체별 PostgreSQL API에서는 이 작업을 수행할 수 있습니다. 다음은 참고용으로 "준비되지 않은" 쿼리를 수행하여 MySQLi 및 PDO가 포함된 연관 배열을 가져오는 방법의 예입니다.

$arr = $mysqli->query("SELECT * FROM myTable")->fetch_all(MYSQLI_ASSOC);
$arr = $pdo->query("SELECT * FROM myTable")->fetchAll(PDO::FETCH_ASSOC);

사실 가장 좋은 방법은 래퍼, 쿼리 빌더 또는 ORM을 사용하는 것입니다. PDO는 값을 직접 실행에 바인딩할 수 있지만 여전히 이상적이지는 않습니다. 제가 만든 클래스에서는 매개변수 바인딩으로 값을 전달하면서 모든 호출을 연결할 수 있습니다.

$arr = $mysqli->query("SELECT * FROM myTable WHERE id > ?", [12])->fetchAll('assoc');

이제 전체 연관 배열이 보다 간결한 방식으로 변수에 저장됩니다. 새 데이터베이스 연결 만들기

삽입, 업데이트, 삭제

PDO

$dsn = "mysql:host=localhost;dbname=myDatabase;charset=utf8mb4";$options = [
  PDO::ATTR_EMULATE_PREPARES   => false, // turn off emulation mode for "real" prepared statements
  PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, //turn on errors in the form of exceptions
  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, //make the default fetch be an associative array];try {
  $pdo = new PDO($dsn, "username", "password", $options);} catch (Exception $e) {
  error_log($e->getMessage());
  exit('Something weird happened'); //something a user can understand}

MySQLi

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);try {
  $mysqli = new mysqli("localhost", "username", "password", "databaseName");
  $mysqli->set_charset("utf8mb4");} catch(Exception $e) {
  error_log($e->getMessage());
  exit('Error connecting to database'); //Should be a message a typical user could understand}

PDO 사용에 유의하세요 prepare()가 실행()에 연결될 수 있습니다.

영향을 받은 행 수 가져오기

PDO

$stmt = $pdo->prepare("INSERT INTO myTable (name, age) VALUES (?, ?)");
$stmt->execute([$_POST['name'], 29]);
$stmt = null;

MySQLi

$stmt = $mysqli->prepare("UPDATE myTable SET name = ? WHERE id = ?");
$stmt->bind_param("si", $_POST['name'], $_SESSION['id']);
$stmt->execute();
$stmt->close();

최신 기본 키 삽입

두 방법 모두 $stmt가 아닌 연결 변수를 사용한다는 점에 유의하세요.

PDO

$stmt->rowCount();

MySQLi

$stmt->affected_rows;

일치하는 행 가져오기

PDO# 🎜 🎜#

PDO에서 이를 달성하는 유일한 방법은 rowCount()의 동작을 변경하는 연결 옵션으로 설정하는 것입니다. 이는 rowCount()가 전체 데이터베이스 연결에 대해 일치하는 행 또는 변경된 행을 반환하지만 둘 다를 반환하지 않음을 의미합니다.

$pdo->lastInsertId();

MySQLi

$mysqli->insert_id;
이렇게 하면 다음과 같이 전체 문자열의 정보가 출력됩니다.
$options = [
  PDO::MYSQL_ATTR_FOUND_ROWS => true];

다음과 같이 할 수 있습니다

$mysqli->info;
#🎜🎜 #이제 이러한 값에 쉽게 액세스할 수 있습니다. 참고로 값은 문자열이므로 모든 값을 int로 변환해도 되고,

===

을 사용하거나

==

을 엄격하게 확인할 수도 있습니다.

Rows matched: 1 Changed: 0 Warnings: 0

Grab

연관 배열 가져오기

PDO#🎜🎜 #

preg_match_all('/(\S[^:]+): (\d+)/', $mysqli->info, $matches); 
$infoArr = array_combine ($matches[1], $matches[2]);
var_export($infoArr);
###mysqli###
['Rows matched' => '1', 'Changed' => '0', 'Warnings' => '0']
#🎜🎜 ## 🎜🎜#단일 행#🎜🎜 ## 🎜🎜 ###pdo####
$stmt = $pdo->prepare("SELECT * FROM myTable WHERE id <= ?");
$stmt->execute([5]);
$arr = $stmt->fetchAll(PDO::FETCH_ASSOC);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
###mysqli################ ee

단일 값 가져오기(스칼라)

PDO

$stmt = $mysqli->prepare("SELECT id, name, age FROM myTable WHERE name = ?");
$stmt->bind_param("s", $_POST[&#39;name&#39;]);
$stmt->execute();
$arr = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
MySQLi
$stmt = $pdo->prepare("SELECT id, name, age FROM myTable WHERE name = ?");
$stmt->execute([$_POST[&#39;name&#39;]]);
$arr = $stmt->fetch(PDO::FETCH_ASSOC);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
#🎜 🎜# 객체 배열 가져오기

PDO

$stmt = $mysqli->prepare("SELECT id, name, age FROM myTable WHERE name = ?");
$stmt->bind_param("s", $_POST[&#39;name&#39;]);
$stmt->execute();
$arr = $stmt->get_result()->fetch_assoc();
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
MySQLi

class myClass {}
$arr = [];
$stmt = $mysqli->prepare("SELECT id, name, age FROM myTable WHERE id = ?");
$stmt->bind_param("s", $_SESSION[&#39;id&#39;]);
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_object(&#39;myClass&#39;)) {
  $arr[] = $row;
}
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();

正如你所看到的,PDO在这里非常出色。MySQLi没有像$mysqli_result->fetch_all(MYSQLI_OBJ)这样的东西。PDO甚至更进一步,通过使用fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'myClass')对它进行位元化,以处理在类构造函数之后调用它的默认行为。可以在MySQLi中复制这种行为,但是它依赖于省略构造函数,和魔术方法 _set(),或者只在构造函数中设置它(如果它不等于默认值)。

PDO

$search = "%{$_POST[&#39;search&#39;]}%";
$stmt = $pdo->prepare("SELECT id, name, age FROM myTable WHERE name LIKE ?");
$stmt->execute([$search]);
$arr = $stmt->fetchAll();
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copy

MySQLi

$search = "%{$_POST[&#39;search&#39;]}%";
$stmt = $mysqli->prepare("SELECT id, name, age FROM myTable WHERE name LIKE ?"); 
$stmt->bind_param("s", $search);
$stmt->execute();
$arr = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();

获取模式

到目前为止,这是我最喜欢的PDO特性。PDO中的获取模式非常有用,而MySQLi还没有添加它们。

获取键/值对

PDO

$stmt = $pdo->prepare("SELECT event_name, location FROM events WHERE id < ?");
$stmt->execute([25]);
$arr = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copy

MySQLi

$arr = [];
$id = 25;
$stmt = $con->prepare("SELECT event_name, location FROM events WHERE id < ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_row()) {
  $arr[$row[0]] = $row[1];
}
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();

输出:

[&#39;Cool Event&#39; => &#39;Seattle&#39;, &#39;Fun Event&#39; => &#39;Dallas&#39;, &#39;Boring Event&#39; => &#39;Chicago&#39;]

获取组列

PDO

$stmt = $pdo->prepare("SELECT hair_color, name FROM myTable WHERE id < ?");
$stmt->execute([10]);
$arr = $stmt->fetchAll(PDO::FETCH_GROUP | PDO::FETCH_COLUMN);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copy

MySQLi

$arr = [];
$id = 10;
$stmt = $con->prepare("SELECT hair_color, name FROM myTable WHERE id < ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_row()) {
  $arr[$row[0]][] = $row[1];
}
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copy

输出:

[
  &#39;blonde&#39; => [&#39;Patrick&#39;, &#39;Olivia&#39;],
  &#39;brunette&#39; => [&#39;Kyle&#39;, &#39;Ricky&#39;],
  &#39;red&#39; => [&#39;Jordan&#39;, &#39;Eric&#39;]
]

获取键/值对数组

PDO

$stmt = $pdo->prepare("SELECT id, max_bench, max_squat FROM myTable WHERE weight < ?");
$stmt->execute([200]);
$arr = $stmt->fetchAll(PDO::FETCH_UNIQUE);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copy

MySQLi

$arr = [];
$weight = 200;
$stmt = $con->prepare("SELECT id, max_bench, max_squat FROM myTable WHERE weight < ?");
$stmt->bind_param("i", $weight);
$stmt->execute();
$result = $stmt->get_result();
$firstColName = $result->fetch_field_direct(0)->name;
while($row = $stmtResult->fetch_assoc()) {
  $firstColVal = $row[$firstColName];
  unset($row[$firstColName]);
  $arr[$firstColVal] = $row;
}
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copy

输出:

[
  17 => [&#39;max_bench&#39; => 230, &#39;max_squat&#39; => 175],
  84 => [&#39;max_bench&#39; => 195, &#39;max_squat&#39; => 235],
  136 => [&#39;max_bench&#39; => 135, &#39;max_squat&#39; => 285]
]

获取组

PDO

$stmt = $pdo->prepare("SELECT hair_color, name, age FROM myTable WHERE id < ?");
$stmt->execute([12]);
$arr = $stmt->fetchAll(PDO::FETCH_GROUP);
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt = null;
Copy

MySQLi

$arr = [];
$id = 12;
$stmt = $con->prepare("SELECT hair_color, name, age FROM myTable WHERE id < ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
$firstColName = $result->fetch_field_direct(0)->name;
while($row = $stmtResult->fetch_assoc()) {
  $firstColVal = $row[$firstColName];
  unset($row[$firstColName]);
  $arr[$firstColVal][] = $row;
}
if(!$arr) exit(&#39;No rows&#39;);
var_export($arr);
$stmt->close();
Copy

输出:

[
  &#39;blonde&#39; => [
    [&#39;name&#39; => &#39;Patrick&#39;, &#39;age&#39; => 22],
    [&#39;name&#39; => &#39;Olivia&#39;, &#39;age&#39; => 18]
  ],
  &#39;brunette&#39;  => [
    [&#39;name&#39; => &#39;Kyle&#39;, &#39;age&#39;=> 25],
    [&#39;name&#39; => &#39;Ricky&#39;, &#39;age&#39; => 34]
  ],
   &#39;red&#39;  => [
    [&#39;name&#39; => &#39;Jordan&#39;, &#39;age&#39; => 17],
    [&#39;name&#39; => &#39;Eric&#39;, &#39;age&#39; => 52]
  ]
]

在数组中的位置

PDO

$inArr = [1, 3, 5];
$clause = implode(&#39;,&#39;, array_fill(0, count($inArr), &#39;?&#39;)); 
$stmt = $pdo->prepare("SELECT * FROM myTable WHERE id IN ($clause)");
$stmt->execute($inArr);
$resArr = $stmt->fetchAll();
if(!$resArr) exit(&#39;No rows&#39;);
var_export($resArr);
$stmt = null;
Copy

MySQLi

$inArr = [12, 23, 44];
$clause = implode(&#39;,&#39;, array_fill(0, count($inArr), &#39;?&#39;)); /
$types = str_repeat(&#39;i&#39;, count($inArr)); /
$stmt = $mysqli->prepare("SELECT id, name FROM myTable WHERE id IN ($clause)");
$stmt->bind_param($types, ...$inArr);
$stmt->execute();
$resArr = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
if(!$resArr) exit(&#39;No rows&#39;);
var_export($resArr);
$stmt->close();

与其他占位符一起排列的位置

PDO

$inArr = [1, 3, 5];
$clause = implode(&#39;,&#39;, array_fill(0, count($inArr), &#39;?&#39;)); 
$stmt = $pdo->prepare("SELECT * FROM myTable WHERE id IN ($clause) AND id < ?");
$fullArr = array_merge($inArr, [5]); 
$stmt->execute($fullArr);
$resArr = $stmt->fetchAll();
if(!$resArr) exit(&#39;No rows&#39;);
var_export($resArr);
$stmt = null;
Copy

MySQLi

$inArr = [12, 23, 44];
$clause = implode(&#39;,&#39;, array_fill(0, count($inArr), &#39;?&#39;));
$types = str_repeat(&#39;i&#39;, count($inArr));
$types .= &#39;i&#39;; //add 1 more int type
$fullArr = array_merge($inArr, [26]); 
$stmt = $mysqli->prepare("SELECT id, name FROM myTable WHERE id IN ($clause) AND age > ?");
$stmt->bind_param($types, ...$fullArr); 
$stmt->execute();
$resArr = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
if(!$resArr) exit(&#39;No rows&#39;);
var_export($resArr);
$stmt->close();

交易

PDO

try {
  $pdo->beginTransaction();
  $stmt1 = $pdo->prepare("INSERT INTO myTable (name, state) VALUES (?, ?)");
  $stmt2 = $pdo->prepare("UPDATE myTable SET age = ? WHERE id = ?");
  if(!$stmt1->execute([&#39;Rick&#39;, &#39;NY&#39;])) throw new Exception(&#39;Stmt 1 Failed&#39;);
  else if(!$stmt2->execute([27, 139])) throw new Exception(&#39;Stmt 2 Failed&#39;);
  $stmt1 = null;
  $stmt2 = null;
  $pdo->commit();
} catch(Exception $e) {
  $pdo->rollback();
  throw $e;
}

MySQLi

try {
  $mysqli->autocommit(FALSE);
  $stmt1 = $mysqli->prepare("INSERT INTO myTable (name, age) VALUES (?, ?)");
  $stmt2 = $mysqli->prepare("UPDATE myTable SET name = ? WHERE id = ?");
  $stmt1->bind_param("si", $_POST[&#39;name&#39;], $_POST[&#39;age&#39;]);
  $stmt2->bind_param("si", $_POST[&#39;name&#39;], $_SESSION[&#39;id&#39;]);
  $stmt1->execute();
  $stmt2->execute();
  $stmt1->close();
  $stmt2->close();
  $mysqli->autocommit(TRUE);
} catch(Exception $e) {
  $mysqli->rollback(); 
  throw $e;
}

MySQLi有一个问题,但是解决方案是使用全局处理程序将错误转换为异常。

命名为Paramters

$stmt = $pdo->prepare("UPDATE myTable SET name = :name WHERE id = :id");
$stmt->execute([&#39;:name&#39; => &#39;David&#39;, &#39;:id&#39; => 3]);
$stmt = null;

相关推荐:《mysql教程》《PHP教程

위 내용은 PDO 대 MySQLi: PHP 데이터베이스 API의 전투의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.