Chủ Nhật, 7 tháng 9, 2014

Một số vấn đề khi truy xuất dữ liệu trực tiếp trong MySql từ PHP

Trong thiết kế lập trình web với PHP và MySql việc thiết kế cơ sở dữ liệu là một việc hết sức quan trọng. Nhưng đôi các bạn thường gặp phải một số vấn đề khi truy xuất dữ liệu. Sau đây là một số cách truy cập cơ sở dữ liệu trong mã PHP và cách sửa chữa những lỗi phát sinh trong quá trình truy xuất dữ liệu sử dụng MySQL trực tiếp
Khi sử dùng các hàm mysql_ để truy cập trực tiếp vào cơ sở dữ liệu có một vấn đề phổ biến là mã PHP đã cũ. Cách truy cập trực tiếp vào cơ sở dữ liệu.
Access/get.php
<?php
function get_user_id( $name )
{
  $db = mysql_connect( 'localhost', 'root', 'password' );
  mysql_select_db( 'users' );
  $res = mysql_query( "SELECT id FROM users WHERE login='".$name."'" );
  while( $row = mysql_fetch_array( $res ) ) { $id = $row[0]; }
  return $id;
}
var_dump( get_user_id( 'jack' ) );
?>
Hãy lưu ý việc sử dụng hàm mysql_connect để truy cập vào cơ sở dữ liệu. Cũng chú ý truy vấn trong đó có dùng sự liên kết chuỗi để bổ sung tham số $name vào truy vấn đó.
Kỹ thuật này có hai sự lựa chọn tốt: mô đun PEAR DB và các lớp PHP Data Objects (PDO-Các đối tượng dữ liệu PHP). Cả hai đều cung cấp sự trừu tượng từ việc lựa chọn của một cơ sở dữ liệu cụ thể. Do đó, mã của bạn có thể chạy mà không cần điều chỉnh quá nhiều trên IBM® DB2®, MySQL, PostgreSQL, hoặc cơ sở dữ liệu khác bất kỳ mà bạn muốn kết nối đến.
Các giá trị khác trong việc sử dụng các tầng trừu tượng của mô đun PEAR DB và PDO là bạn có thể sử dụng toán tử ? trong các câu lệnh SQL của bạn. Việc này làm cho SQL dễ dàng bảo trì hơn và bảo vệ ứng dụng của bạn khỏi các cuộc tấn công nội xạ SQL.
Mã thay thế khi sử dụng PEAR DB được hiển thị dưới đây.
Access/get_good.php
<?php
require_once("DB.php");
function get_user_id( $name )
{
  $dsn = 'mysql://root:password@localhost/users';
  $db =& DB::Connect( $dsn, array() );
  if (PEAR::isError($db)) { die($db->getMessage()); }
  $res = $db->query( 'SELECT id FROM users WHERE login=?',
  array( $name ) );
  $id = null;
  while( $res->fetchInto( $row ) ) { $id = $row[0]; }
  return $id;
}
var_dump( get_user_id( 'jack' ) );
?>
Chú ý rằng tất cả các đề cập trực tiếp của MySQL đã diễn ra, trừ chuỗi kết nối cơ sở dữ liệu trong $dsn. Ngoài ra, chúng ta sử dụng biến $name trong SQL thông qua toán tử ?. Sau đó, dữ liệu với truy vấn này được gửi đi thông qua array ở cuối phương thức query().
Không sử dụng chức năng tăng tự động
Giống như hầu hết các cơ sở dữ liệu hiện đại, MySQL có khả năng tạo các trình nhận dạng (identifier) duy nhất tăng tự động trên một cơ sở cho mỗi bản ghi. Mặc dù vậy, chúng ta vẫn thấy mã lần đầu tiên chạy một lệnh SELECT để tìm mã nhận dạng (id) tối đa, sau đó bổ sung thêm một vào id đó, cũng như một bản ghi mới. Phần mã code sau cho thấy một lược đồ mẫu bad (xấu).
 Badid.sql
