Java基础_week6

1.Tcp网络编程步骤:

客户端步骤:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

public class ClientDemo {
	public static void main(String[] args) throws IOException {
		//1:创建客户端的套接字
		Socket s = new Socket("localhost", 10086);
		//2:获取管道输出流并转换成高效字符缓冲输出流 
		//第1层:字符缓冲输出流
		//第2层:字符转换输出流
		//第3层:字节输出流
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		//3 获取输入流
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入用户名");
		 String userName = sc.nextLine();
		System.out.println("请输入密码");
		String password = sc.nextLine();
		//3:写数据
		bw.write(userName);
		bw.newLine();
		bw.write(password);
		bw.flush();
		//bw.close();  //切记,缓冲流写数据,需要刷空!!!
		
		//告诉服务器。客户端这边数据写入完毕
		s.shutdownOutput();
		
		//4:读取从服务器响应的数据
		String info = br.readLine(); //阻塞式方式
		System.out.println(info);
		
		//4:关闭套接字
		s.close();
		
		
	}

}


服务端步骤:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class ServerDemo {
	
	public static Map<String, String> getUserInfo() throws FileNotFoundException, IOException{
		
        //创建属性集合列表(配置文件)
		Properties p = new Properties();
        
        //将文件内容加载到属性集合列表中,该方法的(参数是 Reader r)
		p.load(new FileInputStream("user.properties"));
		String userName = p.getProperty("userName");
		String password = p.getProperty("password");
		
		Map<String, String> map = new HashMap<>();
		map.put("userName", userName);
		map.put("password", password);
		
		return map;
		
	}
	   

	public static void main(String[] args) throws IOException {
		
		//1:创建服务器端套接字
		ServerSocket ss = new ServerSocket(10086);
		//2:监听客户端的套接字
		Socket s = ss.accept();
		//3:获取输入流
		//第1层:字符缓冲输入流
		//第2层:字符转换输入流
		//第3层:字节输入流
		BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		//4:获取输出流
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		//4:读取数据
		String userName = br.readLine();
		String password = br.readLine();
		//5:判断用户名和密码
		//获取正确的用户名和密码
		Map<String, String> map = getUserInfo();
		
		System.out.println(userName);
		System.out.println("--------------------------");
		
		if(map.get("userName").equals(userName)&&map.get("password").equals(password)){
			//需要将响应返回给客户端
			//System.out.println("登陆成功");
			bw.write("登陆成功");
			bw.flush();
		}else{
			bw.write("登陆失败");
			bw.flush();
		}
		
		
		//5:关闭客户端套接字
	         s.close();
	}
}

2.反射的核心思想:

 就是获取类的字节码文件对象,-------字节码文件对象获取类的构造方法并且创建该类的对象
 字节码文件获取类的成员方法,并去调用
 字节码文件对象获取类的成员方法,并去调用

3.面试题:(获取一个类的字节吗文件对象的方式)

反射思想:
1) 通过类加载器--------效验语法以及类的初始化,获取类的字节码文件对象(Class.forName())
2)通过字节码文件对象
获取这个类的构造器的类Constructor,创建实例,使用方法

      获取这个类的成员方法的Method类,调用成员方法 
      获取这这个类的成员变量Field,可以给成员变量赋值

 1)Object类的getClass()方法:任意java类对象.getClass()----Class
 2)任意Java类型的.  Class属性   类名.Class---
 3)Class就是代表正在运行的类字节码文件,使用静态方法
 public static Class<?> forName(String className) throws ClassNotFoundException 在开发中常用的
 **注意:**
 参数:必须是当前类的"全限定名称"  包名.类名
 使用: Class.forName("包名.类名");

反射的基本使用:(代码示例)

