MySQL表的约束(五)

表的约束:表中一定要有各种约束,通过约束,让我们未来插入数据库表中的数据是符合预期的。

约束的本质是通过技术手段,倒逼程序员,插入正确的数据。反过来,站在mysql视角,凡是插入进来的数据,都是符合数据约束的。
约束的最终目标:保证数据的完整性和可预期性。

表的约束很多,这里主要介绍如下几个: null/not null,default, comment, zerofill,primary

key,auto_increment,unique key 。

空属性null

两个值:null(默认的)和not null(不为空)

数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法参与运算。

c 复制代码
mysql> create table myclass(
    -> class_name varchar(20) not null,
    -> class_room varchar(10) not null);
Query OK, 0 rows affected (0.49 sec)

mysql> desc myclass;
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| class_name | varchar(20) | NO   |     | NULL    |       |
| class_room | varchar(10) | NO   |     | NULL    |       |
+------------+-------------+------+-----+---------+-------+
2 rows in set (0.02 sec)

插入数据

c 复制代码
mysql> insert into myclass (class_name,class_room) values('高三二班','101');
Query OK, 1 row affected (0.02 sec)

在不允许为空的地方不插入数据,会报错!

c 复制代码
mysql> insert into myclass (class_name) values('高三二班');
ERROR 1364 (HY000): Field 'class_room' doesn't have a default value

默认值default

default:如果设置了,用户将来插入,有具体的数据,就用用户的,没有就用默认的。

c 复制代码
mysql> create table member(
    -> name varchar(20) not null,
    -> age tinyint unsigned default 0,
    -> sex char(2) default '男'
    -> );
Query OK, 0 rows affected (0.07 sec)

mysql> desc member
    -> ;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| name  | varchar(20)      | NO   |     | NULL    |       |
| age   | tinyint unsigned | YES  |     | 0       |       |
| sex   | char(2)          | YES  |     | 男      |       |
+-------+------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

插入数据

c 复制代码
mysql> insert into member(name) values(('张三');
Query OK, 1 row affected (0.02 sec)

mysql> select * from member;
+--------+------+------+
| name   | age  | sex  |
+--------+------+------+
| 张三   |    0 | 男   |
+--------+------+------+
1 row in set (0.00 sec)

数据在插入的时候不给该字段赋值,就使用默认值

not null default联合使用的情况

c 复制代码
mysql> create table member1 (
    -> name varchar(20) not null,
    -> age tinyint unsigned default 0,
    -> sex char(2) not null default '男' --注意这里
    -> );
Query OK, 0 rows affected (0.08 sec)

mysql> desc member1;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| name  | varchar(20)      | NO   |     | NULL    |       |
| age   | tinyint unsigned | YES  |     | 0       |       |
| sex   | char(2)          | NO   |     | 男      |       |
+-------+------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

关于第三个元素sex插入,这里设置为not null default '男',如何理解?

  • 如果填值,那么符合not null通过,
  • 如果填null,那么不符合not null不通过,
  • 如果不填值 ,这时候与not null无关了,看default
    • 如果设定了default,那么按default的值来走
    • 如果没有设定default,那么实际上默认填null,进而与not null违背,不通过

总结:defaultnot null不冲突,而是相互补充的。

例子:

c 复制代码
mysql> insert into member1(name,age,sex) values('张三',18,'男');
Query OK, 1 row affected (0.01 sec)

mysql> insert into member1(name,age,sex) values('张三',18,null);
ERROR 1048 (23000): Column 'sex' cannot be null

mysql> insert into member1(name,age) values('张三',18);
Query OK, 1 row affected (0.02 sec)

注意:not nulldefalut一般不需要同时出现,因为default本身有默认值,不会为空。这样做的话,很大程度上导致not null没什么作用。


对于既不设置not null也不设置default的情况

c 复制代码
mysql> create table member2(
    -> name varchar(20));
Query OK, 0 rows affected (0.07 sec)

实际上编译器进行了优化,默认带上default null

c 复制代码
mysql> show create table member2\G
*************************** 1. row ***************************
       Table: member2
Create Table: CREATE TABLE `member2` (
  `name` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL -- 默认设置NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)

所以我们不插入任何数据时,默认填null

列描述

列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员进行了解。

可以理解为一种注释。

c 复制代码
mysql> create table member3(
-> name varchar(20) not null comment '姓名',
-> age tinyint unsigned default 0 comment '年龄',
-> sex char(2) default '男' comment '性别'
-> );

通过desc查看不到注释信息。

c 复制代码
mysql> desc tt12;
+-------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL |  |
| age | tinyint(3) unsigned | YES | | 0 |  |
| sex | char(2) | YES | | 男 |  |
+-------+---------------------+------+-----+---------+-------+

通过show可以看到

c 复制代码
mysql> show create table tt12\G
*************************** 1. row ***************************
Table: tt12
Create Table: CREATE TABLE `tt12` (
`name` varchar(20) NOT NULL COMMENT '姓名',
`age` tinyint(3) unsigned DEFAULT '0' COMMENT '年龄',
`sex` char(2) DEFAULT '男' COMMENT '性别'
) ENGINE=MyISAM DEFAULT CHARSET=gbk
1 row in set (0.00 sec)

zerofill

c 复制代码
mysql> create table t1(
    -> a int unsigned not null,
    -> b int unsigned not null);
Query OK, 0 rows affected (0.08 sec)

mysql> desc t1;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| a     | int unsigned | NO   |     | NULL    |       |
| b     | int unsigned | NO   |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.02 sec)

