Lưu mảng PHP vào MySQL?


88

Cách tốt để lưu một mảng dữ liệu vào một trường mysql duy nhất là gì?

Ngoài ra khi tôi truy vấn mảng đó trong bảng mysql, cách tốt để đưa nó trở lại dạng mảng là gì?

Serialize và unserialize có phải là câu trả lời?

Câu trả lời:


87

Không có cách nào tốt để lưu trữ một mảng vào một trường duy nhất.

Bạn cần kiểm tra dữ liệu quan hệ của mình và thực hiện các thay đổi thích hợp cho lược đồ của mình. Xem ví dụ dưới đây để tham khảo cách tiếp cận này.

Nếu bạn phải lưu mảng vào một trường duy nhất thì hàm serialize()unserialize()sẽ thực hiện thủ thuật. Nhưng bạn không thể thực hiện các truy vấn trên nội dung thực tế.

Để thay thế cho chức năng tuần tự hóa, còn có json_encode()json_decode().

Hãy xem xét mảng sau

$a = array(
    1 => array(
        'a' => 1,
        'b' => 2,
        'c' => 3
    ),
    2 => array(
        'a' => 1,
        'b' => 2,
        'c' => 3
    ),
);

Để lưu nó trong cơ sở dữ liệu, bạn cần tạo một bảng như thế này

$c = mysql_connect($server, $username, $password);
mysql_select_db('test');
$r = mysql_query(
    'DROP TABLE IF EXISTS test');
$r = mysql_query(
    'CREATE TABLE test (
      id INTEGER UNSIGNED NOT NULL,
      a INTEGER UNSIGNED NOT NULL,
      b INTEGER UNSIGNED NOT NULL,
      c INTEGER UNSIGNED NOT NULL,
      PRIMARY KEY (id)
    )');

Để làm việc với các bản ghi, bạn có thể thực hiện các truy vấn như sau (và vâng, đây là một ví dụ, hãy cẩn thận!)

function getTest() {
    $ret = array();
    $c = connect();
    $query = 'SELECT * FROM test';
    $r = mysql_query($query,$c);
    while ($o = mysql_fetch_array($r,MYSQL_ASSOC)) {
        $ret[array_shift($o)] = $o;
    }
    mysql_close($c);
    return $ret;
}
function putTest($t) {
    $c = connect();
    foreach ($t as $k => $v) {
        $query = "INSERT INTO test (id,".
                implode(',',array_keys($v)).
                ") VALUES ($k,".
                implode(',',$v).
            ")";
        $r = mysql_query($query,$c);
    }
    mysql_close($c);
}

putTest($a);
$b = getTest();

Các connect()hàm trả về một nguồn tài nguyên kết nối mysql

function connect() {
    $c = mysql_connect($server, $username, $password);
    mysql_select_db('test');
    return $c;
}

26

Nói chung, có, serialize và unserialize là cách để đi.

Tuy nhiên, nếu dữ liệu của bạn là một cái gì đó đơn giản, lưu dưới dạng một chuỗi được phân tách bằng dấu phẩy có lẽ sẽ tốt hơn cho không gian lưu trữ. Ví dụ: nếu bạn biết rằng mảng của bạn sẽ chỉ là một danh sách các số, thì bạn nên sử dụng implode / boom. Đó là sự khác biệt giữa 1,2,3a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}.

Nếu không, hãy tuần tự hóa và hủy số hóa công việc cho mọi trường hợp.


23
Vì bạn đang ở đây, độc giả, tôi chỉ sẽ dành thời gian để thông báo rằng tôi đã phát hiện ra, qua nhiều năm kinh nghiệm, rằng đây thực sự không phải là cách để đi. Câu trả lời được chấp nhận là một cách tiếp cận mạnh mẽ hơn nhiều.
Matchu

4
Sine bạn đang ở đây, độc giả Tôi sẽ chia sẻ với bạn rằng nó đơn giản phụ thuộc vào yêu cầu của bạn. Nếu bạn không cần truy vấn theo các giá trị mảng của mình và cần thứ gì đó rất NHANH CHÓNG, bạn có thể lưu trữ dữ liệu của mình một cách an toàn như thế này trong một trường duy nhất (đó là những gì câu hỏi đã nêu rõ), hãy gõ một khóa chính vào đó và bạn đi . Nếu bạn thắc mắc ứng dụng là gì: đẩy dữ liệu vào một hàng đợi nhận cron'd mỗi 5 phút. Một cron khác tạo mảng mất nhiều thời gian hơn. Hàng đợi tìm nạp dữ liệu được tính toán và chuyển nó đến API của bên thứ ba. Không có cách nào tốt hơn để làm điều đó.
Rid Iculous