DROP TABLE IF EXISTS users;
CREATE TABLE users (
  id MEDIUMINT,
  login TEXT,
  password TEXT
);
INSERT INTO users VALUES ( 1, 'jack', 'pass' );
INSERT INTO users VALUES ( 2, 'joan', 'pass' );
INSERT INTO users VALUES ( 1, 'jane', 'pass' );
Trường id ở đây được quy định đơn giản là một số nguyên. Vì vậy, mặc dù nó sẽ là duy nhất, chúng ta có thể thêm vào bất kỳ giá trị nào mà chúng ta muốn, như đã chỉ ra trong câu lệnh INSERT tiếp theo câu lệnh CREATE. Mã PHP bổ sung thêm users (những người sử dụng) vào kiểu lược đồ này.
Mã thêm users: Add_user.php
<?php
require_once("DB.php");
function add_user( $name, $pass )
{
  $rows = array();
  $dsn = 'mysql://root:password@localhost/bad_badid';
  $db =& DB::Connect( $dsn, array() );
  if (PEAR::isError($db)) { die($db->getMessage()); }
  $res = $db->query( "SELECT max(id) FROM users" );
  $id = null;
  while( $res->fetchInto( $row ) ) { $id = $row[0]; }
  $id += 1;
  $sth = $db->prepare( "INSERT INTO users VALUES(?,?,?)" );
  $db->execute( $sth, array( $id, $name, $pass ) );
  return $id;
}
$id = add_user( 'jerry', 'pass' );
var_dump( $id );
?>
Mã trong add_user.php đầu tiên thực hiện một truy vấn để tìm ra giá trị tối đa của id. Sau đó tệp này chạy một câu lệnh INSERT với giá trị id cộng thêm một. Mã này có thể không chạy thành công trong các điều kiện ganh đua (race) trên các máy chủ có một tải nặng. Hơn nữa, nó không hiệu quả.
Vì vậy, sự thay thế là gì? Sử dụng tính năng tăng tự động trong MySQL để tạo các ID duy nhất cho mỗi lần chèn tự động. Lược đồ cập nhật được hiển thị bên dưới như sau:
Goodid.php
DROP TABLE IF EXISTS users;
CREATE TABLE users (
  id MEDIUMINT NOT NULL AUTO_INCREMENT,
  login TEXT NOT NULL,
  password TEXT NOT NULL,
  PRIMARY KEY( id )
);
INSERT INTO users VALUES ( null, 'jack', 'pass' );
INSERT INTO users VALUES ( null, 'joan', 'pass' );
INSERT INTO users VALUES ( null, 'jane', 'pass' );
Chúng ta thêm cờ NOT NULL để chỉ ra rằng các trường này không rỗng (null). Chúng ta cũng đã bổ sung cờ AUTO_INCREMENT để chỉ thị rằng trường này tăng tự động, cũng như cờ PRIMARY KEY để chỉ thị trường nào là id. Những thay đổi này cho phép tăng một chút tốc độ. Liệt kê 6 cho thấy mã PHP đã cập nhật, mã này chèn users (những người dùng) vào bảng.
Add_user_good.php
<?php
require_once("DB.php");

function add_user( $name, $pass )
{
  $dsn = 'mysql://root:password@localhost/good_genid';
  $db =& DB::Connect( $dsn, array() );
  if (PEAR::isError($db)) { die($db->getMessage()); }
  $sth = $db->prepare( "INSERT INTO users VALUES(null,?,?)" );
  $db->execute( $sth, array( $name, $pass ) );
  $res = $db->query( "SELECT last_insert_id()" );
  $id = null;
  while( $res->fetchInto( $row ) ) { $id = $row[0]; }
  return $id;
}
$id = add_user( 'jerry', 'pass' );
var_dump( $id );
?>
Thay vì nhận được giá trị id tối đa, tôi bây giờ chỉ cần sử dụng câu lệnh INSERT để chèn dữ liệu, sau đó sử dụng một câu lệnh SELECT để lấy id của bản ghi vừa mới được chèn vào. Mã này đơn giản hơn nhiều và hiệu quả hơn so với phiên bản gốc và lược đồ liên quan của nó.
Một lựa chọn khác đối với chức năng tăng tự động của MySQL là sử dụng phương thức nextId() trong hệ thống PEAR DB. Trong trường hợp của MySQL, điều này tạo ra một bảng tuần tự mới và quản lý việc sử dụng một cơ chế khóa phức tạp. Lợi thế của việc sử dụng phương thức này là nó sẽ hoạt động trên các hệ thống cơ sở dữ liệu khác.

Dù bằng cách nào, bạn nên sử dụng một hệ thống quản lý sự tăng các ID duy nhất cho bạn và không dựa vào hệ thống mà bạn truy vấn đầu tiên, sau đó tăng giá trị của chính bạn và thêm bản ghi. Cách tiếp cận thứ hai dễ bị ảnh hưởng theo các điều kiện ganh đua trên các trang có khối lượng cao.

Không có nhận xét nào:

Đăng nhận xét