Зберегти PHP-масив у MySQL?


88

Який хороший спосіб зберегти масив даних в одному полі MySQL?

Також коли я запитую цей масив у таблиці mysql, який хороший спосіб повернути його у форму масиву?

Чи серіалізувати та несеріалізувати відповідь?

Відповіді:


87

Немає хорошого способу зберігати масив в одному полі.

Вам потрібно вивчити ваші реляційні дані та внести відповідні зміни у вашу схему. Див. Приклад нижче для посилання на цей підхід.

Якщо вам потрібно зберегти масив в одному полі, тоді функції serialize()and unserialize()зроблять трюк. Але ви не можете виконувати запити щодо фактичного вмісту.

Як альтернатива функції серіалізації є також json_encode()і json_decode().

Розглянемо наступний масив

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

Щоб зберегти його в базі даних, потрібно створити таку таблицю

$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)
    )');

Для роботи із записами ви можете виконувати такі запити (і так, це приклад, будьте обережні!)

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();

connect()Функція повертає ресурс з'єднання MySQL

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

26

Як правило, так, серіалізація та несеріалізація - це шлях.

Якщо ваші дані щось просте, збереження у вигляді рядка, розділеного комами, можливо, було б кращим для місця для зберігання. Якщо ви знаєте, що ваш масив буде просто списком чисел, наприклад, тоді вам слід використовувати implode / explode. Це різниця між 1,2,3і a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}.

Якщо ні, то серіалізуйте та десеріалізуйте роботу для всіх випадків.


23
Оскільки ти тут, читачу, я просто знайду час, щоб повідомити, що з тих пір, завдяки багаторічному досвіду, виявив, що це насправді не такий шлях. Прийнята відповідь - набагато сильніший підхід.
Matchu

4
Звичайно, ти тут, читачу, я поділюсь з тобою, що це просто залежить від твоїх вимог. Якщо вам не потрібно запитувати значення ваших масивів і вам потрібно щось дуже ШВИДЕ, ви можете безпечно зберігати свої дані, як це, в одному полі (що чітко сформульовано у питанні), ляпніть по ньому первинним ключем, і ви йдете . Якщо вам цікаво, що це за програма: введення даних у que, який отримує cron'd кожні 5 хвилин. Інший cron створює масиви, що займає набагато більше часу. Que отримує обчислені дані та передає їх стороннім API. Немає кращого способу зробити це.
Rid Iculous

1
@RidIculous Я розгублений, ти говориш про власну особисту заявку чи програму, яка призвела до того, що було задано питання?
Пітер Ліндквіст

1
Хоча це не має значення для передумови мого висловлювання, префікс "Якщо вам цікаво, що це за програма" повинен надати ясність.
Rid Iculous

10

Просто використовуйте функцію серіалізації PHP:

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

Однак, якщо ви використовуєте прості масиви, подібні до цього, ви також можете використовувати implode і explode. Використовуйте порожній масив замість нового.


9

Серіалізувати / десеріалізувати масив для зберігання в БД

Відвідайте http://php.net/manual/en/function.serialize.php

З Посібника PHP:

Подивіться на "Повернення" на сторінці

Повертає рядок, що містить подання байтового потоку значення, яке можна зберігати де завгодно.

Зверніть увагу, що це двійковий рядок, який може містити нульові байти, і його потрібно зберігати та обробляти як такий. Наприклад, вихід serialize () зазвичай повинен зберігатися в полі BLOB у базі даних, а не в полі CHAR або TEXT.

Примітка: Якщо ви хочете зберегти html в BLOB-пам’яті, переконайтеся, що кодуєте base64, інакше це може порушити функцію серіалізації.

Приклад кодування:

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

$YourSerializedData тепер готовий до зберігання в BLOB.

Після отримання даних з BLOB вам потрібно base64_decode, а потім десеріалізувати Приклад декодування:

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

8

Найкращий спосіб, який я знайшов для себе, - це зберегти масив як рядок даних із символами-роздільниками

$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 . "');";

Потім ви можете шукати дані, що зберігаються у вашому масиві, за допомогою простих запитів

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

використовуйте функцію explode () для перетворення рядка "array_data" в масив

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

зауважте, що це не працює з багатовимірними масивами, і переконайтесь, що ваш "array_separator" унікальний і не існував у значеннях масиву.

Будь обережний !!! якщо ви просто візьмете дані форми та помістите їх у базу даних, ви потрапите в пастку, оскільки дані форми не є безпечними для SQL! ви повинні обробляти значення форми за допомогою mysql_real_escape_string, або якщо ви використовуєте MySQLi mysqli :: real_escape_string, або якщо значення є цілим чи логічним приведенням (int) (boolean) до них

$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']);

У моєму випадку, я думаю, це найкращий варіант для мене.
Імтіаз,

6

Серіалізація та несеріалізація досить поширені для цього. Ви також можете використовувати JSON через json_encode та json_decode для менш специфічного для PHP формату.


5

Як вже згадувалося раніше - якщо вам не потрібно шукати дані в масиві, ви можете використовувати серіалізацію - але це "лише php". Тому я б рекомендував використовувати json_decode / json_encode - не тільки для підвищення продуктивності, а й для читабельності та переносимості (інші мови, такі як javascript, можуть обробляти json_encoded дані).


3

Е-е, я не знаю, чому всі пропонують серіалізувати масив.

Я кажу, найкращий спосіб - це насправді вписати його у свою схему бази даних. Я поняття не маю (і ви не дали підказки) про фактичне семантичне значення даних у вашому масиві, але, як правило, існує два способи зберігання таких послідовностей

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

Таким чином ви зберігаєте свій масив в одному рядку.

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
)

