文章851
标签121
分类10

MySQL 唯一索引中的 NULL 值:允许多个吗?

2024-09-28T08:56:00.png
在数据库设计中,索引是一种重要的优化工具,尤其是唯一索引(UNIQUE INDEX)。它不仅用于加速查询,还确保了数据的唯一性。然而,对于 NULL 值在唯一索引中的处理,许多人可能会产生疑问:在 MySQL 中,唯一索引的字段值是否允许存在多个 NULL 值?

唯一索引的基本概念

唯一索引是一种特殊类型的索引,用于保证表中某一列或某几列的值在所有行中都是唯一的。唯一索引的主要作用是防止重复数据的插入。例如,当你在用户表中创建一个唯一索引以确保电子邮件地址的唯一性时,MySQL 会拒绝任何试图插入相同电子邮件地址的记录。

NULL 值的处理

在 SQL 标准中,NULL 值被视为“未知”。这意味着 NULL 值不等于任何其他值,包括另一个 NULL 值。因此,在 MySQL 中:

  • 唯一索引可以包含多个 NULL 值。
  • NULL 值之间不被视为相等。

示例

考虑一个简单的用户表 users,我们希望确保每个用户的电子邮件地址是唯一的,但也允许用户没有提供电子邮件。我们可以在 email 字段上创建一个唯一索引:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) UNIQUE
);

在这种情况下,我们可以插入以下数据:

INSERT INTO users (email) VALUES (NULL);
INSERT INTO users (email) VALUES (NULL);
INSERT INTO users (email) VALUES ('user@example.com');

上述插入操作是允许的,因为两个 NULL 值在唯一索引中不会被认为是冲突的。

注意事项

尽管 MySQL 允许在唯一索引中存在多个 NULL 值,但在设计数据库时仍需谨慎:

  1. 数据完整性:确保对业务逻辑的理解,合理使用 NULL 值。
  2. 索引性能:过多的 NULL 值可能会影响索引的性能,因此在设计时要关注查询效率。
  3. 数据库版本:不同版本的 MySQL 对 NULL 值的处理可能存在差异,确保参考相应版本的文档。

总结

在 MySQL 中,唯一索引允许多个 NULL 值的存在,这是因为 NULL 值被视为“未知”,并不相等于其他 NULL 值。在设计数据库时,理解这一特性对于确保数据完整性和优化查询性能至关重要。

PHP OpenSSL Rsa 工具类

2024-08-20T12:33:49.png


<?php


class Rsa
{
    /**
     * 生成证书
     * @return array
     */
    public static function exportOpenSSLFile($bits = 1024)
    {
        $config = array(
            "digest_alg" => "sha512",
            "private_key_bits" => $bits,           //字节数  512 1024 2048  4096 等
            "private_key_type" => OPENSSL_KEYTYPE_RSA,   //加密类型
        );
        $res = openssl_pkey_new($config);
        if ($res == false) return [];

        openssl_pkey_export($res, $private_key);
        $public_key = openssl_pkey_get_details($res);
        $public_key = $public_key["key"];
        openssl_free_key($res);

        return [$private_key, $public_key];
    }

    /**
     * 生成签名
     * @param array $params 待签名的所有参数
     * @return string 生成的签名
     */
    public static function getSignGenerator($params, $ssl_private)
    {
        //生成待验签的字符串
        $data = self::getSignStr($params);
        $pem = "-----BEGIN RSA PRIVATE KEY-----\n" .
            wordwrap($ssl_private, 64, "\n", true) .
            "\n-----END RSA PRIVATE KEY-----";

        //openssl_private_encrypt($data, $crypted, $pem);
        openssl_sign($data, $sign, $pem, OPENSSL_ALGO_SHA256);

        return base64_encode($sign);
    }

    /**
     * 验证签名 公钥验证签名
     * @param array $params 待签名的所有参数
     * @param string $sign 生成的签名
     * @return boolean 校验的结果
     */
    public static function signCheck($encrypted, $sign, $ssl_public)
    {
        //对方的公钥内容 一行的形式
        $pem = "-----BEGIN PUBLIC KEY-----\n" .
            wordwrap($ssl_public, 64, "\n", true) .
            "\n-----END PUBLIC KEY-----";

        $result = @openssl_verify(md5($encrypted), base64_decode($sign), $pem, OPENSSL_ALGO_SHA512);

        return $result == 1;
    }

