重学MySQL(如何安装MySQL 5.7数据库)

前言

MySQL支持Centos、Red Hat、 Ubuntu、Windows、Mac等系统,具体支持的系统版本信息可以查看MySQL官方说明。MySQL的安装方式也有很多,例如在Centos上可以使用yum、rpm、二进制文件、源码编译安装等,个人比较喜欢二进制安装的方式,既可以方便的指定安装位置,又没有源码安装那么麻烦。而且源码安装的方式也很通用,在centos与mac上的安装方式基本相同。

安装步骤

环境介绍:

系统版本: CentOS Linux release 7.6.1810 (Core)
MySQL版本: mysql-5.7.32

1.下载MySQL

https://downloads.mysql.com/archives/community/

根据不同的系统版本下载不同版本的mysql

例如: 下载linux版本的二进制安装包
在这里插入图片描述

例如:下载mac版本的二进制安装包
在这里插入图片描述

如果下载MySQL安装包较慢,可以使用迅雷下载,会比直接用浏览器下载快的多。

2.安装mysql

2.1安装mysql依赖

如果没有libaio则mysql初始化和启动就会报错 (mac系统可以省略这一步)

yum install libaio

2.2 修改资源限制

vi /etc/security/limits.conf
# 在文件末尾加入下面参数

* soft nofile 100001
* hard nofile 100002
* soft memlock unlimited
* hard memlock unlimited
* soft nproc 65535
* hard nproc 65535

2.3 重启服务器

reboot

2.4 解压mysql安装包

tar -xvf mysql-5.7.32-el7-x86_64.tar.gz

解压后可以看到如下目录

bin						# mysql的可执行程序(例如:mysql、mysqld、mysql、mysqld_safe等)
docs					# mysql的帮助手册
man						# unix的man手册
include				# 放置一些头文件(例如:mysql.h、sql_common.h等)
lib						# 存放一些库文件
share					# 用于存放字符集、语言等信息
support-files	# 其它支持文件

2.5 创建mysql用户、目录信息

cd mysql-5.7.32-el7-x86_64
groupadd mysql
useradd -r -g mysql -s /bin/false mysql
mkdir data etc tmp
touch etc/my.cnf mysqld_err.log
chown -R mysql:mysql /data/mysql-5.7.32-el7-x86_64
chmod 755 -R /data/mysql-5.7.32-el7-x86_64

2.6 初始化mysql

bin/mysqld --initialize --basedir=/data/mysql-5.7.32-el7-x86_64 --datadir=/data/mysql-5.7.32-el7-x86_64/data --user=mysql

在执行mysqld --initialize的时候一定要设置basedir为解压后的mysql目录 ,使用–initialize或者–initialize-insecure初始化数据库都可以,看自己喜好。

–initialize: 创建默认数据库并退出。创建一个超级用户和过期的密码并存储在日志中。
–initialize-insecure: 创建默认数据库并退出。创建一个超级用户和空密码。

执行完了后大概是下面的样子

2021-06-10T10:05:21.688225Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2021-06-10T10:05:21.974571Z 0 [Warning] InnoDB: New log files created, LSN=45790
2021-06-10T10:05:22.046242Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
2021-06-10T10:05:22.111192Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 5e3a942a-c9d3-11eb-aaf8-525400933ed6.
2021-06-10T10:05:22.117654Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
2021-06-10T10:05:22.566092Z 0 [Warning] CA certificate ca.pem is self signed.
2021-06-10T10:05:22.731437Z 1 [Note] A temporary password is generated for root@localhost: :viiStZFk21R

复制上面的密码,一会用来登录mysql

3.创建mysql配置文件

创建mysql配置文件之前我们先来稍微了解一下我们的配置应该如何传递给mysqld

我们可以在启动mysqld的时候通过命令行指定启动参数,例如:mysqld --port=3306,但是每次启动的时候都要指定很长一串配置,比较不方便,所以我们也可以将配置写到配置文件中。

配置文件中的启动选择被划分为了很多组,每个组有一个组名,用[]括起来,类似下面这样

[server]
具体的配置...

[mysqld]
具体的配置...

[mysqld_safe]
具体的配置...

[client]
具体的配置...

[mysql]
具体的配置...

[mysqladmin]
具体的配置...

在配置文件中指定的配置于命令行语法,但是配置文件中只能使用长形式的配置。(例如-P是短形式的配置,–port就是长形式的配置)。并且配置文件中指定的启动选项不能加--前缀,=周围可以有空白字符(启动命令行中=周围不允许有空白字符),配置文件中还可以使用#添加注释。

配置文件中不同的选项组是给不同的启动命令使用的,不过有两个组比较特别[server]可以给所有的服务器命令使用,[client]可以给所有的客户端命令使用。

启动命令类别能读取的组
mysqld服务器[mysqld]、[server]、[mysqld-5.7]
[mysqld_safe]服务器[mysqld]、[server]、[mysqld_safe]
mysql.server服务器[mysqld]、[server]、[mysql.server]
mysql客户端[mysql]、[client]
mysqladmin客户端[mysqladmin]、[client]
mysqldump客户端[mysqldump]、[client]

所以我们直接使用clientserver组就行,通过二进制安装后默认是没有配置文件的,需要我们自己创建一个,将下面的配置放到我们的数据库配置文件中etc/my.cnf,端口可以改成自己想要的。当然下面配置的目录别忘了换成你自己实际的目录。

测试环境可以直接使用下面配置模板,但是线上环境需要根据机器配置再调整一下参数

[client]
port = 8906
default-character-set = utf8mb4
socket = /data/mysql-5.7.32-el7-x86_64/tmp/mysql.sock

[server]
user = mysql
port = 8906

slow_query_log = 1
long-query-time = 1

log_timestamps = SYSTEM

max_connections = 5000

character-set-server = utf8mb4

basedir = /data/mysql-5.7.32-el7-x86_64
tmpdir = /data/mysql-5.7.32-el7-x86_64/tmp
datadir = /data/mysql-5.7.32-el7-x86_64/data
socket = /data/mysql-5.7.32-el7-x86_64/tmp/mysql.sock
log-error = /data/mysql-5.7.32-el7-x86_64/mysqld_err.log
pid-file = /data/mysql-5.7.32-el7-x86_64/mysqld.pid

# 跳过域名解析,设置为ON后会减少域名解析步骤,第一次连接时可能会加快连接速度
# 授权表也就不能使用主机名授权了
skip_name_resolve = ON

# innodb页大小
# 页是InnoDB存储引擎磁盘管理的最小单位,每个页默认16KB
# 设置完成后,不可修改,除非通过mysqldump导入和导出产生新的库
# 一个区会分配64个连续的页,所以一个区的大小是16k * 64 = 1M
# 一个区内页与页之间必须是连续的,区与区之间不要求连续
innodb_page_size = 16384

# buffer pool会包含缓存页和一些控制信息,控制信息大概占用每个缓存页的5%左右
# 所以buffer pool会占用设置的105%左右 
# 默认128MB, 
# buffer pool不能设置的占用机器内存比例过高,因为buffer pool实际占设置的105%左右,mysql其他操作会占用一些,操作系统也会占用一些,还要预留一些给os cache使用
# 如果机器只跑一个mysql服务,可以配置为机器内存的50%-60%比较合适
# innodb_buffer_pool_size必须是innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances的倍数
# 如果我们设置的不是倍数,mysql会自动帮我们调整为倍数
# 主要是为了保证每个buffer pool中的chunk数量相同
innodb_buffer_pool_size = 128M

# buffer实际上就是一块在内存里的数据结构,由一堆缓存页和描述数据块和free、flush、lru链表组成
# mysql是可以多线程处理请求的,那么操作lru flush free链表肯定就会有线程安全问题,肯定是要加锁的
# 虽然基于内存的锁也很快,但是对于激烈的竞争锁的场景下,性能肯定严重下降
# 设置多个buffer_pool相当于对数据结构进行了分段,降低锁的竞争
# 比如buffer pool设置了16G, 4个buffer_pool_instances,就相当于每个buffer pool大小大概有4G
# 但是也并不是buffer pool设置的越多越好,管理buffer pool也是需要开销的,因此buffer pool总大小小于1G的时候设置多个buffer pool是不生效的
innodb_buffer_pool_instances = 1

# 在MySQL5.7.5之前是不能在运行期间调整buffer pool的大小的
# MySQLl5.7.5之后为了可以让buffer pool扩容,搞了一个chunk
# buffer pool是由chunk组成的,这样当给buffer pool扩容的时候,只需要增加chunk就行了
# 如果mysql没有chunk,buffer pool是一块连续的内存空间,扩容的时候只能申请一块新的内存地址
# 然后将之前buffer pool的数据拷贝到新的buffer pool中,这样效率比较低
innodb_buffer_pool_chunk_size = 128M

# MySQL重启后buffer pool内存中的数据都会被清空,此时buffer pool内存中的数据需要预热
# 否则突然来了很多请求,会造成很大的IO压力
# 打开这个参数后,当mysql被正常关闭后会把buffer pool中的数据自动dump出来,以便下次启动可以选择是不是加载
innodb_buffer_pool_dump_at_shutdown = ON

# buffer pool保存的数据文件名字
innodb_buffer_pool_filename = ib_buffer_pool

# MySQL关闭是从每个buffer pool中最近使用页面保存的百分比
innodb_buffer_pool_dump_pct = 25

# 中止buffer pool加载操作
# 使用 SET GLOBAL innodb_buffer_pool_load_abort=ON; 
innodb_buffer_pool_load_abort = OFF

# MySQL启动时加载buffer pool
innodb_buffer_pool_load_at_startup = ON

# 在线保存buffer pool使用
# 如果在MySQL服务器运行时要保存buffer pool
# 使用 SET GLOBAL innodb_buffer_pool_dump_now=ON; 语句
# 查询buffer pool保存进度: SHOW STATUS LIKE 'Innodb_buffer_pool_dump_status'; 
innodb_buffer_pool_dump_now = OFF

# 在线恢复buffer pool状态
# 使用 SET GLOBAL innodb_buffer_pool_load_now=ON;
# 查询buffer pool加载进度: SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';
innodb_buffer_pool_load_now = OFF

# redo log buffer大小
innodb_log_buffer_size = 32M

# 每个redo log文件大小
# 如果线上环境的TPS较高,建议加大至1G以上,如果压力不大可以调小
innodb_log_file_size = 1G 

# 可以有多少个redo log文件, redo log是循环写的
innodb_log_files_in_group = 3

# 线性预读技术,根据缓冲池中按顺序访问的页面来预测可能很快需要哪些页面
# 一个区(extent)由64个页(page)组成
# 当一个区内的56个页被顺序读到innodb buffer pool中后,会将下一个区通过异步的方式加载到innodb buffer pool中,以便优化IO性能
# 没有这个参数之前,仅仅访问到一个区内最后一个页的时候,才会异步加载下一个区
innodb_read_ahead_threshold = 56

# 随机预读技术,根据缓冲池中已有的页面来预测何时可能很快需要页面,而不管这些页面的读取顺序如何
# 如果在innodb buffer pool中找到来自相同范围的13个连续页面,则InnoDB异步发出请求以预取该范围的剩余页面
innodb_random_read_ahead = OFF

# innodb buffer pool大小是有限的,如果需要读取新的页到buffer pool中,但是buffer pool的free链表已经没有空闲的缓存页了
# 这时候就会触发淘汰策略,把旧的缓存页从buffer poll中移除,然后把新的缓存页放进来
# 所以buffer pool中有一个LRU链表 (最近最少使用原则)
# 但是mysql还有预读技术, 但是如果太多page通过预读技术读到LRU头部后,但是这些page都没有用到,反而把一些常用的page淘汰了,这显然不合适
# 所以buffer pool中的LRU链表按照一定比例分成了两截,分别是
# 使用率比较高的缓存页,这一部分链表叫做热数据(young区域)
# 使用率比较低的缓存页,这一部分链表叫做冷数据(old区域)
# innodb_old_blocks_pct 这个参数用来设置old区域在LRU链表中所占的比例,大约占3/8
# 当磁盘上某个page在初次加载到buffer pool时,会被放到LRU old区域的头部,这样对预读到buffer pool但是后续不访问的页面就会被从
# old区域淘汰,而不会影响young区域使用比较频繁的page
# 当读扫描不能完全放入buffer pool的大表时,可以设置为较小的值,防止一次读取就会耗费buffer pool很大一部分,例如5%
# 当扫描小表时,在buffer pool内移动页面的开销较小,可以尝试增大,例如50%
innodb_old_blocks_pct = 37