1
@RidIculous Tôi đang bối rối, bạn đang nói về ứng dụng cá nhân của riêng bạn hay ứng dụng dẫn đến câu hỏi được đặt ra?
Peter Lindqvist

1
Trong khi điều đó không liên quan đến tiền đề của tuyên bố của tôi, tiền tố "Nếu bạn thắc mắc ứng dụng là gì" sẽ cung cấp sự rõ ràng.
Rid Iculous

10

Chỉ cần sử dụng hàm tuần tự hóa PHP:

<?php
$myArray = array('1', '2');
$seralizedArray = serialize($myArray);
?>

Tuy nhiên, nếu bạn đang sử dụng các mảng đơn giản như vậy, bạn cũng có thể sử dụng mã hóa và phát nổ, sử dụng một mảng trống thay vì mới.


9

Serialize / Unserialize mảng để lưu trữ trong DB

Truy cập http://php.net/manual/en/ Chức năng.serialize.php

Từ Hướng dẫn sử dụng PHP:

Xem phần "Quay lại" trên trang

Trả về một chuỗi chứa biểu diễn luồng byte của giá trị có thể được lưu trữ ở bất kỳ đâu.

Lưu ý rằng đây là một chuỗi nhị phân có thể bao gồm các byte rỗng và cần được lưu trữ và xử lý như vậy. Ví dụ: đầu ra serialize () thường phải được lưu trữ trong trường BLOB trong cơ sở dữ liệu, thay vì trường CHAR hoặc TEXT.

Lưu ý: Nếu bạn muốn lưu trữ html thành một blob, hãy đảm bảo mã hóa nó theo base64 nếu không nó có thể phá vỡ chức năng tuần tự hóa.

Mã hóa mẫu:

$YourSerializedData = base64_encode(serialize($theHTML));

$YourSerializedData hiện đã sẵn sàng để được lưu trữ trong blob.

Sau khi lấy dữ liệu từ blob, bạn cần base64_decode rồi hủy mã hóa Ví dụ giải mã:

$theHTML = unserialize(base64_decode($YourSerializedData));

8

Cách tốt nhất mà tôi tự tìm ra là lưu mảng dưới dạng chuỗi dữ liệu với các ký tự phân tách

$array = array("value1", "value2", "value3", "...", "valuen");
$array_data = implode("array_separator", $array);

$query = "INSERT INTO my_tbl_name (id, array_data) VALUES(NULL,'" . $array_data . "');";

Sau đó, bạn có thể tìm kiếm dữ liệu, được lưu trữ trong mảng của mình bằng truy vấn đơn giản

$query = "SELECT * FROM my_tbl_name WHERE array_data LIKE '%value3%'";

sử dụng hàm boom () để chuyển đổi chuỗi "array_data" thành mảng

$array = explode("array_separator", $array_data);

lưu ý rằng điều này không hoạt động với mảng nhiều chiều và đảm bảo rằng "dấu_mảng_mảng" của bạn là duy nhất và không tồn tại trong các giá trị mảng.

Hãy cẩn thận !!! nếu bạn chỉ lấy một dữ liệu biểu mẫu và đưa vào cơ sở dữ liệu, bạn sẽ mắc bẫy, dữ liệu biểu mẫu không an toàn với SQL! bạn phải xử lý giá trị biểu mẫu của mình với mysql_real_escape_string hoặc nếu bạn sử dụng MySQLi mysqli :: real_escape_string hoặc nếu giá trị là số nguyên hoặc kiểu ép kiểu boolean (int) (boolean) trên chúng

$number = (int)$_POST['number'];
$checked = (boolean) $_POST['checked'];

$name = mysql_real_escape_string($db_pt, $_POST['name']);
$email = mysqli_obj->real_escape_string($_POST['email']);

Trong trường hợp của tôi, tôi đoán đây là lựa chọn tốt nhất cho tôi.
Imtiaz

6

Serialize và unserialize là khá phổ biến cho điều đó. Bạn cũng có thể sử dụng JSON thông qua json_encode và json_decode cho một định dạng ít dành riêng cho PHP.


5