    /**
     * 我们自己的加密
     * @param $string
     * @param $pubKey
     * @return string
     */
    function encrypt($string, $ssl_public)
    {
        $res = "-----BEGIN PUBLIC KEY-----\n" .
            wordwrap($ssl_public, 64, "\n", true) .
            "\n-----END PUBLIC KEY-----";

        openssl_public_encrypt($string, $encrypt, $res);

        return base64_encode($encrypt);
    }


    /**
     * 私钥加密 (使用公钥解密)
     * @param string $data
     * @param $privateKey
     * @param int $padding
     * @return null|string
     */
    public static function privateEncrypt(string $data, $privateKey, $padding = OPENSSL_PKCS1_PADDING)
    {
        $encrypted = '';
        $chunks = str_split($data, 117);
        foreach ($chunks as $chunk) {
            $partialEncrypted = '';
            $encryptionOk = openssl_private_encrypt($chunk, $partialEncrypted, $privateKey, $padding);
            if ($encryptionOk === false) {
                return null;
            }
            $encrypted .= $partialEncrypted;
        }

        return base64_encode($encrypted);
    }

    /**
     * 公钥加密(使用私钥解密)
     * @param string $data 加密字符串
     * @param int $padding
     * @return null|string
     */
    public static function publicEncrypt(string $data, $publicKey, $padding = OPENSSL_PKCS1_PADDING)
    {
        $encrypted = '';
        $chunks = str_split($data, 117);
        foreach ($chunks as $chunk) {
            $partialEncrypted = '';
            $encryptionOk = openssl_public_encrypt($chunk, $partialEncrypted, $publicKey, $padding);
            if ($encryptionOk === false) {
                return null;
            }
            $encrypted .= $partialEncrypted;
        }

        return base64_encode($encrypted);
    }

    /**
     * @param string $encrypted
     * @param $privateKey
     * @return null
     * @uses 私钥解密 (使用公钥加密)
     */
    public static function privateDecrypt(string $encrypted, $privateKey)
    {
        $decrypted = '';
        $chunks = str_split(base64_decode($encrypted), 128);
        foreach ($chunks as $chunk) {
            $partial = '';
            $decryptIsTrue = openssl_private_decrypt($chunk, $partial, $privateKey);
            if ($decryptIsTrue === false) {
                return null;
            }
//            echo $partial, PHP_EOL;
            $decrypted .= $partial;
        }

        return $decrypted;
    }

    /**
     * 公钥解密 (使用私钥解密)
     * @param string $encrypted 被解密字符串
     * @return null
     */
    public static function publicDecrypt(string $encrypted, $publicKey)
    {
        $decrypted = '';
        $chunks = str_split(base64_decode($encrypted), 128);
        foreach ($chunks as $chunk) {
            $partial = '';
            $decryptIsTrue = openssl_public_decrypt($chunk, $partial, $publicKey);
            if ($decryptIsTrue === false) {
                return null;
            }
            $decrypted .= $partial;
        }
        return $decrypted;
    }

    /**
     * 私钥签名
     * @param $data string 验签内容
     * @param $signature string 签名字符串
     * @param int $signature_alg
     * @return string
     */
    public static function privateSign($data, $privateKey, $signature_alg = OPENSSL_ALGO_SHA1)
    {
        $signature = '';
        openssl_sign($data, $signature, $privateKey, $signature_alg);
        openssl_free_key($privateKey);

        return base64_encode($signature);
    }

    /**
     * 公钥验签
     * @param $data string 验签内容
     * @param $signature string 签名字符串
     * @param int $signature_alg
     * @return bool
     */
    public static function publicSign($data, $signature, $publicKey)
    {
        $result = openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA512);

        return $result === 1;
    }

    /**
     * 生成待签名的字符串
     * @param array $data 参与签名的参数数组
     * @return string 待签名的字符串
     */
    public static function getSignStr(array $data)
    {
        unset($data['sign']);
        //排序
        ksort($data);
        //剔除sign 如果对方的签名叫sign 或者可以在调用方法的时候剔除
        //unset($data['sign']);

        $stringToBeSigned = '';

        $i = 0;

        foreach ($data as $k => $v) {
            if ($i == 0) {
                $stringToBeSigned .= "$k" . "=" . "$v";
            } else {
                $stringToBeSigned .= "&" . "$k" . "=" . "$v";
            }

            $i++;
        }

        return $stringToBeSigned;
    }

}