# 第一次被加载到buffer pool的page会放到LRU的old区域的头部,不能刚加载进来就访问了它一次,就把它放到young区域的头部,这不合理
# 所以这个参数是设置一个page被加载进来后,隔了多少毫秒后再次被访问,才会放到LRU young区域的头部
innodb_old_blocks_time = 1000

# redo log刷盘策略,可选值:0,1,2
# 0: 提交事务时,InnoDB不会立即触发将缓存日志写到磁盘文件的操作,每秒会写入到os cache中,并调用fsync刷入磁盘(MySQL或服务器崩溃后会丢失1s数据)
# 1: 每次提交事务时,InnDB会立即将数据写入磁盘中(最安全,服务器或MySQL崩溃后不会丢失数据)
# 2: 提交时写入到os cache中,每秒调用fsync刷新到磁盘中(MySQL崩溃不会丢失数据,服务器崩溃会丢失1s数据)
# 推荐设置为1
innodb_flush_log_at_trx_commit = 1

# 后台线程会定时从LRU链表尾部开始扫描一些页,如果从里面发现脏页,会把它们刷新到磁盘
# innodb_lru_scan_depth是每次扫描的数量
innodb_lru_scan_depth = 1024

# binlog刷盘策略, 可选值:0,n
# 0: 只会将数据写入os cache中,不会调用fsync将binlog刷新到磁盘中,由操作系统决定什么时候进行刷新
# 1: 每次都将binlog同步刷新到磁盘(不会丢失数据)
# 2: 每2次会fsync一次
# 3: 每3次fsync一次 ...
# mysql5.7默认参数为1,
sync_binlog = 1

4.配置环境

centos系统可以配置到~/.bashrc中。mac系统如果用的是zsh可以配置到~/.zprofile

export MYSQL_HOME=/data/mysql-5.7.32-el7-x86_64
export PATH=$MYSQL_HOME/bin:$PATH

将新增的变量信息加载到当前shell

source ~/.bashrc

因为mysql配置文件加载顺序的原因, ~/.my.cnf最后加载。

ln -s /data/mysql-5.7.32-el7-x86_64/etc/my.cnf ~/.my.cnf

5.启动MySQL

5.1 启动MySQL服务器之前,我们先来了解一下bin目录中的执行文件

在MySQL的安装目录下有一个bin目录,里面放着很多可执行文件,并且里面分为了客户端程序和服务器程序

服务器程序
  • mysqld: MySQL后台进程(即MySQL服务器进程)。该进程运行后,客户端才能通过连接服务器来访问数据库(但是我们一般不直接使用mysqld)
  • mysqld_safe: 服务器启动脚本。推荐使用mysqld_safe来启动MySQL服务器,mysqld_safe里面也是调用了mysqld,但是当mysqld异常停止后,mysqld_safe会重启mysqld,还可以将服务器程序的异常信息重定向到日志中,这样可以方便我们找出错误发生的原因。
  • mysql.server: (这个程序其实在support-files目录下,只不过拿到这里一起介绍了),mysql.server里面调用了mysqld_safe,功能比mysqld_safe更强大。mysql.server start这样就可以启动,mysql.server stop这样就可以关闭MySQL服务器。
  • mysql_multi: 服务器启动脚本,可以启动或停止系统上安装的MySQL实例。
  • myisamchk: 用来描述、检查、优化和维护MyISAM表的实用工具。
