【系统学习】1-MySQL-基础

1-MySQL基础

MySQL基本概念

数据库、数据库管理系统、SQL

image-20231027105815873

举例:数据库(存储数据的仓库);数据库管理系统(MySQL、Oracle等);SQL(操作数据库的语言)

MySQL:关系型数据库

定义:建立在关系模型基础上,由多张相互连接的二维表组成的数据库。

什么是二维表?:由行和列组成的表(类似excel,有表头、有行、有列)

关系型数据库的好处:

  • 使用表存储数据,格式统一,便于维护
  • 使用SQL语言操作,标准统一,使用方便

客户、数据库管理系统、数据库三者关系图

image-20231027110437533

  • 通过客户端【Navicat】连接数据库管理系统(DBMS)【MySQL】,再通过DBMS操作数据库
  • 通过SQL语句实现上述操作【select xx from tb_xx where id = xx
  • 一个数据库服务器可以有多个数据库,一个数据库可以有多个表,一个表可以有多条记录

表字段的数据类型【知识】

参考文章:https://blog.csdn.net/qq_45445505/article/details/137025254

SQL语言

全称:Structured Query Language,结构化查询语言

是操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准

SQL通用语法格式

  • SQL语句可以单行或多行书写,以分号结尾
  • SQL语句可以使用空格/缩进来增强语句的可读性
  • MySQL数据库的SQL语句不区分大小写,关键字建议使用大写
  • 注释方式:
-- 单行注释
# 单行注释

/* 
	多行
	注释
*/

SQL语言分类-4种

image-20231027111222727

SQL-DDL | Data Definition Language

数据定义语言,用来定义数据库对象(数据库、表、字段)

操作数据库

# 查询所有数据库
show databases;

# 创建数据库:[]里面的内容为选写,增加创建数据库时候的补充条件
create database [if not exists] 数据库名 [default charset 字符集] [collate 排序规则];
-- create schema [if not exists] 数据库名 [default charset 字符集] [collate 排序规则];

# 查看创建当前数据库时候的建库SQL语句
show create table 表明;

# 进入【切换】到某个数据库
use 数据库名;

# 查看当前数据库名字
select database();

# 删除数据库
DROP DATABASE [ IF EXISTS ] 数据库名;
字符集utf8、utf8mb4等
引擎InnoDB(MySQL5.5之后的默认引擎)、Memory、MyISAM

操作数据表

# 查询当前数据库的所有表
show tables;

# 创建数据表
CREATE TABLE 表名(
	字段1 字段1类型 [约束] [COMMENT 字段1注释],
	字段2 字段2类型 [约束] [COMMENT 字段2注释],
	字段3 字段3类型 [约束] [COMMENT 字段3注释],
	......
	字段n 字段n类型 [约束] [COMMENT 字段n注释]
) ENGINE=引擎 DEFAULT CHARSET=字符集;[COMMENT 表注释] ;

# 查看指定表
desc 表名;

# 查看创建当前数据表时候的建表SQL语句
show create table 表名;

# 修改数据表名字
ALTER TABLE 表名 RENAME TO 新表名;


# 数据表-添加字段
ALTER TABLE 表名 ADD 字段名 类型 (长度) [ COMMENT 注释 ] [ 约束 ];

# 数据表-修改字段数据类型
ALTER TABLE 表名 MODIFY 字段名 新数据类型 (长度);

# 数据表-修改字段名+数据类型
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型 (长度) [ COMMENT 注释 ] [ 约束 ];

# 数据表-删除字段
ALTER TABLE 表名 DROP 字段名;


# 删除数据表
DROP TABLE [IF EXISTS] 表名;

# 删除数据表,并重新创建该数据表
TRUNCATE TABLE 表名; 

表字段约束

作用于表中字段上的规则,用于限制存储在表中的数据。保证数据库中数据的正确、有效、完整

约束类别