Như đã đề cập trước đây - Nếu bạn không cần tìm kiếm dữ liệu trong mảng, bạn có thể sử dụng serialize - nhưng đây là "chỉ php". Vì vậy, tôi khuyên bạn nên sử dụng json_decode / json_encode - không chỉ cho hiệu suất mà còn cho khả năng đọc và tính di động (các ngôn ngữ khác như javascript có thể xử lý dữ liệu json_encoded).


3

Uhh, tôi không biết tại sao mọi người đề xuất tuần tự hóa mảng.

Tôi nói, cách tốt nhất là thực sự đưa nó vào lược đồ cơ sở dữ liệu của bạn. Tôi không biết (và bạn không có manh mối nào) về ý nghĩa ngữ nghĩa thực tế của dữ liệu trong mảng của bạn, nhưng nói chung có hai cách lưu trữ chuỗi như vậy

create table mydata (
  id int not null auto_increment primary key,
  field1 int not null,
  field2 int not null,
  ...
  fieldN int not null
)

Bằng cách này, bạn đang lưu trữ mảng của mình trong một hàng duy nhất.

create table mydata (
    id int not null auto_increment primary key,
    ...
)

create table myotherdata (
    id int not null auto_increment primary key,
    mydata_id int not null,
    sequence int not null,
    data int not null
)

Nhược điểm của phương pháp đầu tiên rõ ràng là nếu bạn có nhiều mục trong mảng của mình, làm việc với bảng đó sẽ không phải là điều tốt nhất. Nó cũng không thực tế (có thể, nhưng cũng không phù hợp - chỉ làm cho các cột có giá trị rỗng) khi làm việc với các chuỗi có độ dài thay đổi.

Đối với phương pháp thứ hai, bạn có thể có các chuỗi có độ dài bất kỳ, nhưng chỉ có một loại. Tất nhiên, bạn có thể tạo một kiểu varchar hoặc một cái gì đó và tuần tự hóa các mục trong mảng của bạn. Không phải là điều tốt nhất để làm, nhưng chắc chắn tốt hơn, so với việc tuần tự hóa toàn bộ mảng, phải không?

Dù bằng cách nào, bất kỳ phương pháp nào trong số này đều có lợi thế rõ ràng là có thể truy cập vào một phần tử tùy ý của chuỗi và bạn không phải lo lắng về việc sắp xếp các mảng và những thứ xấu xí như vậy.

Đối với việc lấy lại nó. Chà, lấy hàng / chuỗi hàng thích hợp với một truy vấn và, tốt, sử dụng một vòng lặp .. phải không?


Đôi khi một mảng thực sự là thích hợp. Nếu bạn chỉ truy cập nó như một thuộc tính của đối tượng đầu tiên, thì điều đó có ý nghĩa.
Matchu

1
Tôi phải không đồng ý ở những điều khoản nghiêm trọng nhất - có vẻ như không thích hợp để tôi lưu trữ ngẫu nhiên, không có cấu trúc ("mảng" php thực sự không phải là mảng, đúng không?), Các đốm dữ liệu không định kiểu trong cơ sở dữ liệu quan hệ . Dù sao thì bạn cũng sẽ sử dụng dấu phân tách là gì, nếu mảng của bạn có thể có bất kỳ chuỗi nào trong đó? Đây chỉ là yêu cầu rắc rối theo nhiều cách khác nhau. Trong 99,9% trường hợp, có một cách khác, tự nhiên hơn. Tôi sẽ đưa ra một phỏng đoán hoang đường ở đây và gợi ý rằng trường hợp của người hỏi không rơi vào 0,1% còn lại.
shylent

2
Trên thực tế, đôi khi rất thích hợp để lưu trữ một mảng trong một trường trong DB. Ví dụ sẽ là siêu dữ liệu như bảng 'biến' toàn cầu, trong đó plugin và mô-đun hệ thống có thể lưu trữ các cài đặt đã phân loại của chúng. một bảng lưu trữ dữ liệu 'phiên' tùy ý có thể được triển khai tốt nhất bằng cách sử dụng trường chứa một mảng khóa / giá trị liên kết. serialize và unserialize (đó là câu trả lời chính xác) chăm sóc các dấu phân cách. kiểm tra một số của một số dự án mã nguồn mở thành công & phổ biến, như WordPress hay Drupal - và bạn sẽ thấy các mảng mà đôi khi được lưu trữ trong DB như thế này
Scott Evernden

@Scott Evernden: Rốt cuộc thì tôi đoán là bạn đúng. php không phải là ngôn ngữ "chính" của tôi, vì vậy tôi đã đánh giá giải pháp từ quan điểm thiết kế cơ sở dữ liệu. Nếu những gì bạn mô tả thực sự là cách phổ biến để làm những việc như vậy (trong php), thì hãy cứ như vậy. Không làm cho tôi thích nó mặc dù :)
shylent