Git:解决报错:fatal: The remote end hung up unexpectedly

2024-09-05T07:47:26.png

问题描述 : Git:解决报错:fatal: The remote end hung up unexpectedly

问题原因 : 推送的文件太大.

解决方法 :

1. 修改设置 git config 文件的 postBuffer的大小 . (设置为500MB)


git config --local http.postBuffer 524288000

注: --local 选项指定这个设置只对当前仓库生效.

2. 或者直接修改本地仓库的 .config 文件

$ cd .git
$ vim config

增加下面两行内容

[http]
    postBuffer = 524288000
Fatal: the remote end hung up unexpectedly

如何在 Mac 安裝 Node.js & NPM

2024-08-12T12:10:28.png

👉🏻 Node.js 官方链接

Node.js
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
nodejs.org

下载 LTS 的版本

2024-08-12T12:12:25.png

点击下载的 node-vx.x.x.pkg 安裝 Node.js
紧接着就是点击 MacOS 安裝的一堆确认(建议安装注意下细节)
2024-08-12T12:20:53.png
2024-08-12T12:21:05.png

2024-08-12T12:22:14.png
2024-08-12T12:22:24.png

2024-08-12T12:22:35.png
2024-08-12T12:22:46.png

成功安裝後我們回到 Terminal

安裝成功後,我們可以透過 Terminal 使用 which 確認是否安裝成功,可以試著在 Terminal 輸入以下命令:

$ which npm
/usr/local/bin/npm

$ which node
/usr/local/bin/node

2024-08-12T12:23:39.png

输入 node & npm Command

我們可以就在 Terminal 做 node & npm 的 command 啦!
2024-08-12T12:24:08.png

2024-08-12T12:24:17.png

启动一個 web server

我们可以另外写一個 web server 的 app 来测试一下,这边我们使用 http 来启动一个 web server,实操代码如下:

// server.js

const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(3000, 'localhost', () => {
  console.log('Server running at http://localhost:3000/');
});

接着我们透过 node 来启动这个web server, 输入一下命令:

$ node server.js
Server running at http://localhost:3000/

2024-08-12T12:25:11.png

接着我们前往浏览器点开 http://localhost:3000/,就可以看到 Hello World 的字串啦!結果如下图,如果有看到 Hello World 就代表我们完全成功啦!
2024-08-12T12:27:20.png

JavaScript , let 和 var 的区别

在 JavaScript 中,letvar 都是用于声明变量的关键字,但它们有一些重要的区别:

  1. 作用域

    • var 声明的变量是函数作用域(function-scoped),而 let 声明的变量是块级作用域(block-scoped)。
  2. 变量提升

    • 使用 var 声明的变量会存在变量提升(hoisting)现象,即变量声明会被提升到函数或全局作用域的顶部,但初始化不会被提升。
    • 使用 let 声明的变量不会发生变量提升,变量只能在声明后使用。
  3. 重复声明

    • 使用 var 可以重复声明同一个变量而不会报错。
    • 使用 let 在同一作用域内重复声明同一个变量会导致语法错误。
  4. 全局对象属性

    • 使用 var 声明的全局变量会成为全局对象的属性(如 window 对象下的属性),而使用 let 声明的变量不会。
  5. 循环中的行为

    • for 循环中,使用 var 声明的变量会在循环体外部存在,而使用 let 声明的变量在每次迭代中都会创建一个新的绑定。

示例:

// 使用 var
function varExample() {
    if (true) {
        var varVariable = 'I am var';
    }
    console.log(varVariable); // 输出 'I am var'
}

// 使用 let
function letExample() {
    if (true) {
        let letVariable = 'I am let';
    }
    console.log(letVariable); // 报错:Uncaught ReferenceError: letVariable is not defined
}

2024-08-12T07:55:04.png

总的来说,推荐使用 let 替代 var,因为 let 更符合现代 JavaScript 开发的需求,避免了 var 存在的一些问题,如变量提升和作用域问题。

">