约束描述关键字
非空约束限制该字段的数据不能为nullNOT NULL
唯一约束保证该字段的所有数据都是唯一、不重复的UNIQUE
主键约束主键是一行数据的唯一标识,要求非空且唯一PRIMARY KEY
默认约束保存数据时,如果未指定该字段的值,则采用默认值DEFAULT
检查约束(8.0.16版本之后)保证字段值满足某一个条件CHECK
外键约束用来让两张表的数据之间建立连接,保证数据的一致性和完整性FOREIGN KEY

约束是作用于表中字段上的,可以在创建表/修改表的时候添加约束

约束示例 | 常规约束

CREATE TABLE tb_user(
	id int AUTO_INCREMENT PRIMARY KEY COMMENT 'ID唯一标识',
	name varchar(10) NOT NULL UNIQUE COMMENT '姓名' ,
	age int check (age > 0 && age <= 120) COMMENT '年龄' ,
	statues char(1) default '1' COMMENT '状态',
	gender char(1) COMMENT '性别'
);

上述建表语句解释:

  • id:主键且自动增长
  • name:不为空,并且唯一
  • age:范围为(0, 120]
  • status:默认为1
  • gender:没有特殊情况

约束示例 | 新建外键约束

用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性

通用写法 | 建表时添加外键约束

CREATE TABLE 表名(
	字段名 数据类型,
	...
	[CONSTRAINT] [外键名称] FOREIGN KEY (外键字段名) REFERENCES 主表 (主表列名)
);

-- []:表示可选项;():必须写

通用写法 | 已有表添加外键约束

# 已有数据表,添加外键
ALTER TABLE 表名 ADD CONSTRAINT 自定义外键名称 FOREIGN KEY (外键字段名) REFERENCES 主表 (主表列名) ;

示例

  • 员工表:emp
字段含义
idID
name姓名
age年龄
dept_id所属部门id
  • 部门表:dept
字段含义
idID
name部门名称
  • 解释:

    • 为员工表的dept_id字段添加外键约束,关联部门表的主键id

    • dept_id就是外键

    • 带有外键的表,emp,就是子表;另外一个表是父表

  • 添加约束

alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id);

约束示例 | 删除外键约束

基本语法

ALTER TABLE 表名 DROP FOREIGN KEY 自定义外键名称;

删除上述中的外键

# 删除外键约束
alter table emp drop foreign key fk_emp_dept_id;

表字段约束 | 父表删除/更新行为

添加外键之后,删除父表数据时产生约束的行为,就称为删除/更新行为

行为类别

行为说明
NO ACTION当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 (与 RESTRICT 一致) 默认行为
RESTRICT当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 (与 NO ACTION 一致) 默认行为
CASCADE当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也删除/更新外键在子表中的记录
SET NULL当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键值为null(这就要求该外键允许取null)
SET DEFAULT父表有变更时,子表将外键列设置成一个默认的值 (Innodb不支持)

SQL语法

ALTER TABLE 子表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段) REFERENCES 父表名 (父表字段名) ON UPDATE CASCADE ON DELETE CASCADE;

SQL-DML | Data Manipulation Language

数据操作语言,用来对数据库中表的数据记录进行增、删、改操作

添加数据

# 添加表数据--单行--指定字段
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (1,2, ...);

# 添加表数据--单行--全部字段
INSERT INTO 表名 VALUES (1,2, ...);

# 添加表数据--批量--指定字段
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (1,2, ...), (1,2, ...), (1,2, ...);

# 添加表数据--批量--全部字段
INSERT INTO 表名 VALUES (1,2, ...), (1,2, ...), (1,2, ...);

修改数据

# 修改表数据
UPDATE 表名 SET 字段名1 =1 , 字段名2 =2 , .... [ WHERE 条件 ];

删除数据

# 删除表数据
DELETE FROM 表名 [ WHERE 条件 ] ;

没有条件,默认处理全部表数据!!!

SQL-DQL | Data Query Language

数据查询语言,用来查询数据库中表的记录

基础查询 | 不带查询条件

# 查询多个字段
SELECT 字段1, 字段2, 字段3 ... FROM 表名;

# 查询所有字段
SELECT * FROM 表名 ;

# 查询字段并设置别名(写不写as都一样)
SELECT 字段1 [ AS 别名1 ] , 字段2 [ AS 别名2 ] ... FROM 表名;
SELECT 字段1 [ 别名1 ] , 字段2 [ 别名2 ] ... FROM 表名;

# 去重查询
SELECT DISTINCT 字段列表 FROM 表名;

基础查询 | 带有查询条件

常用比较运算符

比较运算符写法功能
>、>=、<、<=、=WHERE id > 10大于、大于等于、小于、小于等于、等于
<> 或者 !=WHERE id <> 10不等于
BETWEEN … AND …WHERE id BETWEEN 10 AND 100在某个范围之内。含最小、最大值,是个闭区间
IN(…)WHERE id in (10, 12, 14)在in之后的列表中的值,多选一
NOT IN(…)WHERE id NOT IN (1, 5, 9)返回值不在列表内的行
LIKE 占位符WHERE id LikE _ABC模糊匹配:_匹配单个字符, %匹配任意个字符)
IS NULLWHERE id IS NULL判断是否是NULL
IS NOT NULLWHERE id IS NOT NULL判断是否不是NULL

上述部分语句解析:

  • WHERE id LikE _ABC 返回以ABC为结尾,且整体长度为4的数据,例如:1ABC、AABC、ABABC(这个不是,长度不满足)

常用逻辑运算符

常用逻辑运算符功能
AND 或者 &&并且
OR 或者 ||或者
NOT 或者 !非,不是

示例

# 基础语法
SELECT 字段列表 FROM 表名 WHERE 条件列表;

# 示例--占位符
select * from emp where name like '__';  		# 查询姓名为两个字的员工
select * from emp where idcard like '%X';		# 查询身份证结尾为X的员工
select * from emp where idcard like '_________________X';		# 查询身份证结尾为X的员工

聚合查询 | 聚合函数

聚合查询:以一列数据为整体,进行纵向查询

任何值为Null的字段数据,都不参与聚合查询

函数功能
count(id)统计id列的数量
max(salary)返回salary列的最大值
min(salary)返回salary列的最小值
avg(salary)返回salary列的平均值
sum(salary)返回salary列的总和
# 基础语法
SELECT 聚合函数(字段列表) FROM 表名;

聚合查询 | 分组查询

基础语法

# 通用语法
SELECT 字段列表 FROM 表名 [ WHERE 分组前筛选条件 ] GROUP BY 分组字段名 [ HAVING 分组后过滤条件 ];

where和having的区别

  • 执行时机:where在分组前执行;having在分组后执行
  • 判断条件:where不能对聚合函数进行判断【】,having可以

执行顺序

  • where > 聚合函数 > having

示例

# 根据性别分组, 统计男性员工 和 女性员工的数量
select gender, count(*) from emp group by gender;

# 根据性别分组 , 统计男性员工 和 女性员工的平均年龄
select gender, avg(age) from emp group by gender;

# 查询年龄小于45的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址
select workaddress, count(*) AS address_count from emp where age < 45 group by workaddress having address_count >= 3;  # AS可省略

# 示例:返回每个role角色下,所有人的薪水总和,然后根据role分组,筛选总和大于1500的结果
select role, sum(salary) as totle from emp group by role having totle > 1500;

排序查询

基础语法

SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1 , 字段2 排序方式2;
排序
ASC升序,默认的方式
DESC降序

多字段排序,当第一个字段一样时候,才会根据第二个字段排序,后续字段排序同理

示例