5
KHÔNG BAO GIỜ thích hợp để lưu trữ một mảng trong một trường trong DB. Đó là sự vi phạm không thuộc dạng bình thường thứ tư, dạng bình thường thứ ba hoặc thậm chí dạng bình thường thứ hai: đó là sự vi phạm của dạng bình thường thứ nhất. Nếu bạn không thể tuân thủ ngay cả với biểu mẫu bình thường đầu tiên, có điều gì đó sai nghiêm trọng với đơn đăng ký của bạn. Điều đó đúng với Drupal và Wordpress; nếu họ làm điều này thì chắc chắn không phải vì khía cạnh ứng dụng của họ được thiết kế tốt .. Tôi đã lập luận như vậy trong công việc cuối cùng của mình, và bởi vì XCart đã làm điều vô nghĩa nên nó đã tạo ra một thứ mà lẽ ra có thể, thay vào đó là cực kỳ khó khăn.
Dexygen

2

Bạn có thể lưu mảng của mình dưới dạng json.
có tài liệu về kiểu dữ liệu json: https://dev.mysql.com/doc/refman/5.7/vi/json.html
Tôi nghĩ đây là giải pháp tốt nhất và sẽ giúp bạn duy trì mã của mình dễ đọc hơn bằng cách tránh các hàm điên rồ .
Tôi hy vọng điều này sẽ hữu ích cho bạn.


0

Đúng vậy, serialize / unserialize là điều tôi thấy nhiều nhất trong nhiều dự án mã nguồn mở.


0

Tôi sẽ đề xuất sử dụng implode / boom với một ký tự mà bạn biết sẽ không có trong bất kỳ mục mảng riêng lẻ nào. Sau đó, lưu trữ nó trong SQL dưới dạng một chuỗi.


3
Câu hỏi này đã được hỏi 3 năm trước và có một câu trả lời được chấp nhận. Bạn có thể thấy hữu ích hơn khi trả lời các câu hỏi mới hơn hoặc các câu hỏi không có câu trả lời.
MDrollette

0

hãy kiểm tra hàm implode, vì các giá trị nằm trong một mảng, bạn muốn đặt các giá trị của mảng vào một truy vấn mysql chèn các giá trị vào một bảng.

$query = "INSERT INto hardware (specifications) VALUES (".implode(",",$specifications).")";

Nếu các giá trị trong mảng là giá trị văn bản, bạn sẽ cần thêm dấu ngoặc kép

$query = "INSERT INto hardware (specifications) VALUES ("'.implode("','",$specifications)."')";

mysql_query($query);

Ngoài ra, nếu bạn không muốn các giá trị trùng lặp, hãy chuyển "INto" thành "BỎ QUA" và chỉ các giá trị duy nhất mới được chèn vào bảng.


Nếu bạn có khóa chính, bạn sẽ không nhận được bản sao với CHÈN VÀO. Nếu bạn không có khóa chính hoặc chỉ mục, việc BỎ QUA không tạo ra bất kỳ sự khác biệt nào.
Peter Lindqvist

0

bạn có thể chèn đối tượng tuần tự hóa (mảng) vào mysql, ví dụ serialize($object)và bạn có thể hủy mã hóa ví dụ đối tượngunserialize($object)


-5

Thay vì lưu nó vào cơ sở dữ liệu, hãy lưu nó vào một tệp và sau đó gọi nó sau.

Những gì nhiều ứng dụng php làm (như sugarcrm) là chỉ sử dụng var_export để lặp lại tất cả dữ liệu của mảng vào một tệp. Đây là những gì tôi sử dụng để lưu dữ liệu cấu hình của mình:

private function saveConfig() {
    file_put_contents($this->_data['pathtocompileddata'],'<?php' . PHP_EOL . '$acs_confdata = ' . var_export($this->_data,true) . ';');        
}

Tôi nghĩ đây là cách tốt hơn để lưu dữ liệu của bạn!


Đó là một cách khác, không nhất thiết phải tốt hơn.
Peter Lindqvist

Thật. Tôi chỉ nghĩ rằng truy cập tệp dễ dàng hơn nhiều so với truy vấn cơ sở dữ liệu để lấy dữ liệu mảng và sau đó khởi tạo mảng. Bằng cách này, bạn chỉ cần đưa tệp vào là xong.
AntonioCS
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.