Junit单元测试
- 黑盒测试:不需要写代码、给输入值、看程序能否输出期望的值
- 白盒测试需要写代码、关注程序的具体执行流程(Junit测试就是白盒测试的一种)
Junit的使用
- 定义一个测试类(测试用例)
- 定义测试方法:可以独立运行
- 给方法加注解@Test
- 判定结果
计算器类
package com.junit;
//计算器类
public class Calculator {
//加法
public int add(int a,int b){
return a+b;
}
//减法
public int sub(int a,int b){
return a-b;
}
}
测试类
package com.test;
import com.junit.Calculator;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class CalculatorTest {
//初始化方法、所有测试方法在执行前都会先执行此方法
@Before
public void init(){
System.out.println("init,,,,,,");
}
//释放资源、在所有方法执行完后、都会自动执行该方法
@After
public void close(){
System.out.println("after,,,,");
}
//测试add方法
@Test
public void testAdd(){
//1、创建计算器对象
Calculator c=new Calculator();
//2、调用add方法
int result1= c.add(1,5);
//System.out.println(result1);
//3、断言
Assert.assertEquals(6,result1);
}
//测试sub方法
@Test
public void testSub(){
//1、创建计算器对象
Calculator c=new Calculator();
//2、调用sub方法
int result2=c.sub(5,6);
//System.out.println(result2);
Assert.assertEquals(-1,result2);
}
}
反射
- 反射:框架设计的灵魂
- 框架:半成品软件、可以在框架的基础上进行软件开发、简化编码
- 反射:将类的各个组成部分封装为其他对象、这就是反射机制
- 好处:可以在程序运行过程中操作这些对象、可以解耦提高程序的可扩展性
获取字节码class对象的三种方式
- Class.forName("全类名”):将字节码文件加载进内存、返回class对象多用于配置文件将类名定义在配置文件中、读取文件加载类
- 类名.class:通过类名的属性class获取 多用于参数的传递
- 对象.getclass():getclass()方法在object类中定义 多用于对象的获取字节码的方式
- 同一个字节码文件(*.class)在一次程序运行过程中、只会被加载一次、不论通过哪一种方法获取的class对象都是同一个
Person类
package com.domain;
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
package com.reflect;
import com.domain.Person;
public class ReflectDemo1 {
/**
* 1. Class.forName("全类名”):将字节码文件加载进内存、返回class对象
* 2. 类名.class:通过类名的属性class获取
* 3. 对象.getclass():getclass()方法在object类中定义
*/
public static void main(String[] args) throws Exception {
// 1. Class.forName("全类名”)
Class cls1 = Class.forName("com.domain.Person");
System.out.println(cls1);
//2. 类名.class
Class cls2 = Person.class;
System.out.println(cls1);
//3. 对象.getclass()
Person person=new Person();
Class cls3=person.getClass();
System.out.println(cls3);
//==比较三个对象
System.out.println(cls1==cls2);
System.out.println(cls1==cls3);
}
}
class对象功能
- 获取功能:获取成员变量、获取构造方法、获取成员方法、获取类名
Person类
package com.domain;
public class Person {
private String name;
private int age;
public String a;
protected String b;
String c;
private String d;
public Person(){
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
public void eat(){
System.out.println("eat......");
}
public void eat(String food){
System.out.println("eat......"+food);
}
}
ReflectDemo2类
package com.reflect;
import com.domain.Person;
import java.lang.reflect.Field;
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
//获取Person的Class对象
Class personClass = Person.class;
//1、Field[]getFields()获取所有public修饰的成员变量
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("==================");
//2、Field[]getField()获取指定public修饰的成员变量
Field a = personClass.getField("a");
//获取成员变量a的值
Person person=new Person();
Object vaule1 = a.get(person);
System.out.println(vaule1);
//设置a的值
a.set(person,"王文超");
System.out.println(person);
System.out.println("===================");
//获取所有的成员变量、不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
Field d = personClass.getDeclaredField("d");
//忽略访问权限修饰符的安全检查
d.setAccessible(true);//暴力反射
Object value2 = d.get(person);
System.out.println(value2);
}
}
ReflectDemo3类
package com.reflect;
import com.domain.Person;
import java.lang.reflect.Constructor;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
//获取Person的Class对象
Class personClass = Person.class;
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
//创建对象
Object person = constructor.newInstance("张三", 23);
System.out.println(person);
System.out.println("===================");
Constructor constructor1 = personClass.getConstructor();
System.out.println(constructor1);
//创建对象
Object person1 = constructor1.newInstance();
System.out.println(person1);
Object person2 = personClass.newInstance();//构造结果和上面的一样
System.out.println(person2);
}
}
ReflectDemo4类
package com.reflect;
import com.domain.Person;
import java.lang.reflect.Method;
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
//获取Person的Class对象
Class personClass = Person.class;
//获取指定名称的方法
Method eat_method = personClass.getMethod("eat");
Person p=new Person();
//执行方法
eat_method.invoke(p);
Method eat_method2 = personClass.getMethod("eat", String.class);
eat_method2.invoke(p,"饭");
System.out.println("=========================");
//获取所有public修饰的方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
String name = method.getName();
System.out.println(name);
//method.setAccessible(true);
}
//获取类名
String classname = personClass.getName();
System.out.println(classname);
}
}
反射——案例
写一个”框架“、可以帮我们创建任意类的对象、并且执行其中的任意方法 前提:不能改变该类的任何代码
实现:1、配置文件 。2、反射
步骤
1、将需要创建对象的全类名和需要执行的方法定义在配置文件中
2、在程序中加载读取配置文件
3、使用反射技术来加载类文件进内存
4、创建对象
5、执行方法
Student类
package com.domain;
public class Student {
public void sleep(){
System.out.println("sleep......");
}
}
pro.properties配置文件
className=com.domain.Student
methodName=sleep
ReflectTest类
package com.reflect;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
//框架类
public class ReflectTest {
public static void main(String[] args) throws Exception {
//可以创建任意类的对象、可以执行任意方法 前提:不能改变该类的任何代码
//1、加载配置文件
//1.1创建Properties对象
Properties pro=new Properties();
//1.2加载配置文件、转换为一个集合
//1.2.1获取class目录下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
//2、获取配置文件中定义的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//3、加载该类进内存
Class cls = Class.forName(className);
//4、创建对象
Object obj = cls.newInstance();
//5、获取方法对象
Method method = cls.getMethod(methodName);
//6、执行方法
method.invoke(obj);
}
}
注解
概念:说明程序的。给计算机看的
注释:用文字描述程序的。给程序员看的
jdk内置注解
@Override :检测被该注解标注的方法是否是继承自父类(接口)的
@ @Deprecated:该注解标注的内容、表示已过时
@SuppressWarnings:压制警告 —一般传递参数all—@SuppressWarnings(“all”)
package com.annotation;
import java.util.Date;
/**
* jdk中预定义的一些注解
* @Override :检测被该注解标注的方法是否是继承自父类(接口)的
* @ @Deprecated:该注解标注的内容、表示已过时
* @SuppressWarnings:压制警告
*/
@SuppressWarnings("all")
public class AnnoDemo2 {
@Override
public String toString(){
return super.toString();
}
@Deprecated
public void show1(){
//有缺陷
}
public void show2(){
//替代show1方法
}
public void demo(){
show1();
Date date=new Date();
}
}
自定义注解
格式
元注解
public @interface 接口名{属性列表;}
本质:注解本质上就是一个接口、该接口默认继承Annotation接口
属性:接口中的抽象方法
1、属性的返回值类型:基本数据类型、String、枚举、注解、以上类型的数组
2、定义了属性、使用时需要给属性赋值 如果使用default关键字给属性默认初始化值、则使用时可以不进行属性的赋值-------如果只有一个属性、并且属性的名称是value时,可以省略属性名称、直接定义值—数组赋值时、使用{}包裹、如果数组只有一个值、可以省略{}
Calculator类
package com.demo;
public class Calculator {
//加法
@Check
public void add(){
System.out.println("1+0="+(1+0));
}
//减法
@Check
public void sub(){
System.out.println("1-0="+(1-0));
}
//乘法
@Check
public void mul(){
System.out.println("1*0="+(1*0));
}
//除法
@Check
public void div(){
System.out.println("1/0="+(1/0));
}
public void show(){
System.out.println("================");
}
}
Check注解
package com.demo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {
}
TestCheck测试类
package com.demo;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
//简单的测试框架
//当主方法执行后、会自动自行被检测的所有方法(加了check注解的方法)判断方法是否有异常、记录到文件中
public class TestCheck {
public static void main(String[] args) throws IOException {
//1、创建计算机对象
Calculator calculator=new Calculator();
//2、获取字节码文件对象
Class cls = calculator.getClass();
//3、获取所有的方法
Method[] methods = cls.getMethods();
int number=0;//出现异常的次数
BufferedWriter bw=new BufferedWriter(new FileWriter("bug.txt"));
for (Method method : methods) {
//4、判断方法上是否有check注解
if (method.isAnnotationPresent(Check.class)){
//5、有、执行
try {
method.invoke(calculator);
}catch (Exception e){
//6、捕获异常
//记录到文件中
number++;
bw.write(method.getName()+"方法出异常了");
bw.newLine();
bw.write("异常的名称:"+e.getCause().getClass().getSimpleName());
bw.newLine();
bw.write("异常的原因:"+e.getCause().getMessage());
bw.newLine();
bw.write("=========================");
bw.newLine();
}
}
}
bw.write("本次测试一共出现"+number+"次异常");
bw.flush();
bw.close();
}
}
SQL简介
- 英文:Structured Query Language,简称 SQL
- 结构化查询语言,一门操作关系型数据库的编程语言
- 定义操作所有关系型数据库的统一标准
- 对于同一个需求,每一种数据库操作的方式可能会存在一些不一样的地方,我们称为“方言”
通用语法
- SQL 语句可以单行或多行书写,以分号结尾
- MySQL 数据库的 SQL 语句不区分大小写,关键字建议使用大写
- 注释----单行注释: – 注释内容 或 #注释内容(MySQL 特有)
- 注意:使用-- 添加单行注释时,–后面一定要加空格,而#没有要求
- 多行注释: /* 注释 */
SQL分类
-
DDL(Data Definition Language) : 数据定义语言,用来定义数据库对象:数据库,表,列等
DDL简单理解就是用来操作数据库,表等
-
DML(Data Manipulation Language) 数据操作语言,用来对数据库中表的数据进行增删改
DML简单理解就对表中数据进行增删改
-
DQL(Data Query Language) 数据查询语言,用来查询数据库中表的记录(数据)
DQL简单理解就是对数据进行查询操作。从数据库表中查询到我们想要的数据。 -
DCL(Data Control Language) 数据控制语言,用来定义数据库的访问权限和安全级别,及创建用户
DML简单理解就是对数据库进行权限控制。比如我让某一个数据库表只能让某一个用户进行操作等。
注意: 以后我们最常操作的是 DML 和 DQL ,因为我们开发中最常操作的就是数据。
DDL:操作数据库、表
操作数据库:CRUD
1、C(create):创建
2、R(Retrieve):查询
3、U(Update):修改
4、D(Delete):删除
5、使用数据库
查询所有的数据库名称
show databases;
查看创建数据库的语句
show create database 数据库名;
如果不存在此数据库则创建
create database if not exists 数据库;
指定数据库的编码
create database 数据库 character set gbk;
修改数据库的字符集
alter database 数据库名称 character set 字符集名称;
删除数据库
drop database 数据库名称;
如果数据库存在则删除
drop database if exists 数据库名称;
*查询当前正在使用的数据库
select database();
使用数据库
use 数据库名称;
操作表:
1、C(create):创建
2、R(Retrieve):查询
3、U(Update):修改
4、D(Delete):删除
5、使用数据库
查询某个数据库中所有表的名称
show tables;
查询表结构
desc 表名;
创建表:语法
create table 表名
(列名1 数据类型1,
列名2 数据类型2,
.。。。。。);
数据库类型
1、int:整数类型------age int,
2、double:小数类型----score double(5,2)
3、date:日期----只包含年月日、yyyy-MM-dd
4、datetime:日期、包含年月日时分秒:yyyy-MM-dd HH:mm:ss
5、timestamp:时间戳类型:包含年月日时分秒yyyy-MM-dd HH:mm:ss -----如果将来不给这个字段赋值、或赋值为null、则默认使用当前的系统时间、自动赋值
6、varchar:字符串类型—name varchar(20):姓名最大20个字符
创建表
create table student(
id int,
name varchar(32),
age int,
score double(4,1),
birthday date,
insert_time timestamp);
复制表
create table 表名 like 被复制的表名;
删除表
drop table if exists 表名;
修改表名
alter table 表名 rename to 新的表名;
修改表的字符集
alter table 表名 character set 字符集名称;
添加一列
alter table 表名 add 列名 数据类型;
修改列名称 类型
alter table 表名 change 列名 新列名 新数据类型;
alter table 表名 modify 列名 新数据类型;
删除列
alter table 表名 drop 列名;
DML:增删改表中的数据
添加数据
insert into 表名(列名1,列名2,...) values(值1,值2,...);
注意:列名和值要一 一对应、如果表名后不定义列名则默认给所有列添加值、除了数字类型其他的需要用引号
删除数据
delete from 表名 where 条件;
注意:若不添加条件则删除表中所有记录
若要删除所有记录
1、delete from 表名; 不推荐使用-有多少条记录、就会执行多少次删除操作
2、truncate table 表名;–先删除表、在创建一张一样的空表
修改数据
update 表名 set 列名1=值1,列名2=值2,...... where 条件;
注意:若不添加条件则修改表中所有记录
DQL:查询表中的记录
select *from 表名;
语法:
select
字段列表
from
表名列表
where
条件列表
group by
分组字段
having
分组之后的条件
order by
排序
limit
分页限定
基础查询
CREATE TABLE student (
id int, -- 编号
name varchar(20), -- 姓名
age int, -- 年龄
sex varchar(5), -- 性别
ddress varchar(100), -- 地址
math double(5,2), -- 数学成绩
english double(5,2), -- 英语成绩
hire_date date -- 入学时间
);
-- 添加数据
INSERT INTO stu(id,NAME,age,sex,address,math,english,hire_date)
VALUES
(1,'马运',55,'男','杭州',66,78,'1995-09-01'),
(2,'马花疼',45,'女','深圳',98,87,'1998-09-01'),
(3,'马斯克',55,'男','香港',56,77,'1999-09-02'),
(4,'柳白',20,'女','湖南',76,65,'1997-09-05'),
(5,'柳青',20,'男','湖南',86,NULL,'1998-09-01'),
(6,'刘德花',57,'男','香港',99,99,'1998-09-01'),
(7,'张学右',22,'女','香港',99,99,'1998-09-01'),
(8,'德玛西亚',18,'男','南京',56,65,'1994-09-02');
多个字段的查询
SELECT 字段列表 FROM 表名;
SELECT * FROM 表名; -- 查询所有数据
select name,age from student;--查询name、age两列
select * from student;--查询所有列的数据,列名的列表可以使用*替代
去除重复
SELECT DISTINCT 字段列表 FROM 表名;
计算列
select name,math as 数学成绩,english as 英文成绩,math+english as 总分 from student;
select name,ifnull(math,0) as 数学成绩,ifnull(english,0) as 英文成绩,math+english as 总分 from student;
--ifnull(表达式1,表达式2)
--表达式1:哪个字段需要判断是否为null
--表达式2:如果该字段为null后的替换值
起别名
--查询姓名、数学成绩、英语成绩。并通过as给math和english起别名(as关键字可以省略)
select name,math as 数学成绩,english as 英文成绩 from student;
select name,math 数学成绩,english 英文成绩 from student;
条件查询
语法
SELECT 字段列表 FROM 表名 WHERE 条件列表;
条件
条件查询练习
--查询年龄大于20岁的学员信息
select * from stu where age > 20;
--查询年龄大于等于20岁的学员信息
select * from stu where age >= 20;
--查询年龄大于等于20岁 并且 年龄 小于等于 30岁 的学员信息
select * from stu where age >= 20 && age <= 30;
select * from stu where age >= 20 and age <= 30;
--上面语句中 && 和 and 都表示并且的意思。建议使用 and 。
也可以使用 between ... and 来实现上面需求
select * from stu where age BETWEEN 20 and 30;
--查询入学日期在'1998-09-01' 到 '1999-09-01' 之间的学员信息
select * from stu where hire_date BETWEEN '1998-09-01' and '1999-09-01';
--查询年龄等于18岁的学员信息
select * from stu where age = 18;
--查询年龄不等于18岁的学员信息
select * from stu where age != 18;
select * from stu where age <> 18;
--查询年龄等于18岁 或者 年龄等于20岁 或者 年龄等于22岁的学员信息
select * from stu where age = 18 or age = 20 or age = 22;
select * from stu where age in (18,20 ,22);
--查询英语成绩为 null的学员信息
null值的比较不能使用 = 或者 != 。需要使用 is 或者 is not
select * from stu where english = null; -- 这个语句是不行的
select * from stu where english is null;
select * from stu where english is not null;
模糊查询练习
模糊查询使用like关键字,可以使用通配符进行占位:
(1)_ : 代表单个任意字符
(2)% : 代表任意个数字符
--查询姓'马'的学员信息
select * from stu where name like '马%';
--查询第二个字是'花'的学员信息
select * from stu where name like '_花%';
--查询名字中包含 '德' 的学员信息
select * from stu where name like '%德%';
排序查询
语法
SELECT 字段列表 FROM 表名 ORDER BY 排序字段名1 [排序方式1],排序字段名2 [排序方式2] …;
ASC : 升序排列 (默认值)
DESC : 降序排列
注意:如果有多个排序条件,当前边的条件值一样时,才会根据第二条件进行排序
练习
--查询学生信息,按照年龄升序排列
select * from stu order by age ;
--查询学生信息,按照数学成绩降序排列
select * from stu order by math desc ;
--查询学生信息,按照数学成绩降序排列,如果数学成绩一样,再按照英语成绩升序排列
select * from stu order by math desc , english asc ;
聚合函数
概念:将一列数据作为一个整体,进行纵向计算。
语法:SELECT 聚合函数名(列名) FROM 表;
注意:null 值不参与所有聚合函数运算
练习
--统计班级一共有多少个学生
select count(id) from stu;
select count(english) from stu;
--上面语句根据某个字段进行统计,如果该字段某一行的值为null的话,将不会被统计。所以可以在count(*) 来实现。* 表示所有字段数据,一行中也不可能所有的数据都为null,所以建议使用 count(*)
select count(*) from stu;
--select count(*) from stu;
select max(math) from stu;
--查询数学成绩的最低分
select min(math) from stu;
--查询数学成绩的总分
select sum(math) from stu;
--查询数学成绩的平均分
select avg(math) from stu;
--查询英语成绩的最低分
select min(english) from stu;
分组查询
语法:
SELECT 字段列表 FROM 表名 [WHERE 分组前条件限定] GROUP BY 分组字段名 [HAVING 分组后条件过滤];
注意:分组之后,查询的字段为聚合函数和分组字段,查询其他字段无任何意义
练习
--查询男同学和女同学各自的数学平均分
select sex, avg(math) from stu group by sex;
> 注意:分组之后,查询的字段为聚合函数和分组字段,查询其他字段无任何意义
select name, sex, avg(math) from stu group by sex; -- 这里查询name字段就没有任何意义
--查询男同学和女同学各自的数学平均分,以及各自人数
select sex, avg(math),count(*) from stu group by sex;
--查询男同学和女同学各自的数学平均分,以及各自人数,要求:分数低于70分的不参与分组
select sex, avg(math),count(*) from stu where math > 70 group by sex;
--查询男同学和女同学各自的数学平均分,以及各自人数,要求:分数低于70分的不参与分组,分组之后人数大于2个的
select sex, avg(math),count(*) from stu where math > 70 group by sex having count(*) > 2;
where 和 having 区别:
执行时机不一样:where 是分组之前进行限定,不满足where条件,则不参与分组,而having是分组之后对结果进行过滤。
可判断的条件不一样:where 不能对聚合函数进行判断,having 可以。
分页查询
语法
SELECT 字段列表 FROM 表名 LIMIT 起始索引 , 查询条目数;
注意: 上述语句中的起始索引是从0开始
练习
--从0开始查询,查询3条数据
select * from stu limit 0 , 3;
--每页显示3条数据,查询第1页数据
select * from stu limit 0 , 3;
--每页显示3条数据,查询第2页数据
select * from stu limit 3 , 3;
--每页显示3条数据,查询第3页数据
select * from stu limit 6 , 3;
从上面的练习推导出起始索引计算公式:
起始索引 = (当前页码 - 1) * 每页显示的条数
约束
约束是作用于表中列上的规则,用于限制加入表的数据
例如:我们可以给id列加约束,让其值不能重复,不能为null值。
约束的存在保证了数据库中数据的正确性、有效性和完整性
添加约束可以在添加数据的时候就限制不正确的数据,年龄是3000,数学成绩是-5分这样无效的数据,继而保障数据的
完整性。
分类
-
非空约束: 关键字是 NOT NULL
-
唯一约束:关键字是 UNIQUE
-
主键约束: 关键字是 PRIMARY KEY
-
检查约束: 关键字是 CHECK
-
默认约束: 关键字是 DEFAULT
-
外键约束: 关键字是 FOREIGN KEY
非空约束: 关键字是 NOT NULL
保证列中所有的数据不能有null值。
例如:id列在添加 马花疼 这条数据时就不能添加成功。
=================================================================================================
唯一约束:关键字是 UNIQUE
保证列中所有数据各不相同。
例如:id列中三条数据的值都是1,这样的数据在添加时是绝对不允许的。
=================================================================================================
主键约束: 关键字是 PRIMARY KEY
主键是一行数据的唯一标识,要求非空且唯一。一般我们都会给没张表添加一个主键列用来唯一标识数据。
例如:上图表中id就可以作为主键,来标识每条数据。那么这样就要求数据中id的值不能重复,不能为null值。
=================================================================================================
检查约束: 关键字是 CHECK
保证列中的值满足某一条件。
例如:我们可以给age列添加一个范围,最低年龄可以设置为1,最大年龄就可以设置为300,这样的数据才更合理些。
注意:MySQL不支持检查约束。
这样是不是就没办法保证年龄在指定的范围内了?从数据库层面不能保证,以后可以在java代码中进行限制,一样也
可以实现要求。
================================================================================================
默认约束: 关键字是 DEFAULT
保存数据时,未指定值则采用默认值。
例如:我们在给english列添加该约束,指定默认值是0,这样在添加数据时没有指定具体值时就会采用默认给定的0。
================================================================================================
外键约束: 关键字是 FOREIGN KEY
外键用来让两个表的数据之间建立链接,保证数据的一致性和完整性。
外键约束现在可能还不太好理解,后面我们会重点进行讲解。
================================================================================================
非空约束
非空约束用于保证列中所有数据不能有NULL值
--添加约束
-- 创建表时添加非空约束
CREATE TABLE 表名(
列名 数据类型 NOT NULL,
…
);
-- 建完表后添加非空约束
ALTER TABLE 表名 MODIFY 字段名 数据类型 NOT NULL;
--删除约束
ALTER TABLE 表名 MODIFY 字段名 数据类型;
唯一约束
唯一约束用于保证列中所有数据各不相同
唯一约束可以有null值、但只能有一条记录为null
sql
--添加约束
-- 创建表时添加唯一约束
CREATE TABLE 表名(
列名 数据类型 UNIQUE [AUTO_INCREMENT],
-- AUTO_INCREMENT: 当不指定值时自动增长
…
);
CREATE TABLE 表名(
列名 数据类型,
…
[CONSTRAINT] [约束名称] UNIQUE(列名)
);
-- 建完表后添加唯一约束
ALTER TABLE 表名 MODIFY 字段名 数据类型 UNIQUE;
---- 建完表后添加唯一约束
ALTER TABLE 表名 MODIFY 字段名 数据类型 UNIQUE;`
--删除约束
ALTER TABLE 表名 DROP INDEX 字段名;
主键约束
主键是一行数据的唯一标识,要求非空且唯一
一张表只能有一个主键
--添加约束
-- 创建表时添加主键约束
CREATE TABLE 表名(
列名 数据类型 PRIMARY KEY [AUTO_INCREMENT],
…
);
CREATE TABLE 表名(
列名 数据类型,
[CONSTRAINT] [约束名称] PRIMARY KEY(列名)
);
-- 建完表后添加主键约束
ALTER TABLE 表名 ADD PRIMARY KEY(字段名);
--删除约束
ALTER TABLE 表名 DROP PRIMARY KEY;
默认约束
保存数据时,未指定值则采用默认值
--添加约束
-- 创建表时添加默认约束
CREATE TABLE 表名(
列名 数据类型 DEFAULT 默认值,
…
);
-- 建完表后添加默认约束
ALTER TABLE 表名 ALTER 列名 SET DEFAULT 默认值;
--删除约束
ALTER TABLE 表名 ALTER 列名 DROP DEFAULT;
外键约束
外键用来让两个表的数据之间建立链接,保证数据的一致性和完整性。
--添加约束
-- 创建表时添加外键约束
CREATE TABLE 表名(
列名 数据类型,
…
[CONSTRAINT] [外键名称] FOREIGN KEY(外键列名) REFERENCES 主表(主表列名)
);
-- 建完表后添加外键约束
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称);
--删除约束
ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;