客户端程序
  • mysql: MySQL客户端命令行工具
  • mysqlaccess: 检查访问主机名、用户名和数据库组合的权限脚本
  • mysqladmin: 执行管理操作的程序,例如创建或删除数据库,重载授权表,将表刷新到硬盘上,以及重新打开日志文件。mysqladmin还可以用来检索版本、进程,以及服务器的状态信息。
  • mysqlbinlog: 将二进制日志读取的工具。在二进制日志文件中包含执行过的语句,可用来帮助系统从崩溃中恢复。
  • mysqldumpslow: 用来分析慢查询日志的工具。
  • mysqlcheck: 检查、修复、分析以及优化表的表维护客户程序。
  • mysqldump: 将mysql数据库转储到一个文件(例如SQL语句或tab分隔符文本文件)的客户程序
  • mysqlhotcopy: 当服务器在运行时,快速备份MyISAM或ISAM表的工具
  • mysqlimport: 使用LOAD DATA INFILE 将文本文件导入相关表的客户程序

5.2 启动mysql服务器

在linux中,MySQL会按照下列路径顺序来寻找配置文件

/etc/my.cnf	
/etc/mysql/my.cnf	
/usr/local/mysql/etc/my.cnf	
$MYSQL_HOME/my.cnf	
~/.my.cnf	
~/.mylogin.cnf	           # (仅限于客户端配置,由mysql_config_editor生成)
启动mysqld

这时候我们就可以启动MySQL了,执行mysqld命令就可以启动mysql,不过一般情况下我们并不直接使用mysqld命令启动mysql,一般会用$MYSQL_HOME/support-files/mysql.server或者mysqld_safe。萌新习惯用mysqld_safe

mysqld_safe --defaults-file=~/.my.cnf &

建议一定要使用--defaults-file参数指定配置文件位置,因为虽然mysql会按照前面说到的顺序搜寻配置文件,后面读到的参数会覆盖前面的参数,不过如果我们自定义的参数没有覆盖到前面的参数,会导致一些我们不想要的参数加进来,可能会发生不符合预期的事情,甚至有一些参数也不能被覆盖。会导致启动mysql出现问题。

对了,执行启动命令后如果没有提示任何错误消息,就代表着启动成功,就像她的不回复,其实也是一种回复。

登录mysql并修改密码(使用刚刚复制的密码登录)

mysql -uroot -p

修改mysql密码

mysql -uroot -p
mysql> set password=password('mengxin');
mysql> flush privileges;

此时mysql默认只能从localhost登录,如果我们在测试环境中想配置成可以允许任意ip访问,需要修改mysql库中的user表的host字段,% 代表允许从任意ip访问。

use mysql;
update user set host='%' where host='root';

配置本机免密登录

mysql_config_editor set -h 127.0.0.1 -P 8906 -u root -p

如果每次使用mysql命令客户端登录mysql都要输入密码的话,可就太麻烦了,但是把密码直接配置到配置文件中又不安全,我们就可以使用mysql_config_editor命令帮助我们记住密码(会生成一个~/.mylogin.cnf文件),还可以使用–login-path参数配置多个数据库地址。

我们一起来看一下mysqld_safe是怎么帮助我们监测mysqld程序的吧
mysqld_safe中定义了一个循环,启动的时候调用了evel_log_error函数,并把启动的参数传给它,并在eval "$cmd"的位置执行mysqld命令后hang在这里,如果程序退出,则会根据pid_file是否存在来判断mysql是否是意外退出,如果是的话则会执行一系列清理工作后重新启动mysql。这样mysqld_safe就可以帮助我们重启意外退出的mysqld进程。

