【MySQL】【systemd】mysqld_pre_systemd 及 mysqld@.service 的 bugs

news2024/10/4 23:28:43

mysqld_pre_systemd 及 mysqld@.service 的 bugs

  • 问题原理
    • mysqld_pre_systemd 的 bugs
    • mysqld@.service 的 bugs
  • 测试案例
    • 重现不指定 `datadir` 和 `log-error` 的 bugs
    • 开启 SELinux ,指定不同于默认值的自定义数据目录和错误日志位置进行测试
  • 修正方法
    • 方法一:向 mysqld@.service 文件添加 mysqld `--datadir` 命令行选项(不建议)
    • 方法二:修改 mysqld_pre_systemd 脚本向选项文件中对应选项组末尾添加 `datadir` 选项(建议)

问题原理

mysqld_pre_systemd 的 bugs

首先看一下这个脚本的原内容:

[root@ic-source ~]$ cat /usr/bin/mysqld_pre_systemd 
#! /bin/bash

# Copyright (c) 2015, 2022, Oracle and/or its affiliates.
#
# Script used by systemd mysqld.service to run before executing mysqld
#

get_option () {
    local section=$1
    local option=$2
    local default=$3
    local instance=$4
    ret=$(/usr/bin/my_print_defaults  ${instance:+--defaults-group-suffix=@$instance} $section | \
              grep '^--'${option}'=' | cut -d= -f2- | tail -n 1)
    [ -z "$ret" ] && ret=$default
    echo $ret
}

install_validate_password_sql_file () {
    local initfile
    initfile="$(mktemp /var/lib/mysql-files/install-validate-password-plugin.XXXXXX.sql)"
    chmod a+r "$initfile"
    echo "SET @@SESSION.SQL_LOG_BIN=0;" > "$initfile"
    echo "INSERT INTO mysql.component (component_id, component_group_id, component_urn) VALUES (1, 1, 'file://component_validate_password');" >> $initfile
    echo $initfile
}

fix_mysql_upgrade_info () {
    datadir=$(get_option mysqld datadir "/var/lib/mysql${instance:+-$instance}" $instance)
    if [ -d  "$datadir" ]  && [ -O "$datadir/mysql_upgrade_info" ]; then
        chown --reference="$datadir" "$datadir/mysql_upgrade_info"
        if [ -x /usr/bin/chcon ]; then
            /usr/bin/chcon --reference="$datadir" "$datadir/mysql_upgrade_info" > /dev/null 2>&1
        fi
    fi
}

install_db () {
    # Note: something different than datadir=/var/lib/mysql requires SELinux policy changes (in enforcing mode)

    # mysql_upgrade_info file should be owned by mysql user since MySQL 8.0.16
    fix_mysql_upgrade_info

    # No automatic init wanted
    [ -e /etc/sysconfig/mysql ] && . /etc/sysconfig/mysql
    [ -n "$NO_INIT" ] && exit 0

    local instance=$1
    datadir=$(get_option mysqld datadir "/var/lib/mysql${instance:+-$instance}" $instance)
    log=$(get_option mysqld 'log[_-]error' "/var/log/mysql${instance:+-$instance}.log" $instance)

    # Restore log, dir, perms and SELinux contexts

    if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
        install -d -m 0751 -omysql -gmysql "$datadir" || exit 1
    fi

    if [ ! -e "$log" -a ! -h "$log" -a x$(dirname "$log") = "x/var/log" ]; then
        case $(basename "$log") in
            mysql*.log) install /dev/null -m0640 -omysql -gmysql "$log" ;;
            *) ;;
        esac
    fi

    if [ -x /usr/sbin/restorecon ]; then
        /usr/sbin/restorecon "$datadir"
        [ -e "$log" ] && /usr/sbin/restorecon "$log"
        for dir in /var/lib/mysql-files /var/lib/mysql-keyring ; do
            if [ -x /usr/sbin/semanage -a -d /var/lib/mysql -a -d $dir ] ; then
                /usr/sbin/semanage fcontext -a -e /var/lib/mysql $dir >/dev/null 2>&1
                /sbin/restorecon -r $dir
            fi
        done
    fi

    # If special mysql dir is in place, skip db install
    [ -d "$datadir/mysql" ] && exit 0

    # Create initial db and install validate_password plugin
    initfile="$(install_validate_password_sql_file)"
    /usr/sbin/mysqld ${instance:+--defaults-group-suffix=@$instance} --initialize \
                     --datadir="$datadir" --user=mysql --init-file="$initfile"
    rm -f "$initfile"

    # Generate certs if needed
    if [ -x /usr/bin/mysql_ssl_rsa_setup -a ! -e "${datadir}/server-key.pem" ] ; then
        /usr/bin/mysql_ssl_rsa_setup --datadir="$datadir" --uid=mysql >/dev/null 2>&1
    fi
    exit 0
}

install_db $1

exit 0
  • 基础程序是 /usr/bin/my_print_defaults ,打印某个 MySQL 程序的默认参数,通过 get_option() 调用。
  • get_option() 用来获取 MySQL 实例的选项配置。install_validate_password_sql_file () 用来创建并执行为 `root`@`localhost` 用户生成随机密码的 MySQL 初始化语句。- fix_mysql_upgrade_info () 用来修复 mysql_upgrade_info 的文件属主和 SELinux 安全上下文。
  • install_db () 是主函数,负责整个 MySQL 实例的初始化安装工作,datadir 不以目录形式存在,且不以符号链接存在,且绝对路径前缀不是/var/lib则创建一个名为/var/lib/mysql-实例名 的默认数据目录;使用类似的判断条件,会创建一个/var/log/mysql-实例名.log 的默认错误日志文件。这些是为 SELinux 环境考虑的。install_db () 还会创建 SSL/RSA 证书。如果存在 /etc/sysconfig/mysql 文件,则运行它,之后判断如果NO_INIT 环境变量的值为非空,则直接以 0 为退出状态退出 mysqld_pre_systemd 主进程。

有问题的点在于脚本默认会创建数据目录和日志文件,却没有在后续使用时显式指定使用它们(因为用户没有配置它们):

  • 在初始化时却只使用了默认数据目录而并没有使用默认错误日志文件及用户指定的自定义临时目录(不指定默认为操作系统指定的临时目录,Linux 操作系统一般为 /tmp)。虽然 MySQL 会给它们赋予默认值,但在特定情况下会无法向错误日志文件记录错误日志。
  • /usr/lib/systemd/system/mysqld@.service 中启动 mysqld 服务时只使用了MYSQLD_OPTS 环境变量的值而并没有显式指定默认创建的数据目录和错误日志文件,以及可能存在的用户自定义tmpdir临时目录选项。这点会在后文介绍 mysqld@.service 部分体现。

mysqld@.service 的 bugs

[root@ic-source ~]$ cat /usr/lib/systemd/system/mysqld@.service
# Copyright (c) 2016, 2022, Oracle and/or its affiliates.
#
# systemd service file for MySQL forking server
#