# 根据年龄对公司的员工进行升序排序 , 年龄相同 , 再按照入职时间进行降序排序
select * from emp order by age, entrydate desc;

分页查询

基础语法

SELECT 字段列表 FROM 表名 LIMIT 起始索引, 查询记录数;
  • 分页查询算是数据库的方言,MySQL中使用的是LIMIT
  • 起始索引 = (待查询页码-1)*每页记录数
  • 第一页的数据,可以简写:xxx LIMIT 10

多表查询:联合查询、子查询【重要】

参考文章:https://blog.csdn.net/qq_45445505/article/details/137051199

SQL语句编写和执行顺序

编写顺序

SELECT  字段列表

FROM 表名列表

WHERE 条件列表

GROUP BY 分段字段列表

HAVING 分组后条件列表

ORDER BY 排序字段列表

LIMIT 分页参数

执行顺序

FROM 表名列表

WHERE 条件列表

GROUP BY 分段字段列表

HAVING 分组后条件列表

SELECT  字段列表

ORDER BY 排序字段列表

LIMIT 分页参数

SQL-DCL | Data Control Language

数据控制语言,用来管理数据库用户、控制数据库的访问权限

管理用户

# 查询用户
select * from mysql.user;

image-20231027164419497

  • Host代表当前用户访问的主机:localhost代表只能本机访问,不可以远程访问;若改为%,表示任意ip可访问该数据库
  • User代表访问该数据库的用户名:root是默认用户;可以新建自定义的用户
  • MySQL中,需要通过Host、User来唯一标识一个用户
# 创建用户
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';

# 修改用户密码
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';

# 删除用户
DROP USER '用户名'@'主机名';

权限控制

权限列表说明
ALL、ALL PRIVILEGES所有权限
SELECT查询数据
INSERT插入数据
UPDATE修改数据
DELETE删除数据
ALTER修改表
DROP删除数据库、表、视图
CREATE创建数据库、表
# 查询权限
SHOW GRANTS FOR '用户名'@'主机名' ;

# 授予权限
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';

# 撤销权限
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';
# 查询 'heima'@'%' 用户的权限
show grants for 'heima'@'%';

# 授予 'heima'@'%' 用户itcast数据库所有表的所有操作权限
grant all on itcast.* to 'heima'@'%';

# 撤销 'heima'@'%' 用户的itcast数据库的所有权限
revoke all on itcast.* from 'heima'@'%';
  • 用*号表示通配符,表示对数据库的所有表格赋予权限

表字段 | 处理函数

字符串函数 | 处理字符串类型数据

常见字符串函数功能
CONCAT(S1,S2,...Sn)将S1、S2、Sn拼接成一个字符串
LOWER(str)将字符串str转为小写
UPPER(str)将字符串str转为大写
LPAD(str,n,pad)左填充:用pad对字符串str进行填充,使其达到n位
RPAD(str,n,pad)RPAD(str,n,pad)右填充:用pad对字符串str进行填充,使其达到n位
TRIM(str)去掉字符串str头部和尾部的空格
SUBSTRING(str,start,len)截取字符串:从start位置开始,截取长度为len
# 员工id变更,五位字符表示,前边补零
update emp set workno = lpad(workno, 5, '0');

数值函数 | 处理数值类型数据

函数功能
CEIL(x)向上取整
FLOOR(x)向下取整
MOD(x,y)返回x/y的模
RAND()返回0-1内的随机数
ROUND(x,y)求x四舍五入的值,保留y位小数
# 通过数据库的函数,生成一个六位数的随机验证码
select lpad(round(rand()*1000000 , 0), 6, '0');

日期函数 | 处理日期类型数据

函数功能
CURDATE()返回当前日期
CURTIME()返回当前时间
NOW()返回当前的日期和时间
YEAR(date)获取指定date的年份
MONTH(date)获取指定date的月份
DAY(date)获取指定date的日期
DATE_ADD(date, INTERVAL expr type)返回一个日期/时间值 加上一个时间间隔expr后的时间值
DATEDIFF(date1,date2)返回date1和date2之间的天数
# date_add:增加指定的时间间隔
select date_add(now(), INTERVAL 70 YEAR);

