简体   繁体   English

MySQL忽略了NOT NULL约束

[英]MySQL ignores the NOT NULL constraint

I have created a table with NOT NULL constraints on some columns in MySQL. 我在MySQL的一些列上创建了一个带有NOT NULL约束的表。 Then in PHP I wrote a script to insert data, with an insert query. 然后在PHP中我编写了一个插入数据的脚本,带有插入查询。 When I omit one of the NOT NULL columns in this insert statement I would expect an error message from MySQL, and I would expect my script to fail. 当我省略这个insert语句中的一个NOT NULL列时,我会期望来自MySQL的错误消息,我希望我的脚本失败。 Instead, MySQL inserts empty strings in the NOT NULL fields. 相反,MySQL在NOT NULL字段中插入空字符串。 In other omitted fields the data is NULL, which is fine. 在其他省略的字段中,数据为NULL,这很好。 Could someone tell me what I did wrong here? 有人能告诉我这里做错了吗?

I'm using this table: 我正在使用这张桌子:

CREATE TABLE IF NOT EXISTS tblCustomers (
  cust_id int(11) NOT NULL AUTO_INCREMENT,
  custname varchar(50) NOT NULL,
  company varchar(50),
  phone varchar(50),
  email varchar(50) NOT NULL,
  country varchar(50) NOT NULL,
  ...
  date_added timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (cust_id)
) ;

And this insert statement: 这个插入声明:

$sql = "INSERT INTO tblCustomers (custname,company) 
        VALUES ('".$customerName."','".$_POST["CustomerCompany"]."')";
$res = mysqli_query($mysqli, $sql);

Or using bind variables: 或者使用绑定变量:

$stmt = mysqli_prepare($mysqli, "INSERT INTO tblCustomers (custname,company, email, country) VALUES (?, ?, ?, ?)");

mysqli_stmt_bind_param($stmt, 'ssss', $customerName, $_POST["CustomerCompany"], $_POST["CustomerEmail"], $_POST["AddressCountry"]);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);

If you're sure you're not using explicit default values, then check your strict mode: 如果您确定没有使用显式默认值,请检查严格模式:

SELECT @@GLOBAL.sql_mode;
SELECT @@SESSION.sql_mode;

MySQL Data Type Default Values MySQL数据类型默认值

As of MySQL 5.0.2, if a column definition includes no explicit DEFAULT value, MySQL determines the default value as follows: 从MySQL 5.0.2开始,如果列定义不包含显式DEFAULT值,MySQL将确定默认值,如下所示:

If the column can take NULL as a value, the column is defined with an explicit DEFAULT NULL clause. 如果列可以将NULL作为值,则使用显式DEFAULT NULL子句定义该列。 This is the same as before 5.0.2. 这与5.0.2之前相同。

If the column cannot take NULL as the value, MySQL defines the column with no explicit DEFAULT clause. 如果列不能将NULL作为值,则MySQL定义没有显式DEFAULT子句的列。 For data entry, if an INSERT or REPLACE statement includes no value for the column, or an UPDATE statement sets the column to NULL, MySQL handles the column according to the SQL mode in effect at the time: 对于数据输入,如果INSERT或REPLACE语句不包含该列的值,或者UPDATE语句将列设置为NULL,则MySQL将根据当时生效的SQL模式处理该列:

  • If strict SQL mode is not enabled, MySQL sets the column to the implicit default value for the column data type. 如果未启用严格的SQL模式,MySQL会将列设置为列数据类型的隐式默认值。

  • If strict mode is enabled, an error occurs for transactional tables and the statement is rolled back. 如果启用了严格模式,则事务表会发生错误,并且会回滚该语句。 For nontransactional tables, an error occurs, but if this happens for the second or subsequent row of a multiple-row statement, the preceding rows will have been inserted. 对于非事务性表,会发生错误,但如果多行语句的第二行或后续行发生这种情况,则会插入前面的行。

Server SQL Modes 服务器SQL模式

What you are doing wrong is building your query using strings instead of using bind parameters. 你做错了是使用字符串而不是使用绑定参数来构建查询。

Aside from the SQL injection vulnerability, the null values are being converted to empty strings even before the database sees them. 除了SQL注入漏洞之外,即使在数据库看到它们之前,空值也会被转换为空字符串。

$x = null;
print_r("VALUES ('$x', 42)");

Outputs: 输出:

VALUES ('', 42)

In other words, you are inserting an empty string, not a NULL. 换句话说,您正在插入一个空字符串,而不是NULL。 To insert a NULL you would have needed to write this: 要插入NULL,您需要编写此代码:

VALUES (NULL, 42)

If you use bind parameters then you won't get this problem and as a bonus your site won't have so many security holes. 如果您使用绑定参数,那么您将不会遇到此问题,作为奖励,您的网站将不会有这么多安全漏洞。 I suggest you read the answer to this question and follow the advice there. 我建议你阅读这个问题的答案,并按照那里的建议。 This will solve your immediate problem as well as improving the security of your site. 这将解决您的直接问题,并提高您网站的安全性。

I agree with Mark Byers - your php is incorrect for the behavior you want. 我同意Mark Byers - 你的php对你想要的行为不正确。

Re: Mark's comment on binding parameters, check out PDO in PHP Re:Mark对绑定参数的评论,请查看PHP中的PDO

If you still don't want to use parameters, you could try the following: 如果您仍然不想使用参数,可以尝试以下操作:


if (isset($customerName) && $customerName != '')
{
  $c = '\'' . $customerName . '\'';
} else {
  $c = 'null';
}

if (isset($_POST['CustomerCompany']) && $_POST['CustomerCompany'] != '')
{
  $cc = '\'' . $_POST['CustomerCompany'] . '\'';
} else {
  $cc = 'null';
}

$sql = 'INSERT INTO tblCustomers (custname,company) 
        VALUES ('.$c.','.$cc.')';

Edit: Have you considered just checking in your PHP code to ensure the values are not blank/null first? 编辑:您是否考虑过只检查您的PHP代码以确保值不是空/空? That way you could avoid the trip to the database altogether (based on my interpretation of your comment)? 这样你就可以避免完全访问数据库(基于我对你的评论的解释)? Not really an answer to the MySQL behavior, but might sort out your problem. 不是MySQL行为的答案,但可能会解决您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM