Java 25-Java基础知识复习②

1.Junit测试-单元测试

          测试分为黑盒测试和白盒测试,其中黑盒最为简单,不用管运行逻辑,只管input和output;白盒测试需要写一些代码,结合input和output查看运行效果。传统测试方法,多次调用容易混淆输出结果,单独新建

1619165095(1)

使用junit测试步骤:

①定义一个测试类(测试用例)

    建议:测试类名: 被测试的类名Test DemoTest

              包名  : xxx.xxx.xx.test        cn.itcast.test

②定义测试方法:可以独立运行

      建议:方法名:test测试的方法名    testAdd();

                返回值 :void

                参数列表:空参  不调用 有参数没意思

                注意: 方法上@Test

                导入Jnuit依赖-导包

③判断结果:执行日志 绿色字体代表成功,红色字体代表出现bug

④ 特别说明-断言Assert.assert(期望值,实际值):

某些时候,代码编写出错junit输出结果不是预期,那么如何有效核实,可以用断言来判断。Assert.assertEquals(3,result)

image

⑤特别说明:@Before和@After -用于重复使用,例如啥资源申请或释放,其他代码会在此期间执行,那么久可以用这两个注解来先和后执行。

image


2.反射

        反射:俗称框架设计的灵魂,在未来框架中,进行开发可以简化代码。一句话:反射就是将类的各个组成部分封装为其他对象,这就是反射机制。参考下图理解:

java代码在计算机中经历的三个阶段:

首先我们在ide开发工具中,假设写某个person类,包含成员变量和构造方法,成员方法,通过javac编译 形成一个Person.class字节码文件,当然我们看不懂字节码文件,但其字节码Person.class文件主要包含三块内容:成员变量内容,构造方法内容,成员方法内容等等,也有类名称等信息。此时切记 类文件person.java和person.class都在电脑硬盘上存储着。此阶段是Source源代码阶段-并未进内存

中间:有个东西:类加载器(对应着java中的对象ClassLoader)可以将源代码中的字节码.class文件加载进入内存中。那么此时产生一个问题,在内存中怎么描述这个字节码文件.class加载后情况:java中一切皆对象,这个把字节码文件经过类加载器classLoader加载进入内存后形成新的对象 叫 Class类对象(描述所有字节码文件进入内存后对象,共性抽取为将成员变量封装为Field数组对象装载所有成员变量 构造方法封装为Constructor数组对象装载 ,成员方法封装为method数组对象装载),最终我们根据class类对象的行为来创建new 对象

最后 我们常见是用new对象 如 new Person(),进行使用,这个阶段称之为Runtime运行阶段。但其实这中间有个第二阶段就是讲字节码文件加载进入内存中,我们才能有这个对象。

image

2.1 反射的好处:

1)可以在程序的运行过程中,操作这些对象。例如我们在idea 编写string str=“123”; 我们可以用str.很多方法出来,这里其实就是用到了反射:细想一下:idea时刻在运行,我们的str定义出来后,它string类的方法类加载器进入到class类对象的method方法中,同时把str加载进入内存,这样我们新建的对象也就可以直接使用了string其他方法了。

2)可以解耦,提供程序的可扩展性。


2.2. 反射的API操作

        我们前面讲了,从class类对象阶段到创建对象进入runtime运行时阶段,最为关键的是如何获取class类对象(因为我们要用成员变量操作对象 Field[],构造方法操作对象 Constructor[] 成员方法操作对象Method[] ,肯定是要先获取Class类对象)

******获取Class类对象的三种方法:分别对应java代码三种阶段

第一种:java源代码阶段-Person.java编译为Person.class(仍然是源代码)

            Class.forName("全限定类名");将字节码.class文件加载进内存,返回class类对象。

image

第二种:Class类对象阶段,也就是已经加载进内存中,那么可以

              类名.class:通过类名.class属性获取class类对象。

第三种:运行期阶段,也就是已经产生new对象。

             对象.getClass();getClass方法封装在object中,所有对象都可用

image