# 查询所有员工的入职天数,并根据入职天数倒序排序。
select name, datediff(curdate(), entrydate) as 'entrydays' from emp order by entrydays desc;

流程函数

函数功能
IF(value , t , f)如果value为true,则返回t,否则返回f
IFNULL(value1 , value2)如果value1不为空,返回value1,否则返回value2
CASE WHEN [ val1 ] THEN [res1] …ELSE [ default ] END如果val1为true,返回res1,… 否则返回default默认值
CASE [ expr ] WHEN [ val1 ] THEN [res1] … ELSE [ default ] END如果expr的值等于val1,返回res1,… 否则返回default默认值
select
	name,
	( case workaddress when '北京' then '一线城市' when '上海' then '一线城市' else '二线城市' end ) as '工作地址'
from emp;

MySQL事务

基本概念

概念 | 什么是事务?

事务是一组操作的结合,他是一个不可分割的工作单位。事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求。

即:这些操作要么都成功,要么都失败

概念 | 隐式事务和显式事务

事务有两种:隐式事务、显式事务

MySQL默认是隐式事务,即:执行insert、update、delete操作的时候,数据库自动开启、提交或回滚事务

改变默认的事务方式:设置autocommit的值

# 显示变量
show variables like 'autocommit';

# 关闭隐式事务
set autocommit=0;

# 开启隐式事务
set autocommit=1;

概念 | 事务的四大特性ACID

原子性(Atomicity)

事务是不可分割的最小操作单元,要么全部成功,要么全部失败

一致性(Consistency)

事务完成时,必须使所有的数据都保持一致状态。这个一致是语义上的一致,而不是语法上的一致。

比如:A转账100给B,A的账户钱少100,B的账户钱多100。在转账这个事务开启前,两者的账户余额正确,数据保持一致性。转账后,两者的账户状态语义上也正确,即:转账的人账户金额-100;收款的人账户金额+100。

隔离性(Isolation)

数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。即并发状态下,各个事物之间相互不干扰。

持久性(Durability)

事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。

概念 | savepoint关键字

我们在进行事务操作的时候出现错误,不想回滚所有操作,只想回滚最后某部分操作,就可以借助该关键字。

具体示例看下边:【事务示例:账户转账】

事务示例:账户转账

数据准备

drop table if exists account;

create table account(
	id int primary key AUTO_INCREMENT comment 'ID',
	name varchar(10) comment '姓名',
	money double(10,2) comment '余额'
) comment '账户表';

insert into account(name, money) VALUES ('张三',2000), ('李四',2000);

未控制事务 | 转账正常

-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';

所有SQL正常执行,没有出错

未控制事务 | 异常情况

-- 1. 查询张三余额
select * from account where name = '张三';
-- 2. 张三的余额减少1000
update account set money = money - 1000 where name = '张三';
人工写一个错误,这行字就是一个错误,下边代码就不会执行....
-- 3. 李四的余额增加1000
update account set money = money + 1000 where name = '李四';

只有前两个SQL执行了,第三个SQL没有执行,出现数据不一致了

控制事务 | 示例

mysql> START TRANSACTION;													# 开启事务
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account where name = '张三';		  					   # 展示张三账户金额
+----+--------+---------+
| id | name   | money   |
+----+--------+---------+
|  1 | 张三   | 2000.00 |
+----+--------+---------+
1 row in set (0.00 sec)

mysql> update account set money = money - 1000 where name = '张三';			# 将张三账户金额减少1000
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update account set money = money + 1000 where name = '李四';			# 将李四账户金额增加1000
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from account where name = '张三';				# 查询张三账户金额(在事务里看,金额确实少了。但是数据库里面账户值还没变)
+----+--------+---------+
| id | name   | money   |
+----+--------+---------+
|  1 | 张三   | 1000.00 |
+----+--------+---------+
1 row in set (0.00 sec)