public class Test_main {
    public static void main(String[] args) throws Exception{
        //获取类的字节码文件
       Class s = Class.forName("com.qf_01.day2.test_1.Person");
        //获取当前类的构造器对象(获取公共的构造方法)
        Constructor con = s.getConstructor();
        //创建实例对象
        Object obj = con.newInstance();
        System.out.println("----------------给公共字段赋值--------------------------");
        //通过字节码文件获取公共字段在File类中的实例对象
        Field nameFile = s.getField("name");
        nameFile.set(obj,"公共的字段");
        System.out.println(obj);

        System.out.println("--------------给私有的字段赋值(默认字段一样)-----------------");
        //通过字节码文件给非公共的字段赋值
        Field ageFile = s.getDeclaredField("age");
        ageFile.setAccessible(true); //抑制java语言访问检查
        ageFile.set(obj,45);
        System.out.println(obj);

        System.out.println("--------------带参数的非公共的构造方法-----------------------");
        //获取指定的非公共的有参构造
        Constructor dcon = s.getDeclaredConstructor(String.class, int.class, String.class);
        dcon.setAccessible(true);  //抑制java语言访问检查
        //实例有参的对象
        Object obj1 = dcon.newInstance("私有", 11, "有参构造");
        System.out.println(obj1);

         System.out.println("---------------调用类的私有成员方法------------------");
        //获取当前类公共成员方法在Method类中的实例
        Method showMethod = s.getMethod("show");
        //通过invoke()方法掉用show();
        showMethod.invoke(obj);

     System.out.println("---------------调用非公共的有参数的成员方法---------------------");
     //获取当前类非公共的成员方法在Method中的实例
     Method funMethod = s.getDeclaredMethod("fun", String.class);
     funMethod.setAccessible(true); //抑制java 访问检查
     //通过invoke()调用fun()方法
     funMethod.invoke(obj1,"我是私有的有参的成员方法");


    }
}

java–jdk动态代理:

代理模式:-----代理角色帮助真是角色 增强功能!
静态代理:
动态代理:
jdk动态代理:jdk提供java.lang.reflest.Proxy
特点:在程序执行过程中就产生了代理,前提必须有一个接口!
cglib动态代理

/* 代理设计模式---->结构型设计模式
 *      代理描述:让代理角色帮助真实角色完成一件事情!(业务代码)
 *      静态代理
 *              代理角色和真实角色必须同一个接口!
 *              创建线程的方式第二种:自定义一个类 实现Runnable接口
 *                              class Thread implements Runnable
 *
 *              弊端:结构组成太繁琐,真实角色,代理角色,必须实现同一个接口
 *      动态代理
 *              jdk动态代理:jdk提供的java.lang.reflet.Proxy
 *              前提:必须有一个接口
 *              通过反射的方式直接将接口的方法进行调用,然后产生代理对象
 *
 *   /           静态方法:
   //java.lang.reflect.Proxy静态方法
       /* public static Object newProxyInstance(
                                          ClassLoader loader,   当前代理实例要实现接口的类加载器
                                       Class<?>[] interfaces,   当前代理实例要实现的接口列表的字节码文件对象
                              InvocationHandler h)              代理实例调用接口的方法的处理程序!
                                            这个类型接口--->里面需要将增强代码和业务代码分离
                        throws IllegalArgumentException*/
                        * //给代理实例的处理程序---调用接口中的方法,对真实角色的方法进行增强!
 */
public class MyInvocationHandler  implements InvocationHandler {

    //要对哪个真实角色产生代理
    private Object target ;
    public MyInvocationHandler(Object target){ //测试类中 UserDao ud = new UserDaoImpl() ;
        this.target = target ;
    }

    //第一个参数:代理实例
    //第二个参数:要调用真实角色的里面method------>add()/update()/delete()/select()
    //第三个参数:调用方法里面传递实际参数,如果没有参数不用传参
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("权限校验");

        //调用方法
        Object obj = method.invoke(target, args); //真实角色的方法的调用
        System.out.println("产生日志");
        return obj;
    }
}

数据库的基本操作语句:


** DDl语句:----针对数据库的操作:**

  1)查询MySQL服务端默认的数据库有哪些:
  show databases;  //查询有哪些库
  2)创建数据库:
    方式一:create database 库名; //直接创建
    方式二:create database if not exists 库名;如果没有这个库则直接创建
  3)查询指定数据库的信息
  show create database 库名;
  4)修改数据库默认的字符集
  alter database 库名 default character set 字符集名称;
  5)删除库;
       方式一: drop database 库名; //直接删除
       方式二:drop database if exists 库名;
  

    关于MySQL中常见的字段类型:
    varchar(字符长度) : 字符串------类似于java中的String
    int :整数类型-----默认里面字符长度int(11) ,
    double : 小数类型
       double(1 ,2 ):
       举例: double(4,2);表示小数类型4位数,保留2位小数
    data:日期类型:-----"2208-8-23"
    datatime:日期时间类型:  ----"2208-8-23 16:02:50"
    timestaple:时间戳 :
    比如网购中下单的一瞬间的时间:
    
** DDl语句针对表的操作:**
 1) 创建表之前需要指定在那个库操作:
 use 库名 ;------选择指定的库(如果没有指定默认创建在MySQL库中
 2)创建表的 语法:
 create table 表名(
 字段名称1 字段类型 ,
 字段名称2 字段类型,
 字段名称3 字段类型
 );
 3)查询库中有哪些表:
 show tables;
 4)查询表的结构
 desc 表名;
** 修改表:**
1)修改表的字段名称
alter table 表名 change 旧的字段名称 新的字段名称 以前的字段类型
2)修改表的字段类型;
alter table 表名 modify 字段名称 新的数据类型;
3)给表添加一个新的字段
alter table 表名 add 字段名称  字段类型
4)给表删除一个字段
alter table 表名 drop 字段名称;
5)给表名重命名
alter table 以前的表名 rename to 新的表名;
6)复制一张一模一样的表
create table 新表名 like 以前的表名;
7)删除表
drop table 表名;

DML语句针对表的数据(记录)的操作语句:

给表插入数据

语法1:插入全表数据

  insert into 表名 values(值1, 值2, 值3....);

语法2:插入全表数据,一次插入多条

insert into 表名 values(值1, 值2, 值3....) ,(值1, 值2, 值3....),(值1, 值2, 值3....);

语法3:插入部分字段,没有插入的字段的值,默认值是null(没有值),

insert  into 表名(字段1, 字段二, 字段三...) values(值1, 值2, 值3...)

语法4:插入部分字段,也可以一次插入多条

insert into 表名 (字段1, 字段2.....部分字段) values(值1, 值2,....部分值), (值1, 值2,....部分值)..

插入表的记录语法注意事项

1)如果是插的全表记录,字段值一定 要和类型匹配
2)插入全表数据(或插入部分字段),字段值得总数量和值的总数量要对应上
修改表记录 (带条件修改)

语法1:带条件修改(修改单个字段)

update 表名 set 字段名1 = 值1 where 字段名2 = 值2 ;

语法2:带条件修改(修改多个字段)

 update 表名 set 字段名称1 = 值1, 字段名称2 = 值2,...where 字段名称1 = 值1 ,字段名称2 = 值2,...

语法2:不带条件修改多个字段: (很少用)

 update 表名 set 字段名 = 值; (将该字段的所有值都修改) 

语法3:带条件修改: 条件和条件中间 and (并列关系)

update 表名 set 字段名 = 值 where 字段名1 = 值1 and 字段名2 = 值2;
删除表的记录

语法1:带单个条件删除

 delete from 表名 where 字段名 = 值;

语法2:带多个条件删除

delete from 表名 where 字段名 = 值 and 字段2 = 值2;

语法3:不带条件,删除全部数据(表的结构并没有删除)

delete from 表名;

delete from 表名 和 truncate table 表名 有什么区别?(面试题)

前者:
   1)仅仅只是删除全部数据,表还是存在的(表的结构还是存在的,;) 
   2)针对非业务字段id 一般:主键(非空且唯一))自增长约束(字段会在上一次的基础上自动增加1)
 后者:
    1)它不仅仅是删除全表数据,还会将表结构删除,并重新生成一张新表
    2)直接影响自增长主键 id值
查询表的记录:

1)基本查询:
查询表的所有记录:
select * from 表名;

– 2)查询全表字段,给定别名 as ,as可以省略
SELECT
id AS ‘学号’,
NAME AS ‘姓名’,
gender AS ‘性别’,
age AS ‘年龄’,
address AS ‘地址’,
birthday AS ‘出生日期’
FROM
student ;
– as可以省略
3)查询指定字段
select 字段名称…from 表名 ;
4)字段求和(字段类型一致)
– 需求:查询所有学生的姓名以及他们的对应的总成绩信息
SELECT
NAME ‘姓名’,
(math+english) ‘总成绩’
FROM
student2;
– 问题:数学成绩有内容的,英语成绩null ,两个相加的结果 null
– 如果null值,mysql有自己的函数,ifnull(字段名称,给一个值); 如果这个字段名称是null,给一个固定值

Dql语句,带条件查询:

– 基本格式:select 字段列表 from 表名 where 条件;
– 条件:1)里面使用基本运算符,比较运算符:<,>=,<=,==,!=(mysql的不等于可以使用这个<>)
– 赋值运算符: =
– 逻辑运算符:java中的&&,|| mysql提供:and并列 , or或
– 某个范围的数据: 字段名称>=值1 and 字段名称<=值2;
– mysql 提供了between 值1 and 值2;
– 查询或的关系:字段名称 = 值1 or 字段名称= 值2 or 字段名称= 值3
– mysql提供:字段名称 in(值1,值2,值3…):相当于字段名称是值1或值2的或者值3的
– 2)模糊查询 like
– 3)聚合函数
– 4)排序查询
– 5)分组查询
– 6)筛选查询
– 7)分页查询

– 需求1:查询学生的年龄是20岁的所有学生信息
SELECT
*
FROM
student2
WHERE
age = 20 ;
– 需求2:查询学生的年龄大于25的学生学号,姓名,年龄,性别,和住址信息
SELECT
id ‘学号’,
NAME ‘姓名’,
age ‘年龄’,
sex ‘性别’,
address ‘住址’
FROM
student2
WHERE age > 25 ;
– 需求3:查询学生年龄在18到22之间所有的学生信息
– 方式1:
SELECT
*
FROM
student2
WHERE
age >= 18 && age <= 22 ;
– 方式2
SELECT
*
FROM
student2
WHERE
age >= 18 AND age <= 22 ; – Mysql提供多个条件并列是and关键字

– 方式3:mysql提供 字段名称 between 值1 and 值2 ; 两者之间
SELECT
*
FROM
student2
WHERE
age
BETWEEN 18 AND 22 ;

– 需求4):查询学生年龄在是18岁或者22岁或者55岁的学生的所有信息
– 方式1:—java的||
SELECT
*
FROM
student2
WHERE
age = 18 || age = 22 || age = 55;
– 方式2: mysql提供表示或的关系的关键字:or

SELECT
*
FROM
student2
WHERE age = 18
OR age = 22
OR age = 55 ;

– 方式3:mysql提供的语法
– select 字段列表 from 表名 字段名称 in(值1,值2,值3…值n): 和上面的等价
SELECT
*
FROM
student2
WHERE age IN (18, 22, 55) ;

– 需求:查询学生年龄不是20岁的学生的信息
SELECT
*
FROM
student2
WHERE
age !=20 ;
– mysql提供不等于<>
SELECT
*
FROM
student2
WHERE
age <> 20 ;

– 需求:查询英语成绩不是null的学生所有信息
/*
select
*
from
student2
where
english != null ;-- 查询某个字段不等于null, mysql语言中 is not null
/
SELECT
*
FROM
student2
WHERE
english IS NOT NULL ;
– 查询某个字段为null的学生所有信息 mysql 某个字段为null 字段名称 is null
/

SELECT
*
FROM
student2
WHERE
english = null ;
*/
SELECT
*
FROM
student2
WHERE
english IS NULL ;

– 2)模糊查询 like
– select 字段列表 from 表名 where 字段名称 like ‘模糊的语法’ ;
– a) like 后面使用 ‘%其他字符%’ 或者 ‘字符%’ %:代表任意多个或者单个字符(开发中模糊搜索最频繁的)

– b)_: 一个下划线 代表单个字符,

– 需求:查询学生中所有姓马的学生所有信息
SELECT
*
FROM student2
WHERE
NAME
LIKE ‘%马%’ ;
– 或者下面
SELECT
*
FROM student2
WHERE
NAME
LIKE ‘马%’ ;

– 查询学生中姓名是三个字符的学生所有信息
SELECT
*
FROM
student2
WHERE NAME LIKE ‘___’ ;

– 查询mysql数据库中的所有带character 字符集的变量信息;
SHOW VARIABLES LIKE ‘%character%’ ;
– 全部变成utf8—>如果要在dos出窗口去查询表的数据,就出现乱码
– 在dos窗口临时更改character_set_client /character_set_results/character_set_server改成gbk就可以在dos展示中文

– 3)聚合函数 —>查询出的结果是一个单行单列的数据
– count(非业务字段:比如id字段,在实际开发中非空并且唯一) 查询(统计)总条数
– count(业务字段:比如 具体信息字段):可能是null值,不会统计

– avg(字段名称):求平均分
– max(字段名称):求这列的最大值
– min(字段名称):求这列最小值
– sum(字段名称):这列求和

– 需求:统计student2表总记录数
/*
select
count(english) ‘总条数’ – english 业务字段,可能有null,不会统计这条数据
from
student2 ;
*/
SELECT
COUNT(id) ‘总条数’
FROM
student2 ;

– 需求:查询数学成绩最高分
SELECT
MAX(math)
FROM
student2; – 99分

– 需求: 查询数学成绩最高分的学生信息
– 1)查询数学最高分
– select max(math) from student2;
– 2)查询出数学成绩是99分的学生信息
– select * from student2 where math = 99 ;
– 类似于Java中 int a= 20 ; int b = 30 ; int x = a+b ;
SELECT
*
FROM
student2
WHERE math =
(SELECT MAX(math) FROM student2);

– 需求:查询数学平均分
SELECT AVG(math) FROM student2;

– 需求:查询出数学成绩大于数学平均成绩的学生信息;
– 1)先查询出来数学平均分是多少
– SELECT AVG(math) FROM student2;
– 2) 查询数学成绩大于 79.5的学生所有信息
/*
select
*
from
student2
where
math > 79.5;
*/
SELECT
*
FROM
student2
WHERE math >
(SELECT
AVG(math)
FROM
student2) ;

– select 嵌套 select 执行效率非常低!

– 需求:求出 英语总成绩,(求和)
SELECT SUM(IFNULL(english,0)) ‘英语总成绩’ FROM student2;

INSERT INTO student2 VALUES(9,‘高圆圆’,43,‘女’,‘西安’,97,87) ;

– 4)排序查询 order by
– select 字段列表 from order by 字段名称 排序规则;
– 排序规则不写:默认asc 升序 ,desc 降序
– 需求: 按照学生成绩的升序排序
SELECT
*
FROM
student2
ORDER BY
math DESC ; – 字段名称后面没有携带排序规则,默认就是asc升序
– 需求:数学成绩大于70的学生,按照学生成绩升序排序
– 携带条件排序,where条件必须放在order by 前面,不能放后面

SELECT
*
FROM
student2
WHERE math > 70
ORDER BY
math ASC ;

– 针对多个字段同时排序,前面字段如果它的值相同,应该按照后面的字段来进行排序

– select 字段列表 from order by 字段名称 排序规则,字段名称2 排序规则2… ;
– 需求:学生的数学成绩降序排序,英语成绩升序排序,查询所有学生信息

SELECT
*
FROM
student2
ORDER BY
math DESC , – 数学降序排序
english ASC ; – 英语升序排序

– 5)分组查询 group by
– 基本语法: select 字段列表 from 表名 group by 分组字段;

– 分组字段可以在select后面查询的 ,group by的后面不能使用聚合函数
– 需求:按照性别分组,统计每个组的总人数
SELECT
sex ‘性别’,
– 查询分组字段
COUNT(id) ‘总人数’
FROM
student2
GROUP BY sex ;-- 按性别分组

– 带条件进行分组查询, where关键字,还有group by 关键字
– goup by 后面不能使用where条件,where 条件必须放在group by 前面,先满足条件,再参与分组
– 需求:按照性别分组,统计每个组的总人数,条件:数学成绩不大于70分的不参与分组

– 错误的写法
/*
select
sex ‘性别’,
count(id) ‘总人数’
from
student2
group by sex
where math > 70 ;
*/
SELECT
sex ‘性别’,
COUNT(id) ‘总人数’
FROM
student2
WHERE math > 70
GROUP BY sex ;

– 6)筛选having
– where,group by,having :先是满足条件,然后参与分组,在进行筛选!
– 在上面的基础上
– 需求
– 按照性别分组,统计每个组的总人数,条件:数学成绩不大于70分的不参与分组, 筛选出总人数大于2的这一组
SELECT
sex ‘性别’,
COUNT(id) ‘总人数’
FROM
student2
WHERE math > 70
GROUP BY sex
HAVING COUNT(id)>2 ;

– 上面这个格式优化
SELECT
sex ‘性别’,
COUNT(id) 总人数 – 别名
FROM
student2
WHERE math > 70
GROUP BY sex
HAVING 总人数 > 2 ;

SELECT * FROM student2;

分页查询:(limit)

MySQL 数据库的分页查询关键字 limit
语法格式:

select 字段名称 from 表名  limit 起始行数, 每页显示的条数
 起始行数-- 从0开始
 起始行数 = (当前页码-1) * 每页显示的条数
-- 现在每页显示两条,    查询第一页数据
SELECT * FROM student2 LIMIT 0,2;
-- 查询第二页数据
SELECT * FROM student2 LIMIT 2,2;
-- 查询第三页数据
SELECT * FROM student2 LIMIT 4,2;
-- 查询第四页数据
SELECT * FROM student2 LIMIT 6,2;

数据库的备份和还原:(两种方式)

方式一:
图形界面化方式,直接借助工具
备份:
鼠标选中备份的库名,右键----->backup/export—>选中sql脚本 backupdatabase as sql dump
最上面选中 structure and data 以及选中备份本地磁盘路径—执行即可
还原:新建库–>use 库名----->在库上面右键—>import导入---->选中要执行的sql脚本文件
方式二:
命令行的方式去备份和还原:
备份:
以管理员的身份进入dos窗口,不需要登录MySQL
输入指令mysqldump -uroot -p密码 要备份的库名 > 指定本地磁盘上的路径D:-------\指定sql脚本文件名称,sql
还原:
在dos窗口,要登录MySQL
mysql -uroot -p ----回车 输入密码
登录成功之后

    将之前的库删除
    新建库
    使用库
    
    source 本地磁盘上的备份的sql脚本文件,自动会执行!

–数据库的约束

 约束是操作数据库的一种行为,插入null,重复数据(非业务字段) 等等---(不符合规范的数据)
 1)默认约束  default
 2)非空约束 not null 
 3)唯一约束 unique
 4)主键约束 primary key
 5)自增长约束 auto_increment
 6)外键约束 foreign key
 7)级联操作 cascade ,必须前提是从在外键
 (级联删除 on delete cascade 级联修改 on update cascade)

  -- 1)默认约束 default
    --作用范围:就是在插入部分字段的时候,没有插入的字段就默认值是null 或者 给定的值
   
   --注意事项
     默认约束对直接插入的null值不起作用,只是在没有插入的字段值才起作用
     
     --通过sql语句将默认约束删除--直接修改字段类型(即可)
     alter table 表名 modify  字段 字段类型;
     
     --通过sql语句添加默认约束--直接修改字段类型
     alter table 表名 modify gender varchar(3) default '女';
     
 --2)非空约束 not null
     CREATE TABLE stu(
	id INT,
	NAME VARCHAR(10) NOT NULL, -- 非空约束
	age INT
);

  --sql语句如何删除 --直接修改字段类型
  alter table 表名 modify 字段名 字段类型
  
  --通过sql语句直接添加非空约束
  alter table 表名 modify 字段名 字段类型 not null;

--3)唯一约束 (实际业务中真实有效的业务必须唯一)
   CREATE TABLE stu(
	id INT,
	NAME VARCHAR(10),
	telephone VARCHAR(11) UNIQUE -- 加入唯一约束 
) ;

 -- 通过sql语句修改删除 唯一约束
 alter table 表名 drop index (索引名)默认是字段名;
 
 -- 通过sql语句修改表,加入唯一约束
 alter table 表名 add constraint 申明约束名 unique(字段名);
 
 --4)主键约束 primary key (一般情况下都是作用在非业务字段 )
 特点: 非空且唯一
 CREATE TABLE stu(
	id INT  PRIMARY KEY,  -- 加入主键约束
	NAME VARCHAR(10) 
);

-- 通过sql语句删除主键约束
alter table 表名 drop primary key;<注意:此时只是删除了主键索引,非空约束还在>

-- 通过sql语句 添加主键约束
alter table 表名 add constraint 主键约束名 primary key(id字段名)

--5)自增长约束 auto_increment, 一般和主键一起搭配使用
CREATE TABLE stu(
	id INT PRIMARY KEY AUTO_INCREMENT,-- id字段主键并且是自增长的
	NAME VARCHAR(10),
	age INT
);
 
    -- 通过sql语句修改表可以删除自增长约束
    alter table 表名 drop modify 字段名称 字段类型 去掉auto_increment约束
    
    -- 通过sql语句 添加自增长约束
    alter table 表名 字段名称 字段类型 auto_increment;
    
  -- 6)外键约束 foreign key 
  语法:
    constraint (声明) 外键约束名称 
    foreign key(作用在从表的字段名)
    references(关联) 主表名(主键字段名);
    
    注意:加入外键约束 插入和删除都比较麻烦
    删除的时候先要将从表的内容删除,然后将主表的内容在删除,解决如下
    --  加入级联删除和级联修改(cascade)
    CREATE TABLE employee(
	id INT PRIMARY KEY AUTO_INCREMENT , -- 员工编号
	NAME VARCHAR(10),		    -- 姓名
	gender VARCHAR(3),		    -- 性别
	dept_id INT,                         -- 员工所在的部门的编号
	CONSTRAINT 		-- 声明
	dept_emp_fk 		-- 外键约束名
	FOREIGN KEY (dept_id)   -- 作用在从表的指定字段上
	REFERENCES              -- 关联
	dept(id)		-- 主表名(主键字段名) ;
	ON DELETE CASCADE  -- 级联删除
	ON UPDATE CASCADE  -- 级联修改

数据库常见理论面试题(三大范式)

   概述:数据库的范式(--- 是设计数据库的一种规范要求)
   标准规范:三大范式(规范):每个范式程递次规范,范式级别越大,数据库中字段冗余度越小
   1NF : 表中的每一列是不能再拆分的原子数据
   2NF : 在1NF 的基础上
     特点一)每一张表只能描述一件事情;
    特点二)非主键字段必须完全依赖于主键字段
  3NF : 在2NF的基础上
     --核心思想:非主键之间不能产生传递依赖
    举例  -- C字段依赖于B字段,B字段依赖于A字段----->
	C依赖于A字段	

多表关系(理论关系):

一对一的关系(是特例,是对对多的一种特例,比如身份证和人)
一对多的关系(开发中频繁用的,比如用户和订单)
多对多的关系(开发中常见的,比如部门和员工之间)

多表查询(重点):

一,内连接查询;
1)隐式内连接(推荐)
2)显示内连接
二,外连接查询;
1)左外连接(推荐)
2)右外连接
三,子查询;
select嵌套查询
多表查询中的问题:

  • A表中有m条记录,B表中有n条记录,直接查询A和B表的数据
    ---->结果 m*n 的总记录数(出现了笛卡尔积现象,原因是两张表之间没有关系)