Недоліком першого методу є, очевидно, те, що якщо у вас є багато елементів у вашому масиві, робота з цією таблицею буде не найелегантнішою річчю. Також непрактично (можливо, але також досить неелегантно - просто зробіть стовпчики нульовими) працювати з послідовностями змінної довжини.

Для другого методу ви можете мати послідовності будь-якої довжини, але лише одного типу. Ви, звичайно, можете зробити такий тип varchar або щось інше і серіалізувати елементи вашого масиву. Не найкраще, що можна зробити, але, звичайно, краще, ніж серіалізація цілого масиву, так?

У будь-якому випадку, будь-який із цих методів отримує очевидну перевагу у тому, що він може отримати доступ до довільного елемента послідовності, і вам не доведеться турбуватися про серіалізацію масивів та подібних потворних речей.

Що стосується повернення. Ну, отримайте відповідний рядок / послідовність рядків із запитом і, ну, використовуйте цикл .. так?


Іноді масив дійсно доречний. Якщо ви збираєтеся отримати до нього доступ лише як атрибут першого об’єкта, то це має сенс.
Matchu

1
Мені доводиться не погоджуватися в найсуворіших термінах - мені здається досить недоречним зберігати випадкові, неструктуровані (php "масиви" насправді взагалі не є масивами, так?), Нетипізовані краплі даних у реляційній базі даних . Що ви все одно будете використовувати для роздільника, якщо у вашому масиві можуть бути будь-які рядки? Це просто прохання про неприємності різними способами. У 99,9% випадків існує інший, більш природний спосіб. Тут я здивовано припущу і припущу, що справа допитувача не потрапляє до решти 0,1%.
shylent

2
Насправді, іноді дуже доречно зберігати масив у полі в БД. Прикладом можуть бути метадані, як глобальна таблиця "змінних", до якої системні модулі та модулі можуть зберігати свої різні параметри. таблицю, яка зберігає довільні дані "сеансу", найкраще реалізувати за допомогою поля, що містить асоціативний масив ключів / значень. серіалізувати та десеріалізувати (що є правильною відповіддю) подбати про сепаратори. перевірте деякі з декількох успішних і популярних проектів з відкритим кодом, таких як WordPress чи Drupal - і ви побачите, що масиви іноді зберігаються в БД так
Скотт Еверден

@ Скотт Евернден: Я думаю, ви все-таки маєте рацію. php не є моєю "основною" мовою, тому я судив про рішення з точки зору проектування бази даних. Якщо те, що ви описуєте, насправді є загальним способом робити такі речі (у php), то нехай буде так. Хоча мені це не подобається :)
shylent

5
НІКОЛИ не доцільно зберігати масив у полі БД. Це порушення не четвертої нормальної форми, третьої нормальної форми або навіть другої нормальної форми: це ПОРУШЕННЯ ПЕРШОЇ НОРМАЛЬНОЇ ФОРМИ. Якщо ви не можете дотримуватися навіть першої звичайної форми, із вашою заявкою щось серйозно не так. Це стосується Drupal та Wordpress; якщо вони це роблять, це, безумовно, не тому, що ця грань їх програм добре розроблена .. Я мав цей аргумент на минулій роботі, і оскільки XCart робив цю нісенітницю, це зробило щось, що мало б бути можливим, натомість надзвичайно складним.
Кисень

2

Ви можете зберегти свій масив як json.
є документація щодо типу даних json: https://dev.mysql.com/doc/refman/5.7/en/json.html
Я думаю, що це найкраще рішення, і допоможе вам зберегти ваш код більш читабельним, уникаючи шалених функцій .
Я сподіваюся, це корисно для вас.


0

Так, серіалізація / несеріалізація - це те, що я найбільше бачив у багатьох проектах з відкритим кодом.


0

Я б запропонував використовувати implode / explode із символом, який, як ви знаєте, не буде міститися в жодному з окремих елементів масиву. Потім збережіть його в SQL як рядок.


3
Це питання було задано 3 роки тому і має прийняту відповідь. Можливо, вам буде корисніше відповідати на нові запитання чи запитання без відповіді.
MDrollette

0

перевірте функцію implode, оскільки значення знаходяться в масиві, ви хочете помістити значення масиву в запит mysql, який вставляє значення в таблицю.

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

Якщо значення в масиві є текстовими, вам потрібно буде додати лапки

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

mysql_query($query);

Крім того, якщо ви не хочете повторюваних значень, переключіть "INto" на "IGNORE", і в таблицю будуть вставлені лише унікальні значення.


Якщо у вас є первинний ключ, ви все одно не отримаєте дублікатів з INSERT INTO. Якщо у вас немає первинного ключа або індексу, IGNORE не робить ніякої різниці.
Пітер Ліндквіст,

0

ви можете вставити серіалізований об'єкт (масив) у mysql, наприклад, serialize($object)і ви можете скасувати серіалізацію прикладу об'єктаunserialize($object)


-5

Замість того, щоб зберігати його в базі даних, збережіть його у файл, а потім зателефонуйте пізніше.

Багато програм php (наприклад, sugarcrm) - це просто використовувати var_export для ехо-передавання всіх даних масиву у файл. Це те, що я використовую для збереження даних своїх конфігурацій:

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

Я думаю, що це кращий спосіб зберегти ваші дані!


Це інший спосіб, не обов’язково кращий.
Пітер Ліндквіст,

Справді. Я просто думаю, що доступ до файлу набагато простіший, ніж запит до бази даних для отримання даних масиву, а потім ініціалізації масиву. Таким чином, ви просто додаєте файл і все готово.
AntonioCS
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.