mysql> COMMIT;									# 上述操作均成功,提交事务,修改生效。若某一操作失败,需要回滚,COMMIT改为ROLLBACK
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account where name = '张三';
+----+--------+---------+
| id | name   | money   |
+----+--------+---------+
|  1 | 张三   | 1000.00 |
+----+--------+---------+
1 row in set (0.00 sec)

上述操作过程大致三个步骤:开启事务、执行一组SQL语句、提交或回滚事务。

针对开启事务这一步,有如下几种方式:

# 方式1:关闭隐式事务
SELECT @@autocommit;
SET @@autocommit = 0;

# 方式2:手动开启事务
START TRANSACTION;

# 方式3:手动开启事务-另一种
BEGIN;

针对提交或回滚事务这一步,是看上数SQL操作是否都成功。若都成功,则提交;若有失败,则回滚,使数据恢复到修改前的状态:

COMMIT;   # 若SQL语句执行正常,提交事务

ROLLBACK; # 若SQL语句有执行异常,回滚事务

若是要用一个sql脚本来处理一组事务,则应该在提交或者回滚这一步加上判断条件:

# 开始事务
BEGIN;

#执行一组SQL
xxxxxx

# 提交或回滚
if(所有SQL执行成功) THEN
	COMMIT;
ELSE
	ROLLBACK;
END IF;

控制事务 | savepoint

savepoint关键字可以使得回滚事务的时候只混滚部分代码处理的结果。

如下,是关于savepoint的使用示例:

# 开启事务
xxx

# 一组SQL
xxx操作1
xxx操作2
SAVEPOINT change1;
xxx查询操作1
xxx查询操作2,出问题报错了

# 因为修改操作都完成了,在查询结果是否正确的时候出了错误,就可以通过这样,只回滚change1到ROLLBACK TO change1之间的代码
ROLLBACK TO change1;

# ROLLBACK如果不加TO,就会回滚到初始位置,不管是否有savepoint
# 若是不想要某个savepoint点,可以删除
RELEASE SAVEPOINT change1;

并发事务存在的问题

数据读问题

赃读

描述:一个事务读到另外一个事务还没有提交的数据后,数据被另一个事务回滚,导致读到的数据无效

不可重复读

描述:一个事务先后读取同一条记录,但两次读取的数据不同,可能的原因是:该数据被另一个事务修改并提交

幻读

描述:在一个事务中,多次查询时,结果集的行数不一致,看起来像是出了“幻影”的行,主要原因是别的事务进行了新增或删除操作导致。

数据更新问题

第一类数据更新

描述:事务A撤销时候,覆盖了已经提交的事务B更新后的数据

第二类数据更新

描述:事务A提交的时候,覆盖了事务B已经提交的数据,造成事务B所做操作丢失

解决方案

为了解决这些并发事务问题,需要使用适当的并发控制机制,例如事务隔离级别、锁机制、并发控制算法等。

通过合理的并发控制,可以保证事务的一致性、隔离性和并发性,避免数据的不一致和冲突。

事务隔离

什么是事务隔离?

事务隔离就是为了解决并发事务存在的问题

隔离级别 | 4种

隔离级别是否避免脏读是否避免不可重复读是否避免幻读
READ UNCOMMITTED,读未提交
READ COMMITTED,读提交×
REPEATABLE READ(MySQL默认隔离级别),可重复读××
SERIALIZABLE,串行化读×××

隔离级别从上到下,越来越高。隔离级别越高,数据越安全,性能越低。

隔离级别设置

# 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;

# 设置事务级别
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
  • SESSION:表示修改仅对本次会话的配置有效
  • GLOBAL:表示修改全局有效
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值