[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target

[Service]
User=mysql
Group=mysql

Type=notify

# Disable service start and stop timeout logic of systemd for mysqld service.
TimeoutSec=0

# Execute pre and post scripts as root
PermissionsStartOnly=true

# Needed to create system tables
ExecStartPre=/usr/bin/mysqld_pre_systemd %I

# Start main service
ExecStart=/usr/sbin/mysqld --defaults-group-suffix=@%I $MYSQLD_OPTS

# Use this to switch malloc implementation
EnvironmentFile=-/etc/sysconfig/mysql

# Sets open_files_limit
LimitNOFILE = 10000

Restart=on-failure

RestartPreventExitStatus=1

# Set enviroment variable MYSQLD_PARENT_PID. This is required for restart.
Environment=MYSQLD_PARENT_PID=1

PrivateTmp=false

如果我将执行部分的内容修改为:

ExecStart=/usr/sbin/mysqld --defaults-group-suffix=@%I --datadir=/var/lib/mysql-%I $MYSQLD_OPTS

则可以直接运行,否则必须指定 datadir 选项。同样的方法,也适用于错误日志。

mysqld 的默认逻辑是用户必须指定 datadirlog-error ,且如果需要使用自定义的临时文件目录 tmpdir ,必须提前创建并授予适当文件访问权限。而如果是这样设计的,就应该在文档中有所声明,而事实是 MySQL 并没有有关这些内容的明确清晰的声明。此外,mysqld@.service 的设计逻辑与 mysql_pre_systemd 中默认初始化的设计逻辑难以自洽,即既然后者初始化了数据目录和错误日志文件,为什么不在启动 mysqld 服务时如未定义这些选项则默认使用呢?

测试案例

重现不指定 datadirlog-error 的 bugs

/etc/my.cnf 中添加如下内容:

[mysqld@test01]
#datadir=/var/lib/mysql-test01
port=3309
mysqlx_port=33090
admin_port=33092
#socket=/var/lib/mysql-test01/mysql.sock
#log-error=/var/log/mysql-test01.log

innodb_buffer_pool_size=256M
innodb_redo_log_capacity=100M
innodb_flush_method=O_DIRECT_NO_FSYNC

执行如下命令,验证当前不存在 /var/libmysql-test01 目录及/var/log/mysql-test01.log

[root@ic-source lib]$ ll /var/lib/mysql-test01
[root@ic-source lib]$ ll /var/log/mysql-test01.log

在这里插入图片描述

使用 systemctl 启动 MySQL 实例 test01

[root@ic-source lib]$ systemctl start mysqld@test01

一定会启动失败,systemctl status mysqld@test01.service -l 查看错误日志:
在这里插入图片描述

再看一下journalctl -xe
在这里插入图片描述
一般看到 polkitd[679]: Unregistered Authentication Agent for unix-process 这种字样的报错,不是文件属主、权限问题,就是文件/目录不存在。[Warning]里还说了因没找到而生成了一个新的 Server UUID ,那么它在哪呢?在 /var/lib/mysql 这个 mysqld.service 的默认目录下。可以通过 server-uuid 内容证明。而另一个 /var/lib/mysql-test01/auto.cnf 为实例初始化时生成的文件,也即应该查找的文件。
在这里插入图片描述
同时,我们查看一下默认创建的错误日志文件是否存在。输出结果证明存在,但内容为空。

[root@ic-source lib]$ ll /var/log/mysql-test01.log 

在这里插入图片描述
下面我们手动启动一下:

[root@ic-source lib]$ mysqld --defaults-group-suffix=@test01 --datadir=/var/lib/mysql-test01 --user=mysql $MYSQLD_OPTS &

注释
$MYSQLD_OPTS默认值为空,可以不加。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

由上图可知,可以正常启动,但使用的 socket 均为默认配置,其中包括 MySQL 标准协议的 socket(/var/lib/mysql/mysql.sockMySQL X 协议的 socket(/run/mysqld/mysqlx.sock 。这里因为我没有启动 mysqld.service ,且已启动的实例中有一个没有显式指定 mysqlx_socket 选项,所以只对 mysqlx.sock 文件已被其他进程使用进行了报错。

启动是启动了,可我们怎么访问呢?

注意,因为初始化后错误日志仍为空,证明刚刚的初始化操作将初始化信息输出到 stderr 里了。我们需要使用 journalctl -xe 找到初始化的 root@`localhost` 用户的临时密码,然后使用 mysql 客户端访问即可。

[root@ic-source ~]$ mysql -uroot -S /var/lib/mysql/mysql.sock -p

在这里插入图片描述
此时已证明可以正常启动了,也进而证明了我的猜想。所以后面的修改初始密码等步骤不做了,我们停止这个进程,并删除掉这个实例相关的文件。

注意
这里还说明一个问题,如果我们要在一台主机上创建并启动多个 MySQL 实例,我们应还需要显式为每个实例指定不同的 MySQL X 协议mysqlx_portmysqlx_socket选项 ,而不只是 MySQL 标准协议portsocket

[root@ic-source lib]$ ps -ef |grep test01 |grep -v grep |awk '{print $2}' |kill -9 $!
[root@ic-source ~]$ rm -rf /var/lib/mysql-test01/
[root@ic-source ~]$ rm -f /var/log/mysql-test01.log 
# 这里我删除了/var/lib/mysql目录下除目录以外的所有文件。如果你的目的不一样,请自行删除
[root@ic-source mysql]$ ll /var/lib/mysql|grep -v "^d"|awk -F \  '{print $9}'|while read i;do rm -f $i;done

注意
即便刚刚我们启动了 mysqld ,但错误日志默认使用的是 stderr 而非 mysqld_pre_systemd 创建的 /var/log/mysql-test01.log 文件,除非你在启动 mysqld 时在命令行显式指定 --log-error 选项。
在这里插入图片描述

开启 SELinux ,指定不同于默认值的自定义数据目录和错误日志位置进行测试

国内一般都会关闭 SELinux,即便是生产环境,我这个测试环境之前也是改成关闭了的,现在改回默认值:

[root@ic-source lib]$ vi /etc/sysconfig/selinux
SELINUX=enforcing
SELINUXTYPE=targeted 

再在根目录 / 下创建一个名为 .autorelabel 空文件,重新刷新SELinux 安全上下文标记。

touch /.autorelabel

说明
.autorelabel 文件用于重新标记 SElinux 的文件系统。
可能在如下场景使用到它:

  • 重启系统时,它会自动重新标记 SElinux 的文件系统。
  • 首次为 SELinux 标记文件系统时。
  • 在不同类型的策略之间切换时发生,例如从禁用策略更改为强制策略(即由 disabled 切换到 enforcing )。

然后重启,有文章说可能需要很长时间,因为要为操作系统中的所有文件重建 SELinux 安全上下文,可笔者并未遇到,启动很快。

将 SELinux 从 targeted 修改为 enforcing 的具体操作过程详见 【MySQL 安全】如何与 SELinux 配合使用 。

在正确配置了 MySQL 有关 SELinux 的配置后,可以顺利启动所有如下 /etc/my.cnf 中定义的 MySQL 服务器实例。

[mysqld@ics_pc_pri]
port=3306
datadir='/var/lib/mysql/data/ics_pc_pri'
tmpdir='/var/lib/mysql/tmp/ics_pc_pri'
socket='/var/lib/mysql/data/ics_pc_pri/mysql.sock'
log-error='/var/log/mysql-ics_pc_pri.log'
slow_query_log_file='/var/log/slow_query-ics_pc_pri.log'
log-bin='ics_pc_pri-bin'

innodb_buffer_pool_size=2048M
innodb_redo_log_capacity=1G
innodb_flush_method=O_DIRECT_NO_FSYNC


[mysqld@ics_rc01_pri]
port=3307
datadir='/var/lib/mysql/data/ics_rc01_pri'
tmpdir='/var/lib/mysql/tmp/ics_rc01_pri'
socket='/var/lib/mysql/data/ics_rc01_pri/mysql.sock'
mysqlx_port=33070
mysqlx_socket='/var/lib/mysql/data/ics_rc01_pri/mysqlx.sock'
admin_port=33072
log-error='/var/log/mysql-ics_rc01_pri.log'
slow_query_log_file='/var/log/slow_query-ics_rc01_pri.log'
log-bin='ics_rc01_pri-bin'

innodb_buffer_pool_size=1024M
innodb_redo_log_capacity=100M
innodb_flush_method=O_DIRECT_NO_FSYNC

[mysqld@replica01]
datadir=/var/lib/mysql/replica01
port=3308
mysqlx_port=33080
mysqlx_socket=/var/lib/mysql/replica01/mysqlx.sock
admin_port=33082
socket=/var/lib/mysql/replica01/mysql.sock
log-error=/var/log/mysql-replica01.log

innodb_buffer_pool_size=256M
innodb_redo_log_capacity=100M
innodb_flush_method=O_DIRECT_NO_FSYNC

[mysqld@test01]
datadir=/var/lib/mysql-test01
socket=/var/lib/mysql-test01/mysql.sock
port=3309
mysqlx_socket=/var/lib/mysql-test01/mysqlx.sock
mysqlx_port=33090
admin_port=33092
#log-error=/var/log/mysql-test01.log
log-error=/var/lib/mysql-test01/mysql-test01.log

innodb_buffer_pool_size=256M
innodb_redo_log_capacity=100M
innodb_flush_method=O_DIRECT_NO_FSYNC

在这里插入图片描述

由此可见:

  • systemdSELinux 并没有强制单元名称的分隔符必须且仅为 @ ,而可以是 _@.-等(我按查阅的 systemd 说明文章只尝试了这四个,可能其他的特殊字符也适用)。

  • SELinux 默认并没有强制 MySQL 相关目录及文件的位置,而是 MySQL 提供的策略限制:

    • mysqld_selinux
    • mysqld_safe_selinux

    笔者使用自定义数据目录、临时文件目录和错误日志位置,均可以启动 MySQL 服务。

参考
有效的单元名称由一个“名称前缀”、一个点(“.”)和一个指定单元类型的后缀组成。“单元前缀”必须包含一个或多个有效字符( ASCII 字母、数字、“:”、“-”、“_”、“.”和“\”)。单元名称(包括后缀)的总长度不得超过 256 个字符。类型后缀必须是“.service”、“.socket”、“.device”、“.mount”、“.automount”、“.swap”、“.target”、“.path”、“.timer”、“.slice”或“.scope” 之一。
systemd 对单元名称中的“实例名”部分并没有明确要求,因而可以是任何 ASCII 字符(估计控制字符不行),但建议沿用其对“单元前缀”的命名规则限制。

修正方法

方法一:向 mysqld@.service 文件添加 mysqld --datadir 命令行选项(不建议)

sed -i -e 's|^\(ExecStart=/usr/sbin/mysqld --defaults-group-suffix=@%I\)|\1 --datadir=/var/lib/mysql-%I|g' /usr/lib/systemd/system/mysqld@.service

在这里插入图片描述
该方法最简单,但限制 datadir 必须使用 /var/lib/mysql-实例名的格式,在选项文件中使用其他自定义的 datadir 不会生效,且会报错。因为命令行选项的优先级高于选项文件的优先级,详见 MySQL 选项优先级 及4.2.2 指定程序选项 。

方法二:修改 mysqld_pre_systemd 脚本向选项文件中对应选项组末尾添加 datadir 选项(建议)

使用如下内容替换 /usr/bin/mysqld_pre_systemd 脚本内容:

#! /bin/bash

# Copyright (c) 2015, 2022, Oracle and/or its affiliates.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0,
# as published by the Free Software Foundation.
#
# This program is also distributed with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms,
# as designated in a particular file or component or in included license
# documentation.  The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have included with MySQL.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA


# Script used by systemd mysqld.service to run before executing mysqld

get_option () {
    local section=$1
    local option=$2
    local default=$3
    local instance=$4
    ret=$(/usr/bin/my_print_defaults  ${instance:+--defaults-group-suffix=@$instance} $section | \
              grep '^--'${option}'=' | cut -d= -f2- | tail -n 1)
    [ -z "$ret" ] && ret=$default && sed -i -E \
        "/^\[mysqld@${instance}\]\$/a ${option}=$ret" /etc/my.cnf
    echo $ret
}

install_validate_password_sql_file () {
    local initfile
    initfile="$(mktemp /var/lib/mysql-files/install-validate-password-plugin.XXXXXX.sql)"
    chmod a+r "$initfile"
    echo "SET @@SESSION.SQL_LOG_BIN=0;" > "$initfile"
    echo "INSERT INTO mysql.component (component_id, component_group_id, component_urn) VALUES (1, 1, 'file://component_validate_password');" >> $initfile
    echo $initfile
}

fix_mysql_upgrade_info () {
    datadir=$(get_option mysqld datadir "/var/lib/mysql${instance:+-$instance}" $instance)
    if [ -d  "$datadir" ]  && [ -O "$datadir/mysql_upgrade_info" ]; then
        chown --reference="$datadir" "$datadir/mysql_upgrade_info"
        if [ -x /usr/bin/chcon ]; then
            /usr/bin/chcon --reference="$datadir" "$datadir/mysql_upgrade_info" > /dev/null 2>&1
        fi
    fi
}

install_db () {
    # Note: something different than datadir=/var/lib/mysql requires SELinux policy changes (in enforcing mode)

    # mysql_upgrade_info file should be owned by mysql user since MySQL 8.0.16
    fix_mysql_upgrade_info

    # No automatic init wanted
    [ -e /etc/sysconfig/mysql ] && . /etc/sysconfig/mysql
    [ -n "$NO_INIT" ] && exit 0

    local instance=$1
    datadir=$(get_option mysqld datadir "/var/lib/mysql${instance:+-$instance}" $instance)
    log=$(get_option mysqld 'log[_-]error' "/var/log/mysql${instance:+-$instance}.log" $instance)
    tmpdir=$(get_option mysqld tmpdir "/tmp" $instance)
    socket=$(get_option mysqld socket "/var/lib/mysql${instance:+-$instance}/mysql.sock" $instance)

    # Restore log, dir, perms and SELinux contexts

    if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
        install -d -m 0751 -omysql -gmysql "$datadir" || exit 1
    fi

    if [ ! -e "$log" -a ! -h "$log" -a x$(dirname "$log") = "x/var/log" ]; then
        case $(basename "$log") in
            mysql*.log) install /dev/null -m0640 -omysql -gmysql "$log" ;;
            *) ;;
        esac
    fi

    if [ ! -d "$tmpdir" -a ! -h "$tmpdir" ]; then
        install -d -m 0751 -omysql -gmysql "$tmpdir" || exit 1
    fi

    if [ -x /usr/sbin/restorecon ]; then
        /usr/sbin/restorecon "$datadir"
        /usr/sbin/restorecon "$tmpdir"
        [ -e "$log" ] && /usr/sbin/restorecon "$log"
		[ -e "$socket" ] && /usr/sbin/restorecon "$socket"
        for dir in /var/lib/mysql-files /var/lib/mysql-keyring ; do
            if [ -x /usr/sbin/semanage -a -d /var/lib/mysql -a -d $dir ] ; then
                /usr/sbin/semanage fcontext -a -e /var/lib/mysql $dir >/dev/null 2>&1
                /sbin/restorecon -r $dir
            fi
        done
    fi

    # If special mysql dir is in place, skip db install
    [ -d "$datadir/mysql" ] && exit 0

    # Create initial db and install validate_password plugin
    initfile="$(install_validate_password_sql_file)"
    /usr/sbin/mysqld ${instance:+--defaults-group-suffix=@$instance} --initialize \
                     --datadir="$datadir" --user=mysql --init-file="$initfile" \
                     --tmpdir="$tmpdir" --log-error="$log" --socket="$socket"
    rm -f "$initfile"

    # Generate certs if needed
    if [ -x /usr/bin/mysql_ssl_rsa_setup -a ! -e "${datadir}/server-key.pem" ] ; then
        /usr/bin/mysql_ssl_rsa_setup --datadir="$datadir" --log-error="$log" --uid=mysql >/dev/null 2>&1
    fi
    exit 0
}

install_db $1

exit 0

笔者已将如上脚本 pull request 到 GitHub 上的 mysql/mysql-server 仓库了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/136549.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Word】MathType 运行时错误‘53’:文件未找到:MathPage.WLL

问题描述 1. 环境: MathType7.4Microsoft Office 365Windows 11 2. 问题 情景1. Microsoft Word 启动时显示 Please reload Word to load MathType addin properly 情景2. 安装MathType后在 Microsoft Word 中使用复制粘贴时报错 运行时错误‘53’ 情景3. 在 M…

JavaScript 对象-三种创建对象的方式,遍历获取到对象。

JavaScript 对象-三种创建对象的方式,遍历获取到对象。 目录JavaScript 对象-三种创建对象的方式,遍历获取到对象。1. 对象1.1 什么是对象?1.2 为什么需要对象2. 创建对象的三种方式2.1 利用字面量创建对象2.2 利用new Object创建对象2.3 利用…

【数组】leetcode209.有序数组的平方(C/C++/Java/Js)

leetcode209.长度最小的子数组1 题目2 思路-滑动窗口3 代码3.1 C版本3.2 C版本3.3 Java版本3.4 JavaScript版本4 总结1 题目 题源链接 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, …, nu…

系列教程之《高铁上的GO》-第一篇

作者:坚果,OpenHarmony布道师,OpenHarmony校源行开源大使,CSDN博客专家,电子发烧友鸿蒙MVP,51CTO博客专家博主,阿里云博客专家。 本文主要讲解Go是什么,Go如何安装,开发G…

【Docker】(二)使用Dockerfile构建并发布一个SpringBoot服务

1.前言 在上一篇笔记 Docker基本概念与安装 中,我们已经获取到了一个Docker服务,并了解了Docker的基本组成及其各个组件的作用。 我们了解到,使用Docker的其中一个目的,是为了更加简单,方便的部署我们编写的服务&…

Typora下载和Markdown基础语法

本章内容如下: Typoar笔记下载资源及主题设置Markdown语法使用的基本方法 这篇博客一开始是为了教女朋友如何使用Typora和Markdown语法写的笔记,Markdown语法的内容不太全,只涉及基础使用。 文章目录Typora下载与主题设置Typora主题设置修改图…

在线考试答题系统的五大功能,你知道多少?

在线考试答题系统-五大功能,你知道多少?-在线考试答题系统优势:在线考试答题系统具有高度的可扩展性,高效灵活、功能强大。考试用户随时随地就可通过网络登录在线考试答题系统,参加在线报名、在线练习、在线考试、在线…

嵌入式开发中为什么选择C语言?它有哪些特点?

众所周知,C语言在嵌入式开发中占据着十分重要的地位,为什么嵌入式开发要选择C语言?嵌入式开发的方向可以分为单片机开发、Linx应用开发和现场可编辑逻辑门阵列(FPGA)开发,不同于传统开发模式,操作系统是嵌入…

Nepnep x CatCTF Writeup

Web: 题目名称 ez_js 直接查看网页源代码,查看game.js,进入该目录即可得到flag Reverse: 题目名称 The cat did it 点进来看到一个看着很复杂的图像,离开的概率我猜是0% MD5加密,第一个即为flag Misc&am…

给在校学生的科普文:数字芯片后端工程师的日常

芯片后端设计,看似只是将网表中的晶体管摆放好。但并不是如同砖头砌墙那样简单粗暴。它是一门兼具形式美和工程实践需求的技术。形式美,直接来源于功能内容和需求,在后端设计的环节中,数以万计的标准单元如散乱的点点繁星&#xf…

2022年度穿戴设备行业分析:智能手表销额增长25%,智能手环销量下滑

当前,随着社会经济的发展与居民可支配收入的提高,居民的购买力逐渐增强,我国智能穿戴设备行业也得以快速发展。同时,随着相关技术的不断开发,我国智能穿戴设备行业的技术水平也持续提高。根据数据显示,智能…

软考中级数据库系统工程师好考吗?

数据库还好的,每年五月份考试,通过率20-30%。 数据库系统工程师,主要考核内容:数据库系统基本概念及关系理论;常用的大型数据库管理系统的应用技术;数据库应用系统的设计方法和开发过程;数据库系…

【C++修炼之路】12. stack queue类

每一个不曾起舞的日子都是对生命的辜负 stack&&queue一. stack的介绍和使用1. stack的介绍2. stack的使用二. stack的模拟实现三. queue的介绍和使用1. queue的介绍2. queue的使用四. queue的模拟实现五. deque的介绍和使用1. deque的介绍2. deque的使用3. deque的缺陷…

东方通无法加载程序jar包中的js

东方通中间件使用龙芯适配程序问题描述:东方通无法加载程序jar包中的js排查过程:根据以往经验确保东方通处于最新版本,确认版本为最新的检查容器配置,确认无误在东方通tongweb/bin/external.vmoption 里把-DWebModuleOnly参数值改…

Qt扫盲-QSS定制Qt Widget控件

QSS定制Qt Widget控件概述一、盒子模型二、子控件概述 在使用样式表时,每个部件都被视为具有四个同心矩形的盒子:外边距矩形、边界矩形、内边距矩形和内容矩形。 其实即是每一个继承至 QWidget 都支持的,这个和 前端的 CSS 里面的 盒子模型有些区别但是…

哪吒S亮相广州车展,定位B级燃油车颠覆者

2022年收官,哪吒汽车宣布全年交付152073台,其中: •哪吒U 51021台; •哪吒V 98847台; •哪吒S 2003台(12月首月交付)。与此同时,在年末的广州车展,哪吒汽车携全系车型参展…

Elastic-Job分布式任务调度(2):Elastic-Job快速入门

1 环境搭建 1.1 版本要求 JDK要求1.7及以上版本 Maven要求3.0.4及以上版本 zookeeper要求采用3.4.6及以上版本 1.2 Zookeeper安装&运行 自行查看我的zookeeper专题 ZooKeeper(3):ZooKeeper集群环境搭建_不死鸟.亚历山大.狼崽子的博客-CSDN博客 1.3 创建maven工程 创建…

Python代理IP的使用和代理池的设置

熟悉python的人都知道为了python的正常请求,维持数据的稳定获取,都会用到代理IP。代理IP不仅可以用来规避IP在单位时间的请求次数,还可以借助代理来隐藏真实的IP,避免出现“IP请求过于频繁”,“403”等报错。今天就带大…

甲方安全之仿真钓鱼演练(邮件+网站钓鱼)

文章目录一、简介1.1 前言1.2 整体思路1.3 演练所需1.4 各邮件厂商日群发上限二、钓鱼平台搭建及配置2.1 gophish平台搭建2.2 收件目标配置(User & Groups)2.3 发信邮箱配置(Sending Profiles)2.4 邮件模版配置(Em…

Windows下socket网络编程,C++,Email的客户端程序(支持邮件基于SMTP的发送和POP3的接收)

阅读前请看一下:我是一个热衷于记录的人,每次写博客会反复研读,尽量不断提升博客质量。文章设置为仅粉丝可见,是因为写博客确实花了不少精力。不用担心你关注我而我却不关注你,因为我是个诚信互关的人!&…