public class ReflectDemoOne {
    /**
     * 获取类的三种方式
     * 源代码阶段 Class.forName("全限定类名"),返回内存中的class类对象
     * class类对象阶段:类名.class属性即可,此时已经在内存中
     * 运行期阶段:对象.getClass();getClass()方法在object中
     */
    public static void main(String[] args) {
        try {
            //第一种方式:源代码阶段 class.forName
            Class<?> personClass = Class.forName("com.itheima.domain.Person");
            System.out.println(personClass);//class com.itheima.domain.Person
            //第二种方式:class类对象阶段 类名.class获取
            Class<Person> personClassTwo = Person.class;
            System.out.println(personClassTwo);//class com.itheima.domain.Person
            //第三种方式:对象.getClass()方法获取
            Class<? extends Person> personClassThree = new Person().getClass();
            System.out.println(personClassThree);//class com.itheima.domain.Person
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

结论:同一个字节码.class文件,在一次程序运行中,class类对象是唯一的。

第一种全限定类名 因为传递的是字符串 多用于配置文件

第二种多用于参数传递,如某个方法里面需要class.类对象。就类名.class即可

第三种多用于对象的获取字节码的方式。

2.3 class类对象的功能

* 获取功能:

(1)获取成员变量们

* Field[] getFields() :获取所有public修饰的成员变量

* Field getField(String name) 获取指定名称的 public修饰的成员变量

* Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符

* Field getDeclaredField(String name) :获取指定名称的的成员变量,不考虑修饰符

(2)获取构造方法们

* Constructor<?>[] getConstructors()

* Constructor<T> getConstructor(类<?>... parameterTypes)

* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)

* Constructor<?>[] getDeclaredConstructors()

(3)获取成员方法们:

* Method[] getMethods()

* Method getMethod(String name, 类<?>... parameterTypes)

* Method[] getDeclaredMethods()

* Method getDeclaredMethod(String name, 类<?>... parameterTypes)

(4)获取全类名

  * String getName()对象.getName()获取全限定类名。返回由类对象表示的实体(类、接口、数组类、原始类型或空白)的名称,作为string。

* Field:成员变量对象 * 操作:

(1). 设置值 * void set(Object obj, Object value) :将指定的参数上的此field对象表示的字段设置为指定的新值。

(2) 获取值 * get(Object obj) :返回改所表示的字段的值field,指定对象上

(3)忽略访问权限修饰符的安全检查  * setAccessible(true):暴力反射,设置暴力反射后,再给定值,获取值。

image

    public static void main(String[] args) {
        //1.获取Person的class对象.用第二种方式获取,类名.class
        Class<Person> personClass = Person.class;
        try {
            //2.获取成员变量们
            Field field = personClass.getField("height");
            Person person = new Person();


            //set(对象)设置值
            field.set(person,123);
            //get(对象)获取值 ,person的height是public修饰,int类型,默认值为0
            Object value = field.get(person);
            System.out.println(field);//public int com.itheima.domain.Person.height
            System.out.println(value);//123
            System.out.println(person);//Person{name='null', age=0, height=123}
        }


* Constructor:构造方法们

最为主要的要注意获取构造方法时,需要给予指定的构造方法参数的类型,也就是class,例如int 是Intage


(1) 创建对象:

           * T newInstance(Object... initargs) : 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法

    public static void main(String[] args) {
        //1.获取Person的class对象.用第二种方式获取,类名.class
        Class<Person> personClass = Person.class;
        //2.获取构造方法们
        try {
            Person person = personClass.getConstructor(String.class,Integer.class).newInstance("123", 123);
            System.out.println(person);

如果是直接获取空参构造器创建对象,也可以直接用class类对象来newInstance。:object person =personclass.newInstance() 


* Method:方法对象

(1)执行方法: * Object invoke(Object obj, Object... args)

(2)获取方法名称: * String getName:获取方法名


    public static void main(String[] args) {
        try {
            //1.获取Person的class对象.用第二种方式获取,类名.class
            Class<Person> personClass = Person.class;
            //2.获取无参成员方法
            Method eat = personClass.getMethod("eat");
            Person person=new Person();
            //3.方法对象执行方法 方法对象.invoke(类对象,参数列表)
            Object invoke = eat.invoke(person);
            System.out.println(invoke);

            //4 获取有参成员方法 class类对象.getMethod(方法名,参数类对象.class)
            Method getFood = personClass.getMethod("getFood", String.class);
            getFood.invoke(person,"小米粥");

切记 getMethods方法获取的方法数组,会包含其父类的方法,本例子中person默认继承父类object,因此会有object方法在其中数组。

image

获取成员方法的方法名:

      遍历得到的方法数组的某一个值.getName()即可

image

案例:写一个假框架,在不改任何该类的代码情况下,帮我创建任意类的对象,并且执行任何方法

思路:

1.将需要创建的对象的全类名和需求执行的方法定义在配置文件中

2.在程序中加载配置文件

3.使用反射技术来加载类文件进内存

4.创建对象

5.执行方法

public class ReflectDemoFour {
    public static void main(String[] args) {

        try {
            //1.创建对象,load配置文件,此前学过 properties对象,可以将properties类文件读取进内存,成为集合
            Properties properties = new Properties();

            //1.1. 获取字节码文件的类加载器,是这个类加载器将类ReflectDemoFour加载进内存的
            ClassLoader classLoader = ReflectDemoFour.class.getClassLoader();
            //1.2 classloader加载器有两个方法 getResource()直接返回资源路径 和getResourceAsStream(文件名)-返回文件路径的字节流
            URL resource = classLoader.getResource("pro.properties");
            System.out.println(resource);//file:/D:/Code/IDEA/eesy_spring/target/classes/pro.properties
            InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
            //1.3 properties对象的load方法,给予字节流或字符流,我们用上面class目录下的配置文件,也就是classloader加载器
            properties.load(resourceAsStream);//加配置文件进入内存

            //2 获取配置文件中定义的数据
            String className = properties.getProperty("className");//我们要加载类的文件名
            String methodName = properties.getProperty("methodName");//我们要加载类的方法


            //3.加载该类进内存,获取class类对象,有了类对象,就可以创建对象
            Class<?> aClass = Class.forName(className);
            //3.1 创建对象
            Object obj = aClass.newInstance();
            //3.2 获取方法对象,名字已经从配置文件中获取到
            Method method = aClass.getMethod(methodName);

            //4.执行方法
            method.invoke(obj);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

如此 我们只要改配置文件 pro.properties文件里面的配置消息接口

image




3.注解
     * 概念:说明程序的。给计算机看的
     * 注释:用文字描述程序的。给程序员看的

    * 定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
     * 概念描述:
         * JDK1.5之后的新特性
         * 说明程序的
         * 使用注解:@注解名称
        
    
****** * 功能作用分类:
         ①编写文档:通过代码里标识的注解生成文档【生成文档doc文档】

image1619334943(1)
         ②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
         ③编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override 检查是否是重写 】


******(1)JDK中预定义的一些注解
         * @Override    :检测被该注解标注的方法是否是继承自父类(接口)的
         * @Deprecated:该注解标注的内容,表示已过时

image
         * @SuppressWarnings:压制警告
             * 一般传递参数all  @SuppressWarnings("all"),也有在类上加这个注解的。

image

******(2)自定义注解

image
         * 格式:元注解+public @interface 注解名称
             元注解
             public @interface 注解名称{
                 属性列表;
             }

        * 本质:注解本质上就是一个接口,该接口默认继承Annotation接口
             * public interface MyAnno extends java.lang.annotation.Annotation {}

        * 属性:接口中的抽象方法,也就是自定义注解中可以定义的成员方法。
             * 要求:
                 1. 属性的返回值有下列取值(不能是void,不能是某个类类型
                     * 基本数据类型   * String   * 枚举   * 注解    * 以上类型的数组

image

                2. 定义了属性,在使用时需要给属性赋值(其实就是给抽象方法赋值,因此我们把注解里面的抽象方法称之为属性,多个属性值,逗号隔开

image1619336225(1)
(1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。

image
( 2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。

image

1619336423(1)

枚举赋值image

注解类型:image

(3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
        
image
         * 元注解:用于描述注解的注解,还是注解(下面四个是常用的)

image
             * @Target:描述注解能够作用的位置
                 * ElementType取值: * TYPE:可以作用于类上;  * METHOD:可以作用于方法上;      * FIELD:可以作用于成员变量上,下为源码

1619336841(1)1619336848(1)
image

* @Retention:描述注解被保留的阶段
                 * @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到;SOURCE(源码阶段),我们一般是runtime选择。如果是class不会虚拟机读取到,如果是source是连字节码文件都不会存在了。

imageimage
          * @Documented:描述注解是否被抽取到api文档中(有就显示注解,没有就不显示注解) javadoc输出文档
          * @Inherited:描述注解是否被子类自动继承

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AnonotationTest {
    //抽象方法
    public abstract String name();
}



******(3)在程序使用(解析)注解:获取注解中定义的属性值

image
         1. 获取注解定义的位置的对象  (Class,Method,Field)
         2. 获取指定的注解
             * getAnnotation(Class)
             //其实就是在内存中生成了一个该注解接口的子类实现对象

                    public class ProImpl implements Pro{
                         public String className(){
                             return "cn.itcast.annotation.Demo1";
                         }
                         public String methodName(){
                             return "show";
                         }
                     }
         3. 调用注解中的抽象方法获取配置的属性值,下面就拿到值了

image

com.itheima.annotation.DemoOne
show

如果注解加载在方法上,方法也有getAnonotation获取注解属性

image

注解与反射两种不同形式的伪框架

image

******案例-简单的测试注解框架

public class TestCheck {
    public static void main(String[] args) throws IOException {

        //1.创建计算器对象
        Calculator calculator = new Calculator();
        //2.获取字节码文件对象
        Class<? extends Calculator> calculatorClass = calculator.getClass();
        //3.通过字节码文件对象,获取所有注解的方法
        Method[] methods = calculatorClass.getMethods();
        int number=0;//出现异常的次数
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("bug.txt"));
        //4.判断方法,是否有check注解,执行方法
        for (Method method : methods) {
            boolean annotationPresent = method.isAnnotationPresent(Check.class);
            if (annotationPresent==true){
                try {
                    Object invoke = method.invoke(calculator);
                } catch (Exception e) {
                    //记录文件信息
                    number++;
                    bufferedWriter.write("1: "+method.getName()+"方法出异常了");
                    bufferedWriter.newLine();
                    //类对象可以通过getName或者getSimpleName取得剪短类名
                    bufferedWriter.write("2: 异常的名称"+e.getCause().getClass().getSimpleName());
                    bufferedWriter.newLine();
                    bufferedWriter.write("3: 异常的原因"+e.getCause().getMessage());
                    bufferedWriter.newLine();
                    bufferedWriter.write("---------------");
                    bufferedWriter.newLine();

                }
            }
        }
        bufferedWriter.write("总结;本次测试,一共出现"+number+"次异常");
        bufferedWriter.close();
    }


}
package com.itheima.annotation.demo;

public class Calculator {

    @Check
    public void add(){
        System.out.println("1+1="+(1+1));
    }

    @Check
    public void sub(){
        System.out.println("1-1="+(1-1));
    }

    @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("1+1="+(1+1));
    }
}
package com.itheima.annotation.demo;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}


4.mysql

************mysql目录结构-安装目录和数据目录

安装目录下 bin data  include lib share等文件夹

其中bin有很多exe命令文件,此前我们是将bin目录放在环境变量中,因此当我们cmd控制台交互时,其实就是运行mysql.exe文件命令、

data是数据目录

include是放置一些c语言的头目录

lib是相当于运行时需要的各类支持包文件

share放置一些mysql运行错误信息

最为重要的ini文件:未来设置数据库可能要找到它  my.ini

image

数据目录:

各个文件夹其实是一个数据库

各个文件夹内.frm文件是表

各个表其实是各种记录数据存储在里面

1619344045(1)

4.1. sql概念和基本语法

       sql全程 structured query language 结构化查询语言,定义了操作关系型数据库的语言规则。每一种数据库略微有差异。

cmd中 登录sql  ->mysql -uroot  -proot

通用语法:

*1. sql是单行,每行以分号;结尾。建议空格提高可读性

*2. cmd中:show databases; 查看mysql里有多少数据库

*3. mysql中不区分大小写,建议关键字大写

*4.  -- 单行注释内容  # 单行注释内容   /*多行注释内容*/


SQL分类语句:CREATE 创建 RETRIEVE 查询 Upudate 修改 Delete删除

DDL:数据库定义语言:create  drop  alter    建库建表建列

DML:数据库操作语言:insert delete update 增删改

DQL:数据库查询语言:select where等           查询

DCL:数据库控制语言:grant revoke

image

***show databases; 出现中其中performance_schema是性能方面,test为空的,我们一般就用mysql里面

***show create database mysql;  可以看见创建mysql默认字符集 utf-8

(1)DDL:数据库定义语言-DDL创建

***create database db1;创建数据库db1;

***create database if not db1;如果不存在db1,则创建,不会报错

***create database db3 character set gbk ;创建db3,且字符集设为gbk

create table 表名 (

    列名1 数据类型1,

   ......

   列名n  数据类型n


); 创建某个表,括号内给字段和字段类型

sql数据类型:

imageimage

create table 表1 like 表2;复制一个表1,参考表2 ;

-------------DDL修改

alter database 数据库名称 character set 字符集;修改数据库字符集;

alter table 表名 rename to 新表名;修改表名

show create table 表名;查看表的字符集和字段

alter table 表名 character set utf-8;修改表的字符集

alter table 表名 add 列名 数据类型;添加表一列

alter table 表名 change 列名1 列名2 列名2数据类型;修改表某一列名

alter table 表名 modify 列名1 列名1数据类型;修改某一列数据类型

alter table 表名 drop 列名;删除某一列;

-------------DDL删除

drop database db1;删除数据库名称;

drop database if exists 数据库名称;若数据库存在,则删除;

drop table 表名 ;

drop table if exists 表名;删除某一表,若存在


--------------DDL查询

select database();查询当前正在使用的数据库;

use db1;使用数据库db1;

show tables;查询某个数据库下有多少个表

desc 表名;查询表结构

**********************DML 数据库操作语言 增删改表中数据

————————DML添加数据

基本语法

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

列名和值一一对应

如果表名后不定义列名,则默认给所有列添加值;

除了数字类型,其他类型要用引号包裹着;日期也要横杠区分 引号包裹



————————DML删除表中的数据

* delete from 表名 [ where 条件]

例如 delete from stu where id=1;

若不加where ,则删除所有数据;

delete from 表名;删除表记录,一条一条删,效率低

truncate table 表名:删除表,再创建一个一模一样的空表,效率比上面高


————————DML修改数据

update 表名 set 列名1=值1,列名2=值2...... [ where 条件]

update student set age=3 where id=3;当id=3,修改其年龄为3;

update student set 列名X=值X;不加条件,则所有这个列都改为值X



********************DQL 查询语句

**********基本查询  多字段查询-去重-计算列-判断null-起别名

select * from  表名; 查询某表全部数据,*代表所有列的简化写法

select  列名1,列名2 ,...列名n  from 表名; 查询某表的几列字段数据(未出现列名的则不会显示)

select DISTINCT 列名 from 表名;查询某列,自动清除重复

select DISTINCT 列名1 ,列名2 from 表名;查询某两列,自动清除两列一样的情况下才重复;


select 列名1,列名2,列名3,列名2+列名3 from 表名:查询某表,并计算列名2和列名3之和显示出来。

select 列名1,列名2,列名3,列名2+IFNULL(列名3 ,0)from 表名:查询某表,并计算列名2和列名3之和显示出来(若遇到null ,设为0,否则+null是null,不是我们想要的接口)。


select 列名1,列名2,列名3,列名2+IFNULL(列名3 ,0) as 总分from 表名:查询某表,并计算列名2和列名3之和显示出来(若遇到null ,设为0,否则+null是null,不是我们想要的接口)。起别名用as  或者空格加中文也行

image


**********条件查询

where 条件  其中条件涉及运算符如下:

1619400277(1)

1619400533(1)

1619400550(1)

-- 查询年龄大于20岁

SELECT * FROM student WHERE age > 20;

SELECT * FROM student WHERE age >= 20;


-- 查询年龄等于20岁

SELECT * FROM student WHERE age = 20;


-- 查询年龄不等于20岁

SELECT * FROM student WHERE age != 20; SELECT * FROM student WHERE age <> 20;


-- 查询年龄大于等于20 小于等于30

SELECT * FROM student WHERE age >= 20 && age <=30;

SELECT * FROM student WHERE age >= 20 AND age <=30;

SELECT * FROM student WHERE age BETWEEN 20 AND 30;


-- 查询年龄22岁,18岁,25岁的信息 OR关键字  IN 关键字


SELECT * FROM student WHERE age = 22 OR age = 18 OR age = 25

SELECT * FROM student WHERE age IN (22,18,25);


-- 查询英语成绩为null                   IS NULL 是NULL关键字

SELECT * FROM student WHERE english = NULL; -- 不对的。null值不能使用 = (!=) 判断

SELECT * FROM student WHERE english IS NULL;


-- 查询英语成绩不为null             IS NOT NULL 不为NULL关键字

SELECT * FROM student WHERE english IS NOT NULL;


***********模糊查询   like模糊查询 配合%和_两种占位符

_下划线代表任意单个字符 %百分号代表任意个字符

-- 查询姓马的有哪些? like         like 与%占位符的模糊查询

SELECT * FROM student WHERE NAME LIKE '马%';


-- 查询姓名第二个字是化的人     like 与%占位符的模糊查询

SELECT * FROM student WHERE NAME LIKE "_化%";


-- 查询姓名是3个字的人              like 与_下划线数量的模糊查询

SELECT * FROM student WHERE NAME LIKE '___';


-- 查询姓名中包含德的人            like 与%占位符的模糊查询

SELECT * FROM student WHERE NAME LIKE '%德%';



************DQL排序查询  默认升序,不给排序方式就升序 ASC 

                                                 降序 DESC

语法: order by 排序字句

           order by 排序字段1 排序方式1,排序字段2 排序方式2

image

多个字段排序,后面第二排序条件是前面第一排序字段是一样的时候才作用

image

************DQL聚合查询  COUNT  MAX MIN SUM  AVG

聚合意思是:将一列数据作为一个整体,进行纵向计算。

select COUNT(列名) from student;计算某一列数量,结果是单行单列,切记是排除非空的数据

image





************DQL分组查询 group by  having

语法:分组查询中select后面只能是分组字段以及聚合函数,其他无意义。

select ExpertSex AS 性别,count(*) as 总计 from expert_base_info GROUP BY ExpertSex;

image

select ExpertSex AS 性别,count(*) as 人数,SUM(ExpertSex) as 总计 from expert_base_info GROUP BY ExpertSex;

image

where条件筛选和分组查询结合使用。

image

复杂分组和分组后继续删选,人数大于2的才进行显示  having

image

where在分组钱进行限定,如果不满足条件,则不参与分组

having在分组之后进行限定,如果不满足结果,则不会被查询出来

where后不可跟聚合函数判断,而having可以进行聚合函数判断

image

************DQL分页查询 limit 开始的索引,每页显示的条数。每个sql不一样。


image


*************约束-对表中的数据进行限定,保证数据正确性,有效性和完整性

(非空约束)not null

          创建表时,设置非空image

         删除表设置的非空 image

          给老表添加非空image


(唯一约束) unique 某一列值不能重复,需要唯一,唯一约束可有唯一null

         创建表时,设置唯一image

         删除表设置的唯一  alter table stu drop index phone_number;

          给老表添加唯一 alter table stu modify phone varchar(20) unique;

(主键约束)primary key-非空且唯一 一张表只能有一个主键,唯一标识

         创建表时,设置主键 image

         删除表主键约束    alter table 表名 drop primary key;

         给老表添加主键 alter table 表名 modify 列名 数据类型 primary key;




(主键自增长)某列是数值类型  auto_increment 自动增长

insert into 表名 values(null,123)--自动增加给null即可,若给数字就下次在此数字上加一,它只以上一行记录为准加1

image

删除自增长 alter table 表名 modify 列名 列数据类型;

添加老表自增长 alter table 表名 modify 列名 列数据类型 auto_increment;


(外键约束)foreign key

create table emp(
     id INT(20) PRIMARY KEY,
         NAME VARCHAR(30),       
         age INT(20),
         dep_name VARCHAR(30),
         dep_location VARCHAR(30)
        
);


SELECT * FROM emp;
ALTER table emp CHARACTER set utf8;
alter table emp change name name varchar(255) character set utf8;
alter table emp change dep_name dep_name varchar(255) character set utf8;
alter table emp change dep_location dep_location varchar(255) character set utf8;

INSERT INTO emp (id,NAME,age,dep_name,dep_location) VALUES(1,'123',20,'研发部','广州');
INSERT INTO emp (id,NAME,age,dep_name,dep_location) VALUES(2,'李四',20,'研发部','广州');
INSERT INTO emp (id,NAME,age,dep_name,dep_location) VALUES(3,'王五',20,'研发部','广州');
INSERT INTO emp (id,NAME,age,dep_name,dep_location) VALUES(4,'赵六',20,'销售部','深圳');
INSERT INTO emp (id,NAME,age,dep_name,dep_location) VALUES(5,'大王',20,'销售部','深圳');
INSERT INTO emp (id,NAME,age,dep_name,dep_location) VALUES(6,'小王',20,'销售部','深圳');
INSERT INTO emp (id,NAME,age,dep_name,dep_location) VALUES(7,'二王',20,'销售部','深圳');

image

1619487599

image

CONSTRAINT 外键名称 FOREIGN KEY (外键列名称) REFERENCES 主表名称(主表列名称)


(外键约束-级联操作)

image


*************多表之间的关系与设计数据库要求

image

image

imageimage

多对多关系实现 需要借助第三张中间表,中间表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张表的主键,当然需要用到联合主键,保证中间表两个字段联合唯一。PRIMARY KEY(rid,uid)

一对一关系实现 需要在任意一方添加唯一的外键指向另外一方的主键

一对多关系实现 需要在多的一方建立外键,指向一的一方主键,不需要唯一

------------案例

1619491406(1)


*************数据库设计范式

1619491995(1)

1619492392(1)

image

image

也就是说 传递依赖要解决,就是一对多必须处理


**************数据库备份与还原

命令行 备份:mysqldump -uroot -proot 数据库名称 > 保存的路径

           还原:source 路径+数据库名称;

**************多表查询

--------内连接--隐式内连接where条件 / 显示内连接 inner join 表名2 on 条件

SELECT * FROM emp,dept WHERE emp.dept_id= dept.id

1619495941(1)

SELECT emp.name,emp.gender,dept.name FROM emp,dept WHERE emp.dept_id= dept.id

1619495968(1)

全部字段:SELECT * FROM emp INNER JOIN dept ON emp.dept_id = dept.id;

指定字段:SELECT emp.id,emp.`name`,dept.`name` FROM emp INNER JOIN dept ON emp.dept_id = dept.id

image

-------------外连接 --左外连接和右外连接

左外连接

select 字段列表 from 表1 left outer join 表2 on 条件

SELECT emp.id,emp.`name`,dept.`name` FROM emp left JOIN dept on emp.dept_id=dept.id

image

右外连接 也就是右边表全部数据和左边表交集部分

SELECT emp.id,emp.`name`,dept.`name` FROM emp right JOIN dept on emp.dept_id=dept.id


-------------子查询

查询中嵌套查询,称嵌套查询为子查询

SELECT * FROM emp WHERE emp.salary=(select MAX(salary) FROM emp)

*****子查询结果是单行单列

子查询作为判断条件,查询结果

image



*****子查询结果是多行单列

image

*****子查询结果是多行多列

image

image



**************事务




**************DCL





5.JDBC








posted @ 2021-04-23 16:44  芒果侠  阅读(106)  评论(0编辑  收藏  举报