Java 25-Java基础知识复习②
1.Junit测试-单元测试
测试分为黑盒测试和白盒测试,其中黑盒最为简单,不用管运行逻辑,只管input和output;白盒测试需要写一些代码,结合input和output查看运行效果。传统测试方法,多次调用容易混淆输出结果,单独新建
使用junit测试步骤:
①定义一个测试类(测试用例)
建议:测试类名: 被测试的类名Test DemoTest
包名 : xxx.xxx.xx.test cn.itcast.test
②定义测试方法:可以独立运行
建议:方法名:test测试的方法名 testAdd();
返回值 :void
参数列表:空参 不调用 有参数没意思
注意: 方法上@Test
导入Jnuit依赖-导包
③判断结果:执行日志 绿色字体代表成功,红色字体代表出现bug
④ 特别说明-断言Assert.assert(期望值,实际值):
某些时候,代码编写出错junit输出结果不是预期,那么如何有效核实,可以用断言来判断。Assert.assertEquals(3,result)
⑤特别说明:@Before和@After -用于重复使用,例如啥资源申请或释放,其他代码会在此期间执行,那么久可以用这两个注解来先和后执行。
反射:俗称框架设计的灵魂,在未来框架中,进行开发可以简化代码。一句话:反射就是将类的各个组成部分封装为其他对象,这就是反射机制。参考下图理解:
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运行阶段。但其实这中间有个第二阶段就是讲字节码文件加载进入内存中,我们才能有这个对象。
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类对象。
第二种:Class类对象阶段,也就是已经加载进内存中,那么可以
类名.class:通过类名.class属性获取class类对象。
第三种:运行期阶段,也就是已经产生new对象。
对象.getClass();getClass方法封装在object中,所有对象都可用
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):暴力反射,设置暴力反射后,再给定值,获取值。
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()
(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方法在其中数组。
获取成员方法的方法名:
遍历得到的方法数组的某一个值.getName()即可
案例:写一个假框架,在不改任何该类的代码情况下,帮我创建任意类的对象,并且执行任何方法
思路:
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文件里面的配置消息接口
3.注解
* 概念:说明程序的。给计算机看的
* 注释:用文字描述程序的。给程序员看的
* 定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
* 概念描述:
* JDK1.5之后的新特性
* 说明程序的
* 使用注解:@注解名称
****** * 功能作用分类:
①编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
③编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override 检查是否是重写 】
******(1)JDK中预定义的一些注解
* @Override :检测被该注解标注的方法是否是继承自父类(接口)的
* @Deprecated:该注解标注的内容,表示已过时
* @SuppressWarnings:压制警告
* 一般传递参数all @SuppressWarnings("all"),也有在类上加这个注解的。
******(2)自定义注解
* 格式:元注解+public @interface 注解名称
元注解
public @interface 注解名称{
属性列表;
}
* 本质:注解本质上就是一个接口,该接口默认继承Annotation接口
* public interface MyAnno extends java.lang.annotation.Annotation {}
* 属性:接口中的抽象方法,也就是自定义注解中可以定义的成员方法。
* 要求:
1. 属性的返回值有下列取值(不能是void,不能是某个类类型)
* 基本数据类型 * String * 枚举 * 注解 * 以上类型的数组
2. 定义了属性,在使用时需要给属性赋值(其实就是给抽象方法赋值,因此我们把注解里面的抽象方法称之为属性,多个属性值,逗号隔开)
(1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
( 2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
(3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
* 元注解:用于描述注解的注解,还是注解(下面四个是常用的)
* @Target:描述注解能够作用的位置
* ElementType取值: * TYPE:可以作用于类上; * METHOD:可以作用于方法上; * FIELD:可以作用于成员变量上,下为源码
* @Retention:描述注解被保留的阶段
* @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到;SOURCE(源码阶段),我们一般是runtime选择。如果是class不会虚拟机读取到,如果是source是连字节码文件都不会存在了。
* @Documented:描述注解是否被抽取到api文档中(有就显示注解,没有就不显示注解) javadoc输出文档
* @Inherited:描述注解是否被子类自动继承
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AnonotationTest { //抽象方法 public abstract String name(); }
******(3)在程序使用(解析)注解:获取注解中定义的属性值
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. 调用注解中的抽象方法获取配置的属性值,下面就拿到值了
com.itheima.annotation.DemoOne show
如果注解加载在方法上,方法也有getAnonotation获取注解属性
注解与反射两种不同形式的伪框架
******案例-简单的测试注解框架
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
数据目录:
各个文件夹其实是一个数据库
各个文件夹内.frm文件是表
各个表其实是各种记录数据存储在里面
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
***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数据类型:
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 或者空格加中文也行
**********条件查询
where 条件 其中条件涉及运算符如下:
-- 查询年龄大于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
多个字段排序,后面第二排序条件是前面第一排序字段是一样的时候才作用
************DQL聚合查询 COUNT MAX MIN SUM AVG
聚合意思是:将一列数据作为一个整体,进行纵向计算。
select COUNT(列名) from student;计算某一列数量,结果是单行单列,切记是排除非空的数据
************DQL分组查询 group by having
语法:分组查询中select后面只能是分组字段以及聚合函数,其他无意义。
select ExpertSex AS 性别,count(*) as 总计 from expert_base_info GROUP BY ExpertSex;
select ExpertSex AS 性别,count(*) as 人数,SUM(ExpertSex) as 总计 from expert_base_info GROUP BY ExpertSex;
where条件筛选和分组查询结合使用。
复杂分组和分组后继续删选,人数大于2的才进行显示 having
where在分组钱进行限定,如果不满足条件,则不参与分组
having在分组之后进行限定,如果不满足结果,则不会被查询出来
where后不可跟聚合函数判断,而having可以进行聚合函数判断
************DQL分页查询 limit 开始的索引,每页显示的条数。每个sql不一样。
*************约束-对表中的数据进行限定,保证数据正确性,有效性和完整性
(非空约束)not null
(唯一约束) unique 某一列值不能重复,需要唯一,唯一约束可有唯一null
删除表设置的唯一 alter table stu drop index phone_number;
给老表添加唯一 alter table stu modify phone varchar(20) unique;
(主键约束)primary key-非空且唯一 一张表只能有一个主键,唯一标识
删除表主键约束 alter table 表名 drop primary key;
给老表添加主键 alter table 表名 modify 列名 数据类型 primary key;
(主键自增长)某列是数值类型 auto_increment 自动增长
insert into 表名 values(null,123)--自动增加给null即可,若给数字就下次在此数字上加一,它只以上一行记录为准加1
删除自增长 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,'销售部','深圳');
CONSTRAINT 外键名称 FOREIGN KEY (外键列名称) REFERENCES 主表名称(主表列名称)
(外键约束-级联操作)
*************多表之间的关系与设计数据库要求
多对多关系实现 需要借助第三张中间表,中间表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张表的主键,当然需要用到联合主键,保证中间表两个字段联合唯一。PRIMARY KEY(rid,uid)
一对一关系实现 需要在任意一方添加唯一的外键指向另外一方的主键
一对多关系实现 需要在多的一方建立外键,指向一的一方主键,不需要唯一
------------案例
*************数据库设计范式
也就是说 传递依赖要解决,就是一对多必须处理
**************数据库备份与还原
命令行 备份:mysqldump -uroot -proot 数据库名称 > 保存的路径
还原:source 路径+数据库名称;
**************多表查询
--------内连接--隐式内连接where条件 / 显示内连接 inner join 表名2 on 条件
SELECT * FROM emp,dept WHERE emp.dept_id= dept.id
SELECT emp.name,emp.gender,dept.name FROM emp,dept WHERE emp.dept_id= dept.id
全部字段: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
-------------外连接 --左外连接和右外连接
左外连接
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
右外连接 也就是右边表全部数据和左边表交集部分
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)
*****子查询结果是单行单列
子查询作为判断条件,查询结果
*****子查询结果是多行单列
*****子查询结果是多行多列
**************事务
**************DCL
5.JDBC