mysql> show create table t1 \G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `a` int(10) unsigned NOT NULL,----后面的数字10是什么意思?
  `b` int(10) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.01 sec)
c 复制代码
mysql> alter table t1 modify b int unsigned zerofill;---添加zerofill字段
Query OK, 0 rows affected, 1 warning (0.21 sec)
Records: 0  Duplicates: 0  Warnings: 1

mysql> desc t1;
+-------+---------------------------+------+-----+---------+-------+
| Field | Type                      | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| a     | int unsigned              | NO   |     | NULL    |       |
| b     | int(10) unsigned zerofill | YES  |     | NULL    |       |
+-------+---------------------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> select * from t1;
+---+------------+
| a | b          |
+---+------------+
| 1 | 0000000002 |
+---+------------+
1 row in set (0.00 sec)

这里b的值由2变成0000000002(共十位数),这是zerofill属性的结果,如果宽度小于设定宽度(这里设置是10),自动填充0.

注:这里只是显示结果,在mysql中实际存储的还是1,设置zerofill属性,只是一种格式化输出而已。

例子:

c 复制代码
mysql> alter table t1 modify b int(4) unsigned zerofill;
Query OK, 0 rows affected, 2 warnings (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 2

mysql> desc t1;
+-------+--------------------------+------+-----+---------+-------+
| Field | Type                     | Null | Key | Default | Extra |
+-------+--------------------------+------+-----+---------+-------+
| a     | int unsigned             | NO   |     | NULL    |       |
| b     | int(4) unsigned zerofill | YES  |     | NULL    |       |
+-------+--------------------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> insert into t1 values(1,1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into t1 values(1,11);
Query OK, 1 row affected (0.01 sec)

mysql> insert into t1 values(1,111);
Query OK, 1 row affected (0.01 sec)

mysql> insert into t1 values(1,1111);
Query OK, 1 row affected (0.01 sec)

mysql> insert into t1 values(1,11111);
Query OK, 1 row affected (0.01 sec)

mysql> insert into t1 values(1,111111);
Query OK, 1 row affected (0.02 sec)

mysql> select * from t1;
+---+--------+
| a | b      |
+---+--------+
| 1 |   0002 |
| 1 |   0001 |
| 1 |   0011 |
| 1 |   0111 |
| 1 |   1111 |
| 1 |  11111 |
| 1 | 111111 |
+---+--------+
7 rows in set (0.00 sec)

如上看出,不够四位的补够四位(前面加0),超过四位的不用管,正常输出。

关于zerofill中类型的默认值?

为什么一开始zerofill的默认位数是10,11?

c 复制代码
mysql> show create table t1 \G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `a` int(11) NOT NULL,----为什么一开始是int(11)
  `b` int(10) unsigned NOT NULL----为什么一开始是int(10)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.01 sec)

实际上对于unsigned int最大能存 2 31 − 1 = 2147483647 2^{31}-1 = 2147483647 231−1=2147483647就是10位数,默认是10就是因为int最大值是10位数的原因,而对于有符号的int,多了一个符号位,所以默认是11。

主键

主键:primary key用来唯一的约束该字段里面的数据,不能重复不能为空一张表中最多只能有一个主键 ;主键所在的列通常是整数类型

c 复制代码
mysql> create table t2(
    -> id int unsigned primary key comment '学号不能为空',
    -> name varchar(20) not null);
Query OK, 0 rows affected (0.06 sec)

mysql> desc t2;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | int unsigned | NO   | PRI | NULL    |       |
| name  | varchar(20)  | NO   |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> show create table t2 \G;
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `id` int unsigned NOT NULL COMMENT '学号不能为空',
  `name` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`) --- 存的有点不一样
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)

插入数据

主键约束:主键对应的字段中不能重复,一旦重复,操作失败。

c 复制代码
mysql> insert into t2 values (1,'张飞');
Query OK, 1 row affected (0.01 sec)

主键约束:主键对应的字段中不能重复,一旦重复,操作失败。
mysql> insert into t2 values (1,'刘备');
ERROR 1062 (23000): Duplicate entry '1' for key 't2.PRIMARY'

删除主键

c 复制代码
alter table 表名 drop primary key;

例子:

c 复制代码
mysql> alter table t2 drop primary key;
Query OK, 1 row affected (0.17 sec)
Records: 1  Duplicates: 0  Warnings: 0

追加主键

没有主键的时候,可以追加主键。

c 复制代码
alter table 表名 add primary key(字段列表)

例子:

c 复制代码
mysql> alter table t2 add primary key(name);
Query OK, 0 rows affected (0.27 sec)
Records: 0  Duplicates: 0  Warnings: 0

复合主键

一张表中最多只能有一个主键,但是不意味着一个表中的主键只能添加给一列。

一个主键可以被添加到一列,或者多列上(复合主键)。

c 复制代码
mysql> create table tt14(
-> id int unsigned,
-> course char(10) comment '课程代码',
-> score tinyint unsigned default 60 comment '成绩',
-> primary key(id, course) ------ id和course为复合主键
-> );
Query OK, 0 rows affected (0.01 sec)

mysql> desc t3;
+--------+------------------+------+-----+---------+-------+
| Field  | Type             | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id     | int unsigned     | NO   | PRI | NULL    |       |
| course | char(10)         | NO   | PRI | NULL    |       |
| score  | tinyint unsigned | YES  |     | 60      |       |
+--------+------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
c 复制代码
mysql> insert into tt14 (id,course)values(1, '123');
Query OK, 1 row affected (0.02 sec)

mysql> insert into tt14 (id,course)values(1, '123');
ERROR 1062 (23000): Duplicate entry '1-123' for key 'PRIMARY' -- 主键冲突

mysql> insert into t3 (id,course)values(2, '123');---后面一样也是可以插入的
Query OK, 1 row affected (0.00 sec)

主键本质上是吧两个字段合成一个字段,所以这两个字段填充时有一个不一样,就可以插入。

自增长

auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键

自增长的特点:

  • 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
  • 自增长字段必须是整数
  • 一张表最多只能有一个自增长

建表,其中id字段设置为自增长

c 复制代码
mysql> create table t4(
    -> id int unsigned primary key auto_increment,---自增长
    -> name varchar(20) not null
    -> );
Query OK, 0 rows affected (0.05 sec)

mysql> show create table t4 \G;
*************************** 1. row ***************************
       Table: t4
Create Table: CREATE TABLE `t4` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)

插入数据

c 复制代码
mysql> insert into t4(name) values('a');
Query OK, 1 row affected (0.02 sec)

mysql> insert into t4(name) values('b');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t4(name) values('c');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t4;
+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | b    |  --自增长
|  3 | c    |
+----+------+
3 rows in set (0.00 sec)
c 复制代码
mysql> insert into t4(id, name) values(1000,'c');---插入1000后下一次自增从哪开始?
Query OK, 1 row affected (0.01 sec)

mysql> insert into t4(name) values('d');
Query OK, 1 row affected (0.01 sec)

mysql> select * from t4;
+------+------+
| id   | name |
+------+------+
|    1 | a    |
|    2 | b    |
|    3 | c    |
| 1000 | c    |
| 1001 | d    |--默认是最后一次插入的id值开始自增
+------+------+
5 rows in set (0.00 sec)

实际上AUTO_INCREMENT=1002储存着最后一次插入的AUTO_INCREMENT

c 复制代码
mysql> show create table t4 \G;
*************************** 1. row ***************************
       Table: t4
Create Table: CREATE TABLE `t4` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1002 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 
1 row in set (0.00 sec)

实际上在建表上可以手动设置初始的auto_increment

c 复制代码
mysql> create table t5(
    -> id int unsigned primary key auto_increment,
    -> name varchar(20) not null
    -> )auto_increment=500; ------手动设置初始的auto_increment值
Query OK, 0 rows affected (0.07 sec)

mysql> show create table t5 \G;
*************************** 1. row ***************************
       Table: t5
Create Table: CREATE TABLE `t5` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=500 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)

获取最后一条记录的 AUTO_INCREMENT 的值

c 复制代码
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|             1001 |
+------------------+
1 row in set (0.00 sec)

唯一键

一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键唯一键就可以解决表中有多个字段需要唯一性约束的问题。

唯一键的本质和主键差不多,唯一键允许为空,而且可以多个为空 ,空字段不做唯一性比较。
关于唯一键和主键的区别

我们可以简单理解成,主键更多的是标识唯一性的。而唯一键更多的是保证在业务上,不要和别的信息出现重复。

c 复制代码
mysql> create table stu(
    -> id char(20) unique comment '这是一个学生的唯一键',
    -> name varchar(32) not null);
    
mysql> desc stu;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | char(20)    | YES  | UNI | NULL    |       |
| name  | varchar(32) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

插入数据

c 复制代码
mysql> insert into stu(id,name) values('12345','张三');
Query OK, 1 row affected (0.01 sec)

mysql> insert into stu(id,name) values('12345','李四');
ERROR 1062 (23000): Duplicate entry '12345' for key 'stu.id'

mysql> insert into stu(id,name) values(NULL,'李四');
Query OK, 1 row affected (0.01 sec)

mysql> insert into stu(id,name) values(NULL,'李四');
Query OK, 1 row affected (0.01 sec)

mysql> insert into stu(id,name) values(NULL,'李四');
Query OK, 1 row affected (0.01 sec)

mysql> select * from stu;
+-------+--------+
| id    | name   |
+-------+--------+
| 12345 | 张三   |
| NULL  | 李四   |
| NULL  | 李四   |
| NULL  | 李四   |
+-------+--------+
4 rows in set (0.00 sec)

本质区别:唯一键允许为空,而且可以多个为空,而主键不允许为空。

外键

外键用于定义主表和从表之间的关系外键约束 主要定义在从表 上,主表 则必须是有主键约束unique约束 。当定义外键后,要求外键列数据必须在主表的主键列存在或为null。

语法:

c 复制代码
foreign key (字段名) references 主表(列)

创建主表,班级表

c 复制代码
mysql> create table myclass (
    -> id int primary key,
    -> name varchar(30) not null comment'班级名'
    -> );
Query OK, 0 rows affected (0.07 sec)

mysql> desc myclass;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int         | NO   | PRI | NULL    |       |
| name  | varchar(30) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

向主表中插入班级数据

c 复制代码
mysql> insert into myclass values (1,'计科1班');
Query OK, 1 row affected (0.02 sec)

mysql> insert into myclass values (2,'计科2班');
Query OK, 1 row affected (0.01 sec)

mysql> select * from myclass;
+----+------------+
| id | name       |
+----+------------+
|  1 | 计科1班    |
|  2 | 计科2班    |
+----+------------+
2 rows in set (0.00 sec)

创建从表,学生表

将class_id与myclass建立外键约束

cpp 复制代码
mysql> create table stu (
    -> id int primary key,
    -> name varchar(30) not null comment '学生名',
    -> class_id int,
    -> foreign key (class_id) references myclass(id) -- 插入外键
    -> );
Query OK, 0 rows affected (0.08 sec)

mysql> desc stu;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int         | NO   | PRI | NULL    |       |
| name     | varchar(30) | NO   |     | NULL    |       |
| class_id | int         | YES  | MUL | NULL    |       |
+----------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

向从表中插入学生数据

c 复制代码
mysql> insert into stu(id,name,class_id) values (1,'张三',1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into stu(id,name,class_id) values (2,'李四',1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into stu(id,name,class_id) values (3,'王五',1);
Query OK, 1 row affected (0.01 sec)

mysql> insert into stu(id,name,class_id) values (4,'赵六',2);
Query OK, 1 row affected (0.00 sec)

mysql> select * from stu;
+----+--------+----------+
| id | name   | class_id |
+----+--------+----------+
|  1 | 张三   |        1 |
|  2 | 李四   |        1 |
|  3 | 王五   |        1 |
|  4 | 赵六   |        2 |
+----+--------+----------+
4 rows in set (0.00 sec)

因为有外键约束的存在,插入一个班级为3班的学生,会出错

c 复制代码
mysql> insert into stu(id,name,class_id) values (5,'小明',3);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test1`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `myclass` (`id`))