...
eval_log_error () {
  cmd="$1"
  case $logging in
    file)
      if [ -w / -o "$USER" = "root" ]; then
        cmd="$cmd > /dev/null 2>&1"
      else
        cmd="$cmd >> "`shell_quote_string "$err_log"`" 2>&1"
      fi
      ;;
    syslog)
      cmd="$cmd --log-syslog=1 --log-syslog-facility=$syslog_facility '--log-syslog-tag=$syslog_tag' > /dev/null 2>&1"
      ;;
    both)
      if [ -w / -o "$USER" = "root" ]; then
        cmd="$cmd --log-syslog=1 --log-syslog-facility=$syslog_facility '--log-syslog-tag=$syslog_tag' > /dev/null 2>&1"
      else
        cmd="$cmd --log-syslog=1 --log-syslog-facility=$syslog_facility '--log-syslog-tag=$syslog_tag' >> "`shell_quote_string "$err_log"`" 2>&1"
      fi
      ;;
    *)
      echo "Internal program error (non-fatal):" \
           " unknown logging method '$logging'" >&2
      ;;
  esac

  #echo "Running mysqld: [$cmd]"
  eval "$cmd"
}
...
...
while true
do
  start_time=`date +%M%S`

  eval_log_error "$cmd"

  # hypothetical: log was renamed but not
  # flushed yet. we'd recreate it with
  # wrong owner next time we log, so set
  # it up correctly while we can!

  if [ $want_syslog -eq 0 -a ! -f "$err_log" -a ! -h "$err_log" ]; then
    if test -w / -o "$USER" = "root"; then
      logdir=`dirname "$err_log"`
      case $logdir in
        /var/log)
          (
            umask 0137
            set -o noclobber
            > "$err_log" && chown $user "$err_log"
          ) ;;
        *) ;;
      esac
    else
      (
        umask 0137
        set -o noclobber
        > "$err_log"
      )
    fi
  fi

  end_time=`date +%M%S`

  if test ! -f "$pid_file"		# This is removed if normal shutdown
  then
    break
  else                                  # self's mysqld crashed or other's mysqld running
    PID=`cat "$pid_file"`
    if kill -0 $PID > /dev/null 2> /dev/null
    then                                # true when above pid belongs to a running mysqld process
      log_error "A mysqld process with pid=$PID is already running. Aborting!!"
      exit 1
    fi
  fi

  if test -f "$pid_file.shutdown"	# created to signal that it must stop
  then
    log_notice "$pid_file.shutdown present. The server will not restart."
    break
  fi


  # sanity check if time reading is sane and there's sleep
  if test $end_time -gt 0 -a $have_sleep -gt 0
  then
    # throttle down the fast restarts
    if test $end_time -eq $start_time
    then
      fast_restart=`expr $fast_restart + 1`
      if test $fast_restart -ge $max_fast_restarts
      then
        log_notice "The server is respawning too fast. Sleeping for 1 second."
        sleep 1
        sleep_state=$?
        if test $sleep_state -gt 0
        then
          log_notice "The server is respawning too fast and no working sleep command. Turning off trottling."
          have_sleep=0
        fi

        fast_restart=0
      fi
    else
      fast_restart=0
    fi
  fi

  if true && test $KILL_MYSQLD -eq 1
  then
    # Test if one process was hanging.
    # This is only a fix for Linux (running as base 3 mysqld processes)
    # but should work for the rest of the servers.
    # The only thing is ps x => redhat 5 gives warnings when using ps -x.
    # kill -9 is used or the process won't react on the kill.
    numofproces=`ps xaww | grep -v "grep" | grep "$ledir/$MYSQLD\>" | grep -c "pid-file=$pid_file"`

    log_notice "Number of processes running now: $numofproces"
    I=1
    while test "$I" -le "$numofproces"
    do 
      PROC=`ps xaww | grep "$ledir/$MYSQLD\>" | grep -v "grep" | grep "pid-file=$pid_file" | sed -n '$p'` 

      for T in $PROC
      do
        break
      done
      #    echo "TEST $I - $T **"
      if kill -9 $T
      then
        log_error "$MYSQLD process hanging, pid $T - killed"
      else
        break
      fi
      I=`expr $I + 1`
    done
  fi
  if [ ! -h "$pid_file" ]; then
    rm -f "$pid_file"
  fi
  if [ ! -h "$safe_mysql_unix_port" ]; then
    rm -f "$safe_mysql_unix_port"
  fi
  if [ ! -h "$pid_file.shutdown" ]; then
    rm -f "$pid_file.shutdown"
  fi
  log_notice "mysqld restarted"
done

总结

一般新部署的MySQL由于没有数据,大概率不会报错,如果有问题很有可能是配置文件导致的,尤其在测试环境中可能一台服务器不止一个mysql,如果没有指定--defaults-file导致掺杂了一些我们不想要的配置进来,就很可能会有问题,所以启动的时候一定要指定defaults-file。如果依然启动失败,可以查看mysql的error-log。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值