将PHP数组保存到MySQL吗?


88

什么是将数据数组保存到单个mysql字段的好方法?

另外,一旦我在mysql表中查询该数组,有什么好方法可以将其恢复为数组形式?

是序列化和反序列化答案吗?

Answers:


87

没有好的方法可以将数组存储到单个字段中。

您需要检查您的关系数据并对模式进行适当的更改。请参阅下面的示例以获取对此方法的参考。

如果必须将数组保存到单个字段中,则serialize()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

通常,是的,序列化和反序列化是可行的方法。

但是,如果您的数据很简单,则另存为逗号分隔的字符串可能会更好地存储空间。例如,如果您知道数组只是数字列表,则应使用爆破/爆炸。1,2,3和之间的区别a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}

如果不是,则在所有情况下都对工作进行序列化和反序列化。


23
既然您在这里,读者,我将花些时间宣布,从多年的经验中我已经发现,这确实不是解决之道。公认的答案是一种更强大的方法。
Matchu

4
既然您在这里,读者我将与您分享这完全取决于您的要求。如果您不需要查询数组值并且需要非常快速的操作,则可以将这样的数据安全地存储在单个字段中(这是问题明确指出的内容),然后在上面敲一个主键就可以了。如果您想知道应用程序是什么:每5分钟将数据推送到que中。另一个cron创建数组需要花费更多时间。que提取计算的数据并将其传递给第三方API。没有更好的方法。
Rid Iculous

1
@RidIculous我很困惑,您是在谈论自己的个人应用程序还是导致提出问题的应用程序?
彼得·林德奎斯特

1
尽管这与我的陈述的前提无关,但前缀“如果您想知道应用程序是什么”应该可以清楚说明。
Rid Iculous

10

只需使用序列化PHP函数:

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

但是,如果您使用类似的简单数组,则不妨使用爆破和爆炸。使用空白数组代替new数组。


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

就我而言,这是我的最佳选择。
Imtiaz 2014年

6

序列化和反序列化对此非常普遍。您还可以通过json_encode和json_decode使用JSON,以减少特定于PHP的格式。



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-

@斯科特·埃弗顿(Scott Evernden):我想你毕竟是对的。php不是我的“主要”语言,因此我从数据库设计的角度来判断解决方案。如果您所描述的确实是执行此类操作的常用方法(在php中),那就这样吧。虽然没有让我喜欢它:)
shylent

5
将数组存储在DB的字段中永远是不合适的。它违反了第四范式,第三范式甚至第二范式:这是对第一范式的违反。如果您甚至不能遵守第一个标准格式,则您的应用程序存在严重问题。这适用于Drupal和Wordpress;如果他们这样做,那肯定不是因为他们的应用程序的方面设计得很好。.我在上一份工作中有这个论点,并且因为XCart这样做是胡说八道,所以使本来应该做的事情变得非常困难。
Dexygen


0

是的,序列化/反序列化是我在许多开源项目中看到最多的内容。


0

我建议对您知道不会在任何单个数组项中包含的字符使用爆破/爆炸。然后将其作为字符串存储在SQL中。


3
这个问题是3年前提出的,已经被接受。您可能会发现回答较新的问题或没有答案的问题会更有用。
MDrollette 2012年

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不会有任何区别。
彼得·林德奎斯特


-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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.