同样地,删除主表中的一个班级,是不允许的,原因是从表中有学生class_id通过外键约束该班级。

c 复制代码
mysql> delete from myclass where id = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test1`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `myclass` (`id`))
相关推荐
2501_915918412 小时前
Wireshark、Fiddler、Charles抓包工具详细使用指南
android·ios·小程序·https·uni-app·iphone·webview
zbguolei2 小时前
MySQL不兼容的字符集排序规则(collation)导致报错
数据库·mysql
aaa最北边2 小时前
进程间通信-1.管道通信
android·java·服务器
WangYaolove13143 小时前
基于Python的登录网站验证码的生成与识别系统(源码+文档)
python·mysql·django·毕业设计·源码
灰灰勇闯IT3 小时前
【Flutter for OpenHarmony--Dart 入门日记】第3篇:基础数据类型全解析——String、数字与布尔值
android·java·开发语言
2501_944521593 小时前
Flutter for OpenHarmony 微动漫App实战:底部导航实现
android·开发语言·前端·javascript·redis·flutter·ecmascript
氦客3 小时前
Android Compose : 仿IOS风格BottomSheet关闭效果:滑动到顶部,再次滑动才关闭
android·compose·bottomsheet·仿ios风格·底部弹框·滑动到顶部·再次滑动才关闭
COSMOS_*11 小时前
2025最新版 Android Studio安装及组件配置(SDK、JDK、Gradle)
android·ide·jdk·gitee·android studio
jian1105812 小时前
android studio Profiler性能优化,查看内存泄漏
android·性能优化·android studio