查询注意事项:(三要素)

  • 查询哪些表
  • 查询这些表的哪些字段
  • 表和表之间的关系是什么(连接条件)
内连接查询使用:
1>隐式连接(推荐:多去使用where条件,这个算sql优化的一种方式)
语法:select 字段列表 from 表名1,表名2 where 连接条件;
 --举例:
 -- 需求:要查询员工表和部门表的所有信息
SELECT
   *
FROM
     employee,
     dept
WHERE
     employee.dept_id =  dept.id ;
 2>显示内连接
 语法:
 select 字段名称 from 表名1 (inner) join 表名2  on 连接条件; 如果有多个条件后面and连接
--举例
-- 需求:查询员工表的编号,姓名,工资,入职日期,以
--及部门表的部门名称
SELECT 
  e.id '员工编号',
  e.`name` '员工姓名',
  e.`salary` '工资',
  e.`join_date` '入职日期',
  d.`name` '部门名称' 
FROM
  employee e 
  INNER JOIN dept d  -- inner可以省略
    ON e.`dept_id` = d.`id` ;

外连接查询使用:
1>左外连接(经常使用)
使用原则: 将A表(左表) 和 B表的交集数据(有连接条件的数据) 以及A表的所有全部查询
语法: select 字段名 from 表名1 left outer join 表名2 on 连接条件 ;
-- outer 可以省略不写 
2>  右外连接
使用原则:将A表(左表) 和 B表(右表)的交集数据以及右表左右的数据查询
语法:select 字段名 from 表名1 right outer join 表名2 on 连接条件;
子查询:
select嵌套select 查询法
1)情况一:在where条件后面使用运算符之类去进行嵌套查询
 --1)查询出最高工资是多少
-- select max(salary) from employee ;-- 15000
-- 2) 查询员工工资是15000的员工姓名,年龄,工资以及部门信息
SELECT 
  e.`name` '姓名',
  e.age '年龄',
  e.`salary`,
  d.`name` '部门名称' 
FROM
  employee e,
  dept d 
WHERE e.`dept_id` = d.`id` 
  AND e.`salary` = 
  (SELECT 
    MAX(salary) 
  FROM
    employee) ;
2)情况二:使用in(值1, 值2, 值3,..) in集合语句
-- 需求:查询出在市场部和财务部的员工所有信息以及部门所有信息

– 1)查询出市场部和财务部的部门id号是多少
– select id from dept where name = ‘财务部’ or name= ‘市场部’ ;
– 2)查询在2号部门和3号部门的所有员工信息以及部门信息

SELECT 
  e.*,
  d.* 
FROM
  employee e,
  dept d 
WHERE e.`dept_id` = d.`id` 
  AND e.`dept_id` IN 
  (SELECT 
    id 
  FROM
    dept 
  WHERE NAME = '财务部' 
    OR NAME = '市场部') ;

– 3)子查询情况3
– 将某条select语句查询的 结果当做一个"虚表",
– 使用这个虚表和其他表关联查询
– 需求:查询:入职日期大于’2017-12-30’的员工所有信息以及部门名称信息

– 查询出入职日期大于’2017-12-30’的员工信息- —>查出来的结果当做一个表(虚表),使用这个虚表和部门表关联查询

SELECT 
  t.id '员工编号',
  t.name '员工姓名',
  t.age '年龄',
  t.salary '工资',
  t.join_date '入职时间',
  d.`name` '部门名称' 
FROM
  (SELECT 
    * 
  FROM
    employee 
  WHERE employee.`join_date` > '2017-12-30') t 
  LEFT OUTER JOIN dept d -- 部门表
    ON t.dept_id = d.id ;
    
  -- 优化---纯使用where条件 隐式内连接
SELECT 
  e.*,
  d.`name` '部门名称' 
FROM
  employee e,
  dept d 
WHERE e.`dept_id` = d.`id` 
  AND e.`join_date` > '2017-12-30' ;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值