11_28

1.TCP客户端和服务器端的代码实现

TCP服务器端的代码实现

1)创建服务器端的Socket对象

2)监听客户端的连接

3)获取监听到的客户端的通道内的自节输入流对象,读数据

4)释放服务器端的资源

有关TCP客户端使用步骤

1)创建客户端的Socket对象,指定ip和端口

2)获取客户端通道内容字节输出流对象,写数据

3)释放资源

2.TCP三次握手的原理--->SYNC+ACK

SYNC同步序列编号
ACK:消息确认字符(当客户端发送数据到服务器端,服务器需要 确认并反馈)
![](D:\EE_2211\day27_code_resource\resource\02_TCP三次握手.png)

3.tcp的应用

3.1TCP方式,客户端可以不断键盘录入数据,服务器端不断展示数据

package com.qf.tcp_03;import java.io.*;
import java.net.Socket;/*** @author 高圆圆* @date 2022/11/28 11:44* 需求:*  TCP客户端不断键盘录入数据,服务器端不断展示数据*/
public class TcpClient {public static void main(String[] args) throws IOException {//1)创建客户端SocketSocket socket  = new Socket("10.35.162.121",8888) ;//2)可以创建BufferedReader 一次读取一行,录入数据BufferedReader br=  new BufferedReader(new InputStreamReader(System.in)) ;//获取通道字节输出流对象,写数据--->字节输出流---->包装字符流OutputStream out = socket.getOutputStream();//可以使用字符流把上面的通道内的字节数出流包装BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out)) ;String line = null ;while((line=br.readLine())!=null){/*if("886".equals(line)){break;}*///录入一行,给封装到通过的字符流写一行进去bw.write(line) ;bw.newLine();bw.flush();}socket.close();}
}``````java
package com.qf.tcp_03;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;/*** @author 高圆圆* @date 2022/11/28 11:44* 服务器端不断展示数据*/
public class TcpServer {public static void main(String[] args) throws IOException {//创建服务器端的SocketServerSocket ss = new ServerSocket(8888) ;System.out.println("服务器正在等待连接");// int i= 0 ;while (true){//监听多个客户端了解//   i++;//监听客户端连接Socket socket = ss.accept();//  System.out.println("第"+i+"个客户端已连接");//获取监听客户端所在的通道内的字节输入流InputStream in = socket.getInputStream();//将桶内的字节输入流封装成字符流读BufferedReader br = new BufferedReader(new InputStreamReader(in)) ;//一次读取一行String line = null ;while((line=br.readLine())!=null){if("886".equals(line)){break;}System.out.println(line) ;//展示数据}}//模拟真实场景,服务器端不关}
}

3.2 TCP客户端的读取文本文件(将文本文件写入通道中),服务器端复制文本文件到指定路径中(将文本文件写入指定文件中)

package com.qf.tcp_04;import java.io.*;
import java.net.Socket;/*** @author 高圆圆* @date 2022/11/28 14:27* 需求:*      TCP客户端的文本文件(当前项目下的UdpReceive.java文件)*              分析:TCP创建字符缓冲输入流--->读UdpReceive.java文件  一次读一行*                  TCP客户端获取通道字节输入流--->封装字符缓冲输出流--->写一行---发给服务器端***/
public class TcpClientTest {public static void main(String[] args) throws IOException {//创建客户端的Socket对象Socket s = new Socket("10.35.162.121",2222) ;//创建字符缓冲输入流对象BufferedReader br = new BufferedReader(new FileReader("UdpReceive.java")) ;//获取客户端通道的字节输出流---->包装成BufferedWriter:字符缓冲输出流BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())) ;//每次从.java文件读取一行,给通道流的流中写一行String line = null ;while((line=br.readLine())!=null){bw.write(line) ;bw.newLine();bw.flush();}System.out.println("文件读完,发送过去了...");//释放资源br.close();s.close();}
}``````java
package com.qf.tcp_04;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;/*** @author 高圆圆* @date 2022/11/28 14:27* TCP服务器端将复制客户端的文件内容,复制到D://2211//day27_code_resource//Copy.java里面*                 分析:*                        TCP获取监听客户端的字节输入流--->封装字符缓冲输入流--->一读取一行*                        创建字符缓冲输出流--->写一行D://2211//day27_code_resource//copy.java到这个文件中*/
public class TcpServerTest {public static void main(String[] args) throws IOException {//创建服务器端的Socket对象ServerSocket ss = new ServerSocket(2222) ;//监听客户端连接Socket s = ss.accept();//获取监听客户端所在的通道内字节输入流对象---->包装成字符缓冲输入流BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())) ;//将监听客户端的通道内的字节流(已经被包装了字符缓冲输入流)的内容----通过的字符缓冲输出流写入到文件中BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\EE_2211\\day27_code_resource\\copy.java")) ;//一次读取一行,写一行到文件中String line = null ;while((line=br.readLine())!=null){bw.write(line);bw.newLine();bw.flush();}System.out.println("复制完毕");//释放资源bw.close();ss.close();}
}

3.3TCP客户端读取文本文件,服务器端复制文本文件,现在服务器端反馈给客户端,"已经复制完毕"

package com.qf.tcp_05;import java.io.*;
import java.net.Socket;/*** @author 高圆圆* @date 2022/11/28 14:57* 需求*  TCP客户端的文本文件(当前项目下的UdpReceive.java文件),*  TCP服务器端复制文本文件到:D:\EE_2211\day27_code_resource\Copy.java文件中*  TCP服务器端需要响应给客户端数据 "文件复制完毕"*  TCP客户端展示服务器反馈的这个数据!***  发现问题:*          两个端都出现了互相等待了*          因为客户端的文本文件读完,是null作为结束条件,但是服务器端不断的从通道内的输入流去读数据,*   两端的通道不知道文件是否完了(服务器端不知道客户端的文件完没完),等待着写数据过来,*** 解决方案:*  通知服务器端,别等了,文件读完了*  1)自定义结束条件 ,服务器端读到自定义结束条件,就反馈!*      弊端:如果文件第一句话恰好是自定义的结束条件,就不好**  2)推荐:在客户端这边有个终止通道内的流 没有数据写过去了!禁止输出流输出!*      public void shutdownOutput()   throws IOException*****/
public class Tcp_ClientTest2 {public static void main(String[] args) throws IOException {//创建客户端的Socket对象Socket s = new Socket("10.35.162.121",2222) ;//创建字符缓冲输入流对象BufferedReader br = new BufferedReader(new FileReader("UdpReceive.java")) ;//获取客户端通道的字节输出流---->包装成BufferedWriter:字符缓冲输出流BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())) ;//每次从.java文件读取一行,给通道流的流中写一行String line = null ;while((line=br.readLine())!=null){//阻塞式方法.一直等待为null文件完毕bw.write(line) ;bw.newLine();bw.flush();}//写一个数据//通道内的流写一句/* bw.write("over");bw.newLine();bw.flush();*///方案2: public void shutdownOutput()   throws IOExceptions.shutdownOutput();//客户端要读取服务器反馈数据//获取通道内的字节输入流InputStream inputStream = s.getInputStream();//读取一个字节数组byte[] bytes = new byte[1024] ;int len = inputStream.read(bytes);System.out.println("客户端接收到了反馈数据:"+new String(bytes,0,len));//释放资源br.close();s.close();}}``````java
package com.qf.tcp_05;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;/*** @author 高圆圆* @date 2022/11/28 14:57*/
public class Tcp_ServerTest2 {public static void main(String[] args) throws IOException {//创建服务器端的Socket对象ServerSocket ss = new ServerSocket(2222) ;//监听客户端连接Socket s = ss.accept();//获取监听客户端所在的通道内字节输入流对象---->包装成字符缓冲输入流BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())) ;//将监听客户端的通道内的字节流(已经被包装了字符缓冲输入流)的内容----通过的字符缓冲输出流写入到文件中BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\EE_2211\\day27_code_resource\\copy.java")) ;//一次读取一行,写一行到文件中String line = null ;while((line=br.readLine())!=null){//阻塞式,null也是表示客户端的通道内的字节输入流读完了/*  if("over".equals(line)){break;}*/bw.write(line);bw.newLine();bw.flush();}//加入反馈,服务器端反馈给客户端数据//获取字节输出流,写OutputStream out = s.getOutputStream();out.write("hello,文件复制完毕".getBytes());out.flush();//释放资源bw.close();ss.close();}
}

4.反射

之前写代码:类名 对象名 =  new 类名() ;考虑运行阶段 Runtime

反射里面研究的类的编译阶段:  Class---->编译的过程
1.反射中如何获取类字节码文件对象
2.反射中是如何通过构造器创建对象呢?
3.通过反射创建对象之后,在去给成员变量赋值
4.通过反射创建对象之后,调用类的成员方法..

### 反射获取构造器并创建当前类实例

package com.qf.reflect_06;/*** @author 高圆圆* @date 2022/11/28 15:56*实体类*/
public class Person {private String name ; //私有的成员班里public int age ; //年龄String gender ; //性别//构造方法public Person(){}//无参构造方法private Person(String name,int age){this.name = name ;this.age = age ;}Person(String name,int age,String gender){this.name = name ;this.age = age ;this.gender = gender ;}//成员方法//没有返回值,无参public void show(){System.out.println("show Person");}//没有返回值,带参private void method(String str){System.out.println(str);}//有返回值.不带参private String function(){return "helloJavaEE" ;}//有返回值,带参String myFunction(int num){return "今晚韩国对阵加纳总球数是"+num ;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", gender='" + gender + '\'' +'}';}
}
package com.qf.reflect_06;import com.sun.xml.internal.ws.addressing.WsaActionUtil;/*** @author 高圆圆* @date 2022/11/28 15:47* 什么是反射?*      编译某个类的时候---->获取这个类的字节码文件,然后去加载,调用里面的成员方法,访问成员变量,*      通过构造方法创建对象!** 编译过程:*      对这个类的属性/成员/构造其进行校验---->类加载器(负责类的加载过程)*              BoostrapClassLoader:启动类加载器,负责java核心库,rt.jar** 如何获取一个类的字节码文件?*** java.lang.Class:代表正在运行的java类或者接口,通过静态方法* public static Class forName(String classname):* 参数:代表就是当前类或者接口的全限定名称 (包名.类名)* String---->全限定名称 java.lang.String* Person---->自定义的---->全限定名称:com.qf.reflect_06.Person**/
public class ReflectDemo {public static void main(String[] args) throws ClassNotFoundException {//如何获取一个类的字节码文件?//第一种//任意Java对象的getClass方法Person p = new Person() ;Class clazz = p.getClass();System.out.println(clazz); //class com.qf.reflect_06.Person//第二种//任意Java类型的class属性Class clazz2 = Person.class ;System.out.println(clazz2);//第三种 推荐// java.lang.Class:代表正在运行的java类或者接口,通过静态方法// public static Class forName(String classname)Class clazz3 = Class.forName("com.qf.reflect_06.Person");System.out.println(clazz3) ;System.out.println(clazz==clazz3);System.out.println(clazz2==clazz3);System.out.println("----------------------------");Person p1 = new Person() ;Person p2 = new Person() ;System.out.println(p1==p2);}
}
package com.qf.refect_07;import com.qf.reflect_06.Person;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;/*** @author 高圆圆* @date 2022/11/28 16:14* 通过反射方式获取类的字节码文件之后,创建当前类对象!** 之前的写法:考虑运行的代码 类名 对象名  = new 类名() ;** 1)获取类的字节码文件对象* 2)获取类的Constructor所在的构造器对象* 3)通过它创建当前类实例*/
public class ReflectDemo2 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//之前的写法:通过无参构造方法创建对象//类名 对象名  = new 类名() ;// Person person = new Person() ;// System.out.println(person);System.out.println("-----------------------------------------------");//通过反射获取构造器(Constructor)对象--->创建当前类实例//1)获取类的字节码文件对象Class clazz = Class.forName("com.qf.reflect_06.Person") ;//2)获取类的Constructor所在的构造器对象// public Constructor<?>[] getConstructors()获取这个类中所有的公共的构造函数// Constructor[] constructors = clazz.getConstructors();//public Constructor<?>[] getDeclaredConstructors()获取这个类中所有的构造函数/* Constructor[] constructors = clazz.getDeclaredConstructors();for(Constructor con:constructors){System.out.println(con);}*///2)获取指定的构造方法所在的Constructor类对象//public Constructor<T> getConstructor(Class<?>... parameterTypes)//获取指定的公共的构造方法所在Constructor实例,参数--->参数类型的Class字节码文件对象//参数是String----->String.class----结果 java.lang.StringConstructor con = clazz.getConstructor();// clazz.getConstructor(String.class)//System.out.println(con);//3)通过它创建当前类实例//public T newInstance(Object... initargs):参数就给构造函数中参数进行实际赋值Object obj = con.newInstance();System.out.println(obj);}
}``````java
package com.qf.refect_07;import com.qf.reflect_06.Person;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;/*** 之前的写法创建一个Person,给成员赋值* Person p = new Person("高圆圆",44) ;*/
public class ReflectDemo3 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//Person p = new Person("高圆圆",44) ;  //之前的代码不行,私有构造方法不能new//现在反射方式通过构造方法赋值//1)获取当前类的字节码文件对象Class clazz = Class.forName("com.qf.reflect_06.Person");//2)获取构造器Constructor类对象--->带两个参数的//public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)//参数里面是参数类型的字节码文件对象Constructor con = clazz.getDeclaredConstructor(String.class, int.class);// System.out.println(con);//private com.qf.reflect_06.Person(java.lang.String,int)//AccessibleObject类提供Field(成员变量的类对象)/Method(成员方法类对象)/Constructor(构造器类对象)的基类//提供功能:取消Java语言访问检查,暴力访问//public void setAccessible(boolean flag) true:就是抑制Java语言访问检查功能con.setAccessible(true);//通过它创建当前类实例Object obj = con.newInstance("高圆圆", 44);//IllegalAccessException:当前构造器私有不能访问System.out.println(obj);}
}

### 反射获取成员方法并调用

package com.qf.reflect_08;import com.qf.reflect_06.Person;import java.lang.reflect.Constructor;
import java.lang.reflect.Method;/*** @author 高圆圆* @date 2022/11/28 17:27* 在反射中如何调用成员方法**      之前的写法:无参构造方法是公共的*      Person p = new Person();*      p.show() ;*/
public class ReflectDemo4 {public static void main(String[] args) throws Exception {//之前的写法// Person p = new Person();//p.show() ;System.out.println("----------------------------------");//反射的写法//1)获取类的字节码文件对象Class clazz = Class.forName("com.qf.reflect_06.Person") ;//2)通过无参构造器创建器Constructor创建当前类实例//如果你这个类没有提供任何构造方法(系统提供无参)或者无参构造方法是公共的---->此时可以直接使用Class类的newInstacne()创建当前类实例//等价于下面这个写法Object obj = clazz.newInstance();System.out.println(obj);//System.out.println(obj);/*Constructor con = clazz.getConstructor();Object obj = con.newInstance() ;*/// System.out.println(obj);// Method getMethods() ;//获取本类中所有的成员的method// Method getDeclaredMethods() ;//获取本类中所有的成员的method以及父类的Object//3)获取指定的成员方法所在的Method类对象// public Method getDeclaredMethod(String name, Class<?>... parameterTypes)获取指定的成员方的method类对象// public Method getMethod(String name, Class<?>... parameterTypes):获取指定的公共的成员方法的Method对象//第一个参数都是方法名//第二个参数是可变参数,方法的形式参数类型的Class(字节码文件对象)Method method = clazz.getMethod("show");//方法本身就是空参System.out.println(method);//调用方法,Method类---提供的invoke//public Object invoke(Object obj, Object... args)//第一个参数:当前类实例//第二个参数:给方法的形式参数赋的实际参数//调用方法到时候将指定的方法实际参数作用在当前类实例上method.invoke(obj) ; //本身这个方法没有返回值,单独调用System.out.println("----------------------------------------------------------");/*** 反射调用这个* private void method(String str){*         System.out.println(str);*     }*/Method m1 = clazz.getDeclaredMethod("method", String.class);// System.out.println(m1);//private void com.qf.reflect_06.Person.method(java.lang.String)//私有方法取消Java语言检查m1.setAccessible(true) ;m1.invoke(obj,"hello,高圆圆") ;}
}

11_29

1.通过反射获取一个类的成员变量的类对象Field并去赋值

package com.qf.reflect_01;/*** @author 高圆圆* @date 2022/11/28 15:56*实体类*/
public class Person {private String name ; //私有的成员变量public int age ; //年龄String gender ; //性别//构造方法public Person(){}//无参构造方法private Person(String name,int age){this.name = name ;this.age = age ;}Person(String name,int age,String gender){this.name = name ;this.age = age ;this.gender = gender ;}//成员方法//没有返回值,无参public void show(){System.out.println("show Person");}//没有返回值,带参private void method(String str){System.out.println(str);}//有返回值.不带参private String function(){return "helloJavaEE" ;}//有返回值,带参String myFunction(int num){return "今晚韩国对阵加纳总球数是"+num ;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", gender='" + gender + '\'' +'}';}
}
package com.qf.reflect_01;import java.lang.reflect.Method;/*** @author 高圆圆* @date 2022/11/29 9:53* 通过反射调用Person类中的私有的function方法*/
public class ReflectDemo {public static void main(String[] args) throws Exception {//1)获取当前类的字节码文件对象Class clazz =  Class.forName("com.qf.reflect_01.Person") ;//2)无参构造方法公共的,直接创建当前类实例Object obj = clazz.newInstance();/***  private String function(){*         return "helloJavaEE" ;*     }*///3)通过字节码文件对象获取当前类的成员方法类对象MethodMethod method = clazz.getDeclaredMethod("function");//System.out.println(method);//4)抑制Java语言访问检查method.setAccessible(true) ;//5)调用方法Object returnObj = method.invoke(obj);System.out.println(returnObj);}
}
package com.qf.reflect_01;import java.lang.reflect.Field;/*** @author 高圆圆* @date 2022/11/29 9:58* 通过反射获取这个类的成员变量所在的类对象Field,给成员变量赋值!** 之前写法--->属性私有化--->构造方法赋值/setXX方法赋值*  Person p = new Person() ;*  p.name = "高圆圆" ;--->如果当前name,age,gender都是私有了,提供setXXX()或者有参构造方法...*  p.age = 44;*  p.gender="女"*  输出p--->执行toString()方法,显示成员信息表达式** 现在要通过反射来去赋值*/
public class ReflectDemo2 {public static void main(String[] args)  throws Exception{//现在要通过反射获取成员变量的Field类对象并且去赋值//1)获取当前类的字节码文件对象Class clazz = Class.forName("com.qf.reflect_01.Person") ;//2)创建当前类实例Object obj = clazz.newInstance() ;System.out.println(obj) ;//3)通过字节码文件对象获取成员变量的Field类对象//获取公共的字段(成员变量)Field类对象//public Field getField(String name)throws NoSuchFieldException,SecurityException//参数是属性名称//获取指定的成员变量的Field类对象//public Field getDeclaredField(String name)throws NoSuchFieldException,SecurityException//private String name ; //私有的成员变量Field nameField = clazz.getDeclaredField("name");//取消Java语言访问检查nameField.setAccessible(true) ;//给成员变量的类对象Field赋值//public void set(Object obj,Object value)throws IllegalArgumentException,IllegalAccessException//就是将指定的成员变量实际参数作用在指定实例上//参数1:当前类实例// 参数2:成员变量的实际参数nameField.set(obj,"高圆圆") ;System.out.println(obj);System.out.println("---------------------------------------------") ;//给age赋值Field ageField = clazz.getField("age");ageField.set(obj,44) ;System.out.println(obj) ;System.out.println("---------------------------------------------") ;//给gender赋值Field genderField = clazz.getDeclaredField("gender");genderField.setAccessible(true) ;genderField.set(obj,"女") ;System.out.println(obj);}
}

2.反射的应用1--ArrayList<Integer>--->里面如何添加字符串?

package com.qf.reflect_01;import java.lang.reflect.Method;
import java.util.ArrayList;/*** @author 高圆圆* @date 2022/11/29 10:34* 现在有一个ArrayList<Integer>,里面都是整数数据,如何通过反射给里面加入String类型的数据*/
public class ReflectTest {public static void main(String[] args)  throws Exception{//有一个ArrayList集合ArrayList<Integer> array = new ArrayList<>() ; //当前类的实例//泛型已经明确了数据类型array.add(100) ;array.add(10) ;array.add(25) ;array.add(55) ;//array.add("helloworld") ;System.out.println(array);System.out.println("-------------------------------------") ;//获取字节码文件对象方式 :三种//通过任意Java对象的getClass()获取到了当前正在运行的类字节码文件对象Class clazz = array.getClass() ;//获取当前它的add方法的Method类对象Method m = clazz.getMethod("add", Object.class);// System.out.println(m);//调用方法m.invoke(array,"helloworld") ;m.invoke(array,"高圆圆") ;System.out.println(array);}
}

3.反射的应用2-->通过读取.properties文件的方式,让程序更灵活

package com.qf.reflect_02;/*** @author 高圆圆* @date 2022/11/29 10:45*/
//学生类
public class Student {public void love(){System.out.println("爱学习,爱Java");}
}
package com.qf.reflect_02;/*** @author 高圆圆* @date 2022/11/29 10:45*/
//工人类
public class Worker {public void love(){System.out.println("爱生活,爱Java,爱高圆圆!");}
}
package com.qf.reflect_02;import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;/*** @author 高圆圆* @date 2022/11/29 10:44* 测试类***/
public class ReflectDemo {public static void main(String[] args) throws Exception {//需要使用Student类的love/* Student student = new Student() ;student.love();*///下一次业务代码需要更改----使用Worker类的功能Worker w = new Worker() ;w.love();//上面代码随着需求变化,可能需要用到不同类的某个的功能//导致代码改来改去,不灵活//设计原则---->"开闭原则" :对修改关闭,对扩展开放!// (对现有代码修改不好的,对现有带提供优化,扩展!)System.out.println("-------------------------------------------");//1)在当期类中读取src下面的xx.propertiesInputStream inputStream = ReflectDemo.class.getClassLoader().getResourceAsStream("classname.properties");//2)创建一个空的属性集合列表Properties prop = new Properties() ;//System.out.println(prop);//3)加载资源文件输入流的内容到属性集合列表中prop.load(inputStream);//System.out.println(prop);//{methodName=love, className=com.qf.reflect_02.Student}//4)通过属性集合列表中key获取valueString className = prop.getProperty("className");//System.out.println(className);String methodName = prop.getProperty("methodName") ;// System.out.println(methodName);//反射//获取当前类的字节码文件对象Class clazz = Class.forName(className) ;//创建当前类实例 无参构造方法系统提供Object obj = clazz.newInstance() ;//通过字节码文件对象获取类的成员方法Method类对象Method method = clazz.getMethod(methodName);//调用方法method.invoke(obj) ;}
}
#描述当期类的权限名称以及它的方法名
className=com.qf.reflect_02.Worker
methodName=love

4.反射---jdk动态代理

代理设计模式核心思想:让代理角色帮助真实角色完成一件事情(对我们业务方法进行增强)静态代理代理角色和真实角色需要实现同一个接口动态代理jdk动态代理里面需要前提有一个接口java.lang.reflect.Proxy提供了创建动态代理类和实例的静态方法public static Object newProxyInstance(ClassLoader loader,        //参数1:当前接口对象的类加载器Class<?>[] interfaces,    //参数2:代理实现接口列表字节码文件对象的数组InvocationHandler h      //参数3:代理实例 调用处理程序实现的接口) throws IllegalArgumentExceptioncglib动态代理

11_30

1.什么是数据库?

数据库就是存储数据的一种仓库!
早期存储数据---->临时变量(局部变量)---->随着方法调用而存在,随着方法调用结束而消失
后面-------->成员变量(非静态) ----->随着方法对象的创建而存在,随着对象的创建完毕等待垃圾回收器回收而消失
容器---->数组---->长度固定(弊端)
--->StringBuƊ er--->字符串缓冲区中存储各种字符序列,它长度可变,但是StringBuƊ er使用完毕等待回收
--->集合---->长度可变,它可以存储任意引用类型数据,使用完毕---->也要被回收掉
--->IO流---->永久存储,但是IO流的太耗时了
数据库存储数据--->
1)存储空间非常大,可以存储百万条,千万条甚至上亿条数据,用户可以对数据库中数据进行新增,查询,更新,删除等操作
2)数据独立性高
3)实现数据共享
4)减少数据的冗余度
5)通过数据库里面"事务"--->实现数据的一致性以及维护性!
2.市面上常见的数据库
数据库分为两大类 :
关系型数据库--->MySQL,SqlServer,Oracle,SQLite,MariaDB(和mysql是同一个数据库引擎)
sqlServer,oracle:收费
Oracle-->中大型公司使用居多--->金融方面互联网公司oracle
Mysql--->免费产品----> 中小型公司使用居多
非关系型数据库--->Redis,Memcache,MongoDb,HBase
redis:后面讲(做数据缓存用的)
3.DDL语句的基础语法---库的操作
库的操作 :
1)查询所有库 show databases;
2)创建库的语法
2.1)create database if not exists 库名 ; 如果没有这个库,则创建该库
2.2) 直接创建库 create database 库名;
3)查询指定库的信息--包括它的字符集
show create database 库名;
4)修改库的字符集

alter database 库名 default(省略) character set 字符集格式;
5)删除库
5.1)drop database if exists 库名; 如果存在库名,则删除
mysql> drop database if exists ee_2211;
5.2)drop databse 库名 ; 直接删除库
4.DDL语句的基础语法--表的操作

-- 普通注释 单行注释
# 特殊注释
/*多行注释*/
-- 创建表的前提------------------>必须现在使用库----相当于进入到库(库就是文件夹)
-- use 库名;
/*
mysql常见的数据类型:
int,int(int类型的字符数)
前者:int--->默认11位,当前这个字段(列的名称) 值本身的实际位数 (推荐)
年龄这个字段-----> 25-->使用int就可以表示即可
后者:int(3)---->给用户id(编号:1,2....n)---->不够三位补0 (不推荐后者)
id--->1---------------->001
varchar(字符长度):字符串类型
姓名这个字段---->varchar(20) ---->最大长度取到20, "高圆圆" 实际三个字符
在mysql中字符串写的时候---->可以使用""双引号,也可以使用''单引号
date:日期类型----->仅仅表示日期
datetime:日期+时间
timestap:时间戳--->当前插入数据或则修改/删除数据的即时时间 :2022-11-30 11:30:00
double:小数类型
double(3,2): 小数是3位数,小数点后保留2位
clob:大字符类型,某个表中某个字段---> 使用clob来存储大文本!
blob:大字节类型:存储大图片文件---大字节类型
*/
-- 查询库中有哪些表
show tables ;
mysql> show tables;
-- 创建表的语法
/*
create table 表名(
字段名称1 字段类型1,
字段名称2 字段类型2,
字段名称3 字段类型3,
....
字段名称n 字段类型n
) ;
-- 查询表的结构
-- desc 表名; -- 看到表的字段有哪些
-- 修改表的字段类型
-- alter table 表名 modify 字段名称 修改后字段类型;
-- 修改字段名称, (注意这个语法不要直接同时修改字段类型)
-- alter table 表名 change 以前的字段名称 现在的字段名称 以前的字段类型;
-- 修改表--->添加一个新的字段
-- alter table 表名 add 字段名称 字段类型
-- 修改表--- 删除表中某个字段
-- alter table 表名 drop 字段名称
-- 修改表名
-- alter table 表名 rename to 新表名; 也可以用 rename table 以前表名 to 新表名
-- 查询表的字符集
-- show create table 表名;
-- 修改表的字符集
-- alter table 表名 character set 字符集格式;
-- 复制表---快速去创建有一个结构相同的表
-- create table 新表名 like 旧表名;
-- 删除表
-- drop table if exists 表名;如果存在表删除
-- drop table 表名; 直接删除表名
5.需要改动mysql服务器端的核心配置文件my.ini文件
my.ini--->自定义目录或者默认的目录--->c判断 programdata--->Mysql--->mysqlserver5.7--->my.ini
1)停掉mysql57的服务---->dos黑窗口---管理员权限打开
C:\Users\Administrator>net stop mysql57
MySQL57 服务正在停止.
MySQL57 服务已成功停止。
C:\Users\Administrator>
2)notepad++打开my.ini核心配置文件
下图为例

3)重启mysql服务器,改动的配置文件才生效
C:\Users\Administrator>net start mysql57
MySQL57 服务正在启动 .
MySQL57 服务已经启动成功。
6.设计模式
设计模式:是一种设计思想
让代码结构更健壮!
1)创建型设计模式--->对象的创建 (使用比较多的)
    常见的单例设计模式,简单工厂--静态方法工厂模式,工厂方法模式
    构建者(Builder)..
2)结构型设计模式:构造一个对象(行为,属性)---->代理,装饰者,适配器...
    代理设计模式(Proxy)
    适配器模式(Adapter)
    桥接模式(Bridge)
    装饰者设计模式(Decorator)
3)行为型设计模式
    将多个类或者对象相互协作,共同完成单个对类或者对象无法单独完成的任务!
    解释器
    模板方法模式
    观察者设计模式
简历----->设计模式---> 写上你所熟知的设计模式
单例设计模式:
始终在内存中始终只有一个对象 !
饿汉式和懒汉式
代码举例
package com.qf.single_pattern;/*** @author 高圆圆* @date 2022/11/30 19:53* 学生类*/
public class Student {  //类一加载,给直接创建当前类实例//实例变量---->静态的private static Student s = new Student() ;//私有的private Student(){}public static Student getStudent(){return s ;}
}
package com.qf.single_pattern;/*** @author 高圆圆* @date 2022/11/30 20:15*/
public class Teacher {private static Teacher t;//这块只是声明! (静态被共用,共享)private Teacher(){}//多个线程在同时操作teacher类,可能造成安全问题/*  public static Teacher getInstance(){synchronized (Teacher.class){//需要用的时候才创建对象if(t==null){t = new Teacher() ;}return  t ;}}*/public synchronized static Teacher getInstance(){ //静态的同步方法//需要用的时候才创建对象if(t==null){t = new Teacher() ;}return  t ;}}
package com.qf.single_pattern;import java.io.IOException;/*** @author 高圆圆* @date 2022/11/30 19:50* 单例设计模式:*     始终在内存中始终只有一个对象!** 饿汉式和懒汉式** 饿汉式: 单例设计模式中最安全的一种设计模式!(不会出现线程安全问题!)** jdk提供了一个Runtime:是和计算机运行环境相关的类(典型的单例设计模式)* public class Runtime {*     private static Runtime currentRuntime = new Runtime();**public static Runtime getRuntime(){return currentRuntime;}private Runtime(){}}*      1)在类的成员位置提供静态实例变量*      2)当前类一定是具体类,构造方法私有化*      3)对外提供公共的静态方法,返回这个实例!(返回值就是当期类本身)*/
public class SinglePatternDemo {public static void main(String[] args) throws IOException {//创建学生对象//Student s1 = new Student() ;//Student s2 = new Student() ;//System.out.println(s1==s2) ;//上面---外界类中直接创建对象!每次都可以new,不合适!// Student.s = null ;//让对象变成null,外界还依然可以修改的实例!//不让你修改,此时这个静态实例变量---->加入私有Student s1 = Student.getStudent();Student s2 = Student.getStudent();System.out.println(s1==s2) ;System.out.println("-----------------------------------------------------") ;//创建和应用运行环境类对象Runtime runtime = Runtime.getRuntime();//成员方法:打开qq//runtime.exec("qq") ;// runtime.exec("mspaint") ;//打开画图板//runtime.exec("shutdown -t 3600 -s");//runtime.exec("shutdown -a");//public int availableProcessors() 获取处理器数量int i = runtime.availableProcessors();System.out.println(i);}
}
package com.qf.single_pattern;/*** @author 高圆圆* @date 2022/11/30 20:13** 懒汉式是可能出现安全问题的一种单例模式** 特点:*  1)当前这个类构造方法私有化*  2)成员位置---提供了静态当前的类变量(此处只是声明了当前类型的一个变量)*  3)提供一个静态的成员方法,返回值是当前类本身,   (安全方法)*          场景:按需加载或者延迟加载,需要用的时候才去创建对象**/
public class SinglePatternDemo2 {public static void main(String[] args) {Teacher t1 = Teacher.getInstance();Teacher t2 = Teacher.getInstance();System.out.println(t1==t2);}
}

12_1
1.MySQL的DQL语句---->数据库查询语句(带条件查询分类)
-- mysql基本查询
-- 如果两个数据int类型字段求和的时候,如果某个字段是null,结果是null
--  mysql的ifnull(字段名称,预期值) 函数-- 需求:查询学生的姓名以及学生的总成绩
SELECT NAME '姓名',(math+english) '总成绩'
FROMstudent2;SELECT NAME '姓名',(math+IFNULL(english,0)) '总成绩'
FROMstudent2;   -- 需求:查询年龄是20或者年龄是18或者年龄是45的学生所有信息
-- where条件可以使用 or 或者java语言||,in(值1,值2.....)
SELECT *
FROMstudent2
WHERE age = 20 OR age = 18 OR age = 45 ;-- 另一种写法
SELECT *
FROMstudent2
WHERE age = 20 || age = 18 || age = 45 ;
-- 另一种写法:in(值1,值2.....)
SELECT *
FROMstudent2
WHERE age IN (20, 18, 45) ;-- 查询某个字段为null的信息---->is null
-- 查询字段不为null---->is not null
-- 需求:查询英语成是null的学生的所有信息
/*
select *
fromstudent2
where english = null;
*/
SELECT *
FROMstudent2
WHERE english IS NOT NULL ;-- 查询某个字段不等于某个值 ---使用!=或者mysql的 <>
-- 需求:查询年龄不是20岁的学生所有信息
SELECT *
FROMstudent2
WHERE age != 20 ;-- 另一种写法SELECT *
FROMstudent2
WHERE age <> 20 ;-- 模糊查询mysql中所有的带有character字符集
SHOW VARIABLES LIKE '%character%' ;-- DQL之模糊条件查询  --- 关键字 like
-- 语法 select 字段列表 from 表名 where 字段名称 like '%xx%'
/*%:代表任意多个字符  (开发中使用居多)_:代表任意一个字符'字符%'  '%字符%'  也可以
*/
-- 需求:查询学生中所有姓马的学生信息SELECT
*
FROM
student2
WHERE
NAME LIKE '%马%'-- 查询学生的姓名是三个字符的人的信息
SELECT *
FROMstudent2
WHERE NAME LIKE '___' ;-- DQL之聚合查询 --->结果是单行单例的
/*
COUNT(字段名称) ---->使用最多  统计表的记录count里面 字段名称:一般非业务字段 (id:一般主键字段)如果字段某个值是null,不会统计max(列名称):求最大值
min(列名称):求最小值
avg(列名称):求当前列的平均值
sum(列名称):求当前这列的总和
*/-- 统计学生表studnet2的总记录数(总条数)
/*
select count(ifnull(english,0)) 'total'
fromstudent2 ;*/ SELECT COUNT(id) '总记录数' FROM student2;-- 需求:查询数学平均分SELECT AVG(math) FROM student2;-- 英语总分SELECT SUM(IFNULL(english,0)) '英语总分' FROM student2;-- 最大值/最小值SELECT MAX(math) FROM student2;SELECT MIN(math) FROM student2;-- 聚合函数---完成sql语句嵌套 (单表操作/多表都可以)-- x + y = 20 ; x = 5 --->代入-- 查询数学成绩大于数学平均分的学生信息!
-- 1)查询出数学成绩的平均分
-- select avg(math) from student2; -- 79.5000
-- 2)查询数学成绩大于79.5000的学生信息
/*
select *
fromstudent2
where math > 79.5000 ;
*/
-- 一步走
SELECT *
FROMstudent2
WHERE
math > (SELECT AVG(math) FROMstudent2) ;-- DQL语句之排序查询 order by
-- 单独使用order by
-- select 字段列表 from 表名  order by  字段名称 排序规则;
/*排序规则:默认asc ,升序排序desc  降序
如果有条件where,还有order by,where在前面满足条件,才排序!
*/
-- 插入一个学生
INSERT INTO student2 VALUES(9,'文章',35,'男','西安',73,98) ;
-- 针对某个字段排序
-- 需求:数学成绩升序排序
SELECT *
FROMstudent2
ORDER BY  math ASC ; -- asc可以省略不写
-- 需求:数学成绩大于70的学生按照降序排序
SELECT *
FROMstudent2
WHERE math > 70
ORDER BY math DESC ;
-- 同时多个条件排序
-- 需求:学生的数学成绩升序,英语成绩降序
SELECT *
FROMstudent2
ORDER BY math ASC,-- 先按照数学排english DESC ;-- DQL语句之分组查询 group by/*注意:1)分组查询里面可以select 查询分组字段 2)分组group by后面不能使用聚合函数*/-- 单独使用-- select 字段列表 from 表名 group by 分组字段名称;-- 需求:按照性别分组,查询数学成绩的平均分 (显示的查出分组字段)
SELECT sex '性别',AVG(math) '数学平均分'
FROMstudent2
GROUP BY sex ;-- 如果分组查询带where条件,
-- 需求:按照性别分组,查询数学成绩平均分,
-- 条件:学生数学成绩大于70的人参与分组
/*where条件和group by,where条件的在group by的前面group by的后面不能使用where,先满足where条件,才参与分组!
*/
/*
select sex '性别',avg(math) '数学平均分'
fromstudent2
group by sex
where math > 70 ;
*/
SELECT sex '性别',AVG(math) '数学平均分'
FROMstudent2
WHERE math > 70
GROUP BY sex ;-- 筛选having
/*注意having的后面可以跟聚合函数,having在group by ,where是gruop by的前面;*/-- 需求:按照性别分组,查询数学成绩平均分,
-- 条件:学生数学成绩大于70的人参与分组,同时筛选出人数大于2的一组!
SELECT sex '性别',AVG(math) '数学平均分',COUNT(id) total
FROMstudent2
WHERE math > 70
GROUP BY sex
HAVING total  > 2 ;-- 分页查询limit
-- select 字段列表 from 表名 limit 起始行数,每页显示的条数;
-- 起始行数= (当前页码数-1)*每页显示的条数;
-- 每页显示2条,
-- 查询第一页的数据
SELECT * FROM student2 LIMIT 0,2 ;
--  查询第二页的数据
SELECT * FROM student2 LIMIT 2,2 ;
-- 查询第三页的数据
SELECT * FROM student2 LIMIT 4,2 ;
-- 查询第四页的数据
SELECT * FROM student2 LIMIT 6,2 ; -- 查询第五页的数据
SELECT * FROM student2 LIMIT 8,2 ; -- select 字段列表 from 表名 limit 值;
SELECT * FROM student2 LIMIT 3 ;-- 如果复合查询:有where条件,还有limit,where在limit前面
SELECT * FROM student2 WHERE id > 2 LIMIT 4;-- 查询全表student2
SELECT * FROM student2; 

2. 数据库约束 (限定用户操作数据库的一种行为)

-- 约束
-- 约束用户操作数据库的一种行为(非法行为)
-- 默认约束 default
-- 非空约束 not null
-- 唯一约束 unqiue
-- 主键约束 primary key
-- 自增长约束 auto_increment
-- 外键约束 foreign key
-- 级联操作cascade-- 默认约束default
-- 创建一张表
CREATE TABLE test1(id INT, -- 编号NAME VARCHAR(10), -- 姓名age INT, -- 年龄gender VARCHAR(3)  DEFAULT '女' -- 姓名) ;INSERT INTO test1 VALUES(1,'文章',35,'男'),(2,'高圆圆',30,'女') ;-- 插入部分字段INSERT INTO test1(id,NAME,age) VALUES(3,'张佳宁',29) ;-- 没有插入字段的值默认值null,为了防止这种数据出现,可以在创建表的时候-- 加入默认约束default,当没有插入这个字段,默认约束起作用!DROP TABLE test1;
-- 通过sql将默认约束删除
-- 修改表的字段类型
ALTER TABLE test1 MODIFY gender VARCHAR(3)
INSERT INTO test1(id,NAME,age) VALUES(4,'刘亦菲',27) ;
-- sql添加,默认约束
ALTER TABLE test1 MODIFY gender VARCHAR(3) DEFAULT '女' ;-- 非空约束 not null
-- 当前这个值不能为null,不能直接添加数据给一个null
CREATE TABLE test1(id INT,NAME VARCHAR(10) NOT NULL -- 创建表的时候在指定字段后面加入not null
);
INSERT INTO test1 VALUES(1,'张三'),(2,'张三丰') ;
-- insert into test1 values(3,null) ; -- 某个字段值直接插入null值(非法行为)
-- Column 'name' cannot be null  当前这个值不能插入null值-- 将默认约束删除了
-- alter table 表名 modify 字段名称 数据类型;
ALTER TABLE test1 MODIFY NAME VARCHAR(10) ;
-- 添加非空约束
ALTER TABLE test1 MODIFY NAME VARCHAR(10) NOT NULL ;
INSERT INTO test1 VALUES(3,NULL) ;-- 唯一约束 unqiue (当前这个值不能重复)
-- 限制id字段/有效身份信息(邮箱/手机号/身份证...)
CREATE TABLE test1(id INT ,NAME VARCHAR(10),telephone VARCHAR(11) UNIQUE -- 唯一约束:存在唯一索引inedex
) ;
INSERT INTO test1 VALUES(1,'高圆圆','13366668888'),(2,'王力宏','13322226666') ;
-- 添加手机号码重复
-- INSERT INTO test1 VALUES(3,'文章','13366668888'); -- 手机号重复,防止这些字段重复(有效身份信息,可以在创建表的时候添加唯一约束)
-- -- Duplicate entry '13366668888' for key 'telephone' 这个字段有多个重复值出现-- 删除唯一约束----(删除唯一索引的名称)
-- alter table 表名 drop index 索引名(索引名如果没有起名字默认是列的名称);
ALTER TABLE test1 DROP INDEX telephone ;INSERT INTO test1 VALUES(3,'文章','13366668888');-- 添加唯一约束-- -- alter table 表名--  add constraint(声明)--  唯一约束的索引名称 -- unique(列名);ALTER TABLE test1 ADD CONSTRAINT index_telephone UNIQUE(telephone) ;
-- uplicate entry '13366668888' for key 'index_telephone' DROP TABLE test1;-- 主键约束primary key ---特点非空且唯一
CREATE TABLE test1(id INT PRIMARY KEY , -- 主键约束NAME VARCHAR(10),gender VARCHAR(3)
);
INSERT INTO test1 VALUES(1,'张三','男'),(2,'李四','女') ;INSERT INTO test1 VALUES(NULL,'高圆圆','女') ;
INSERT INTO test1 VALUES(1,'赵又廷','男') ;
-- 上面的sql直接插入null而且id重复,使用primary key (主键索引)-- 通过sql删除主键
-- alter table 表名 drop primary key ;
ALTER TABLE test1 DROP PRIMARY KEY ;-- 通过sql添加主键
-- alter table 表名 add primary key (列名称) ;
ALTER TABLE test1 ADD PRIMARY KEY(id) ;-- 自增长约束 auto_increment
-- 一般自增长约束都是在主键字段上,保证唯一
-- 指定插入数据的值,下次在之前的值上继续自增1
DROP TABLE test1;
CREATE TABLE test1(id INT PRIMARY KEY  AUTO_INCREMENT, -- 主键约束 + 自增长NAME VARCHAR(10),gender VARCHAR(3)
);INSERT INTO test1(NAME,gender) VALUES('张三','男'),('李四','女') ;
-- 指定插入id的值
INSERT INTO test1 VALUES(20,'高圆圆','女') ;
UPDATE test1 SET id = 25  WHERE id = 20 ;
-- 自增长主键的值一定插入之后产生的而不是修改!
INSERT INTO test1(NAME,gender) VALUES('赵又廷','男') ;-- mysql自带函数---查找数据库表中最后一次自增主键的值是多少
SELECT LAST_INSERT_ID();SELECT * FROM test1 ;-- 外键约束 foreign key
-- 有一张表 员工表
CREATE TABLE employee(id INT PRIMARY KEY AUTO_INCREMENT, -- 员工编号NAME VARCHAR(10) ,  -- 员工姓名gender VARCHAR(3) , -- 员工性别dept_name VARCHAR(10) -- 员工所在的部门名称
);
INSERT INTO employee(NAME,gender,dept_name)
VALUES('高圆圆','女','测试部'),
('张佳宁','女','运维部'),
('王宝强','男','开发部'),
('文章','男','开发部'),
('赵又廷','男','运维部') ;/*问题:1)查询员工的所有信息---部门名称字段 冗余度大(重复度高)2)一张表描述了两个事情(员工信息,又有部门信息!)解决方案:将这张表拆分两张表一张表员工信息一张表描述部门信息
*/
DROP TABLE employee;-- 创建一张部门表
CREATE TABLE dept(id INT PRIMARY KEY AUTO_INCREMENT, -- 部门编号NAME VARCHAR(10) -- 部门名称
);
INSERT INTO dept(NAME) VALUES('开发部'),('测试部'),('运维部');
-- 创建一个员工表
CREATE TABLE employee(id INT PRIMARY KEY AUTO_INCREMENT, -- 员工编号NAME VARCHAR(10) , -- 员工姓名gender VARCHAR(3) , -- 性别dept_id INT -- 部门编号
);
INSERT INTO employee(NAME,gender,dept_id)
VALUES('高圆圆','女',2),
('张佳宁','女',3),
('王宝强','男',1),
('文章','男',1),
('赵又廷','男',3) ;-- 插入了一个条数据:没有4号部门,但是依然能插入进去!
-- 防止出现问题,添加外键约束---让两个产生关联关系
INSERT INTO employee(NAME,gender,dept_id) VALUES('张三','男',4) ;-- 创建员工表的时候,同时添加外键约束!
/*
外键作用的表---从表,另一张表:主表创建表的时候添加外键constraint (声明)外键名--->起名字 主表名_从表名_fkforiegn key (从表的字段名称)references -- (关联)主表名(主键字段的名称)
*/
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) -- 主表的主键字段);-- 有了外键之后,直接修改或者删除主表数据,前提需要让从表的数据跟主表没有关联
-- 这个时候才能修改和删除主表数据!
-- 1)将3号部门的员工删除了
DELETE FROM employee WHERE dept_id = 3 ;-- 2)将3号部门在删除
DELETE FROM dept WHERE id = 3;-- 有外键约束,修改--先修改从表,然后在修改主表-- 将2号部门的员工---将部门编号设置1
UPDATE employee SET dept_id = 1 WHERE id = 1 ;
-- 1)将2号部门的员工 --- 改为部门编号3UPDATE dept SET id = 3 WHERE id =2 ;
UPDATE employee SET dept_id = 3 WHERE id =1;-- sql删除外键约束
-- alter table 表名 drop foreign key 外键名;
ALTER TABLE employee DROP FOREIGN KEY dept_emp_fk ;INSERT INTO employee(NAME,gender,dept_id) VALUES('张三','男',4) ;
-- sql 添加外键约束
-- alter table 表名 add constraint 外键名称 foreign key
-- (从表字段名称) references 主表的(主键字段) ;
ALTER TABLE employee
ADD CONSTRAINT dept_emp_fk
FOREIGN KEY (dept_id)
REFERENCES dept(id) ;-- 级联操作cascade
-- 级联删除/级联修改 on delete cascade /on update casade
-- 当修改/删除主表的数据,从表数据随之改动 -- 将上面这个语句放在外键的后面
-- 添加外键的同时---添加级联修改和级联删除
ALTER TABLE employee
ADD CONSTRAINT dept_emp_fk
FOREIGN KEY (dept_id)
REFERENCES dept(id)
ON UPDATE CASCADE
ON DELETE CASCADE ;-- 直接修改主表数据,
-- 将1号部门改成2号部门,这个时候1号部门的员工,它部门编号变成2
UPDATE dept SET id = 2 WHERE id =1 ;
-- 直接删除主表数据,从表随之变化
-- 将3号部门解散
DELETE FROM dept WHERE id = 3 ;SELECT * FROM dept ;
SELECT * FROM employee ;

12_2

1.表和表的关系问题

-- 一对多 
/*
    用户和订单的关系
    一个用户可以有多个订单,
    某个订单从属于某个用户
    
    员工和部门的关系
    一个部门有多个员工
    一个员工属于某个部门的
*/

-- 多对多
/*
    订单表和商品表
    一个订单包含多个商品
    一个商品被多个订单包含
    
    学生表和选课表
    一个学生可以选多个课程
    一个课程被多个学生选择
*/
-- 一对一是一种特例
/*
    人和身份证
    一个人对应一个身份证
    一个身份证从属于某个人的
    
    人和电话...
*/

2.数据库的三大范式(设计数据库) 

 1NF:第一范式    数据库表中每一列是不能在拆分的原子性!(最基本的要求)
 (表中每一个列是单独的,不能在拆分)
 2NF:第二范式
        在满足1NF基础上,
        1)一张描述一件事情
        2)非主键字段必须完全依赖于主键字段    
 3NF:第三范式
        在满足2NF基础上
        非主键字段中间不能产生传递依赖
        A字段--->依赖B字段--->依赖于C字段   A字段--->依赖C字段
        学生表
             学生id  学生的姓名  学生其他信息   学院id     学生所在的学院     系主任
         学生表和选课

3.多表查询

-- 多张同时查询 /*
笛卡尔乘积
内连接
外连接
子查询:select 嵌套 select....情况1:单行单例的数据情况2  多行多列情况3:通过两个表的关系---查询出结果集---->当做"虚表"在和其他之间关联查询!*/CREATE DATABASE ee_2211_02;-- 设计一个部门表CREATE TABLE dept(id INT PRIMARY KEY AUTO_INCREMENT ,-- 部门编号NAME VARCHAR(10)                   -- 部门名称) ;INSERT INTO dept(NAME) VALUES('开发部'),('市场部'),("销售部") ;-- 设计员工表CREATE TABLE employee(id INT PRIMARY KEY AUTO_INCREMENT, -- 员工编号NAME VARCHAR(10),                  -- 姓名gender VARCHAR(3),                 -- 性别salary DOUBLE,                 -- 工资join_date DATE,                     -- 入职日期dept_id INT ,                      -- 部门编号-- 设置外键CONSTRAINT -- 声明dept_emp_fk  -- 外键名FOREIGN KEY (dept_id) -- 指定外键名作用从表的指定字段上REFERENCES  -- 关联dept(id));INSERT INTO employee(NAME,gender,salary,join_date,dept_id) VALUES('文章','男',12000.0,'2021-11-11',1),('王宝强','男',8000.0,'2022-05-28',1),('高圆圆','女',7000.0,'2021-12-31',2),('张佳','女',8000.0,'2021-10-30',3) ,('马保国','男',3000.0,'2022-10-15',3),('黄晓明','男',15000.0,'2022-9-30',1),('姚笛','女',6000.0,'2021-10-10',3);-- 多表查询语法select 字段列表 from 表名1,表名2;-- 需求:查询员工表和部门表的所有信息
SELECT e.*,d.*
FROMemployee e,dept d ;
/*上面查询的结果不符合实际要求,7个员工,现在出现了21个
这个就是笛卡尔乘积,针对A表的记录 和B的记录数,两个表的记录相乘出现笛卡尔乘积的原因:没有设置连接条件!   针对多表查询1)查询哪张表!2)查询指定表的哪些字段!3)他们表和表之间的关系!
*/
-- 多表查之内连接()
/*隐式内连接:where条件---多去使用这种查!select    字段列表 from 表名1,表名2...表名nwhere    这些表之间的连接条件;
*/
-- 需求:查询员工表和部门表的所有信息
SELECT e.`id` '员工编号',e.`name` '姓名',e.`gender` '性别',e.`salary` '工资',e.`join_date` '入职日期',e.`dept_id` '员工所在的部门',d.id '部门编号',d.`name` '部门名称'
FROMemployee e,dept d
WHERE e.`dept_id` = d.`id` ;-- 内连接---显示内连接   (inner可以省略) join
/*select字段列表from 表名1(inner) join表名2on  连接条件
*/
-- 需求:查询员工的姓名,工资,入职日期以及各他的部门名称信息
SELECT e.`name` '姓名',e.`salary` '工资',e.`join_date` '入职日期',d.`name` '部门名称'
FROMemployee e JOIN dept d ON e.`dept_id` = d.`id` ;-- 插入一个员工
INSERT INTO employee(NAME,gender,salary,join_date)
VALUES('邓超','男',10000.0,'2022-10-20') ; -- 外连接
-- 左外连接(通用)
-- 将A表(左表)的和B表(右表)的交集以及A表(左表)中所有数据全部查询!
/*select 字段列表from左表名left (outer) join    -- outer可以省略   -- righter (outer) join 可以右外连接表名2on连接条件;
*/-- 查询所有的员工信息以及员工所在的部门名称信息,没有部门员工的也得查出来
/*
select e.*,d.`name` '部门名称'
from employee e,dept d
where e.`dept_id` = d.`id` ;*/
SELECT e.*,d.`name` "部门名称"
FROMemployee e LEFT OUTER JOIN dept d    -- outer可以省略ON e.`dept_id` = d.`id` ;-- 多表查询之子查询
-- 就是select去嵌套select
-- 情况1:使用where 后面条件表达式=,<=,>=.... -- 需求:查询员工工资最高的员工信息以及他的部门信息-- 1)查询最高工资是多少
SELECT MAX(salary) FROM employee ; -- 15000
-- 2)是15000的员工信息以及部门门信息
SELECT e.*,d.`name` '部门名称'
FROMemployee e,dept d
WHERE e.`dept_id` = d.`id` AND e.`salary` = 15000 ;-- 上面的sql一步走
SELECT e.*,d.`name` '部门名称'
FROMemployee e,dept d
WHERE e.`dept_id` = d.`id` AND e.`salary` = (SELECT MAX(salary) FROMemployee) ;-- 查询大于平均工资所有员工信息以及部门名称信息
-- 1)平均工资是多少
SELECT AVG(salary) FROM employee ; -- 8625
-- 2)查询员工表中员工工资大于8625的员工信息以及部门名称信息,没有部门的员工必须查(外连接)
SELECT e.*,d.`name` '部门名称'
FROM
employee e,
dept d
WHERE e.`dept_id` = d.`id` AND e.`salary` > 8625;-- 上面sql优化--一步走,查询出没有部门的员工---使用外连接
SELECT e.*,d.`name` '部门名称'
FROMemployee e,dept d
WHERE e.`salary` > (SELECT AVG(salary) FROMemployee) AND e.`dept_id` = d.`id` ;-- 情况2:利用in集合语句 (使用最多)
-- 需求:查询在"市场部"和销售部的员工信息-- 分步走
-- 1)查询市场部和销售部的部门编号SELECT id
FROMdept
WHERE NAME = '市场部' OR NAME = '销售部' ;
-- 2)查询员工表中在2或者3号部门的员工信息以及部门信息
SELECT e.*,d.`name` '部门名称'
FROM employee e,dept d
WHERE e.`dept_id` = d.`id` AND e.`dept_id` IN(2,3) ;-- 一步走
SELECT e.*,d.`name` '部门名称'
FROMemployee e,dept d
WHERE e.`dept_id` = d.`id` AND e.`dept_id` IN (SELECT id FROMdept WHERE NAME = '市场部' OR NAME = '销售部') ;-- 多表查询情况3:
-- 查询某个表的结果集----->
-- 当前"虚表"继续和其他进行关联查询(按照连接条件)
-- 查询入职日期大于"2021-11-11"后入职的员工信息以及部门名称信息-- 分步走
-- 1)查询入职日期大于"2021-11-11"后入职的员工信息
SELECT
*
FROM employee  e
WHERE e.`join_date` > '2021-11-11' ;
-- 2)在1)的结果集的基础上和部门表进行关联查询
SELECT t.name '员工姓名',t.join_date '入职日期',d.`name` '部门名称'
FROM(SELECT * FROMemployee e WHERE e.`join_date` > '2021-11-11') t LEFT JOIN dept d ON  t.dept_id = d.id ;   -- 左外连接,没有员工的部门需要查询-- 另一种写法(不考虑没有部门的员工)
SELECT e.*,d.`name` '部门名称'
FROMemployee e,dept d
WHERE e.`join_date` > '2021-11-11' AND e.`dept_id` = d.`id` ;SELECT * FROM dept  ;SELECT * FROM employee ;

12_3

1.数据库的事务

1.1什么是数据库事务(Transaction)
在一个业务中执行多个sql(多张表的sql),这多个sql句要么同时执行成功,
要么同时执行失败!

举例
转账操作  多个账户同时操作,一个减钱,一个加钱
提交订单
订单表和订单项表,同时添加数据

-- 创建一个账户表
CREATE TABLE account(id INT PRIMARY KEY AUTO_INCREMENT , -- 账户idNAME VARCHAR(10), -- 账户名称balance INT -- 余额
);INSERT INTO account (NAME,balance) VALUES('zhangsan',1000),('lisi',1000);-- zhangsan给lis转账500-- 没有数据库事务管理转账操作
/*
update account set balance = balance - 500 where id = 1 ;-- 转账出问题了 -- 这块不执行了,前面执行了!update account set balance = balance + 500 where id = 2;
*/-- 使用数据库事务管理整个转账的业务操作-- 开启事务
START TRANSACTION ;-- 操作多个sql语句或多张表的sql(同时增删改)
UPDATE account SET balance = balance - 500 WHERE id = 1;
-- 出问题了
UPDATE account SET balance = balance + 500 WHERE id = 2 ;-- 事务回滚
ROLLBACK ;-- 提交事务
COMMIT;UPDATE account SET balance = 1000 ;-- 查询账户
SELECT * FROM account ;

1.2事务特点 ACID (关系型数据库传统事务)

-- 原子性,一致性,隔离性,持久性!
/*
    原子性:在使用事务管理的时候,执行多个sql增删改,要么同时执行成功,要么同时失败
    一致性:高并发的时候,需要保证事务多次读写,保证数据一致性!
    隔离性:事务和事务是独立的,相互不影响!
            举例
                购物车业务--->购物车表和购物车项表同时添加数据
                订单业务---->订单表和订单项表同时添加数据
    持久性:    事务一旦提交,对数据的影响是永久性,即使关机了,数据还是要更新的!

*/

--

-- 事务的隔离级别
/*
四个级别:从小到大,安全性---从低到高,效率性:从高到低!
  read uncommitted :读未提交   
  
  read committed :读已提交
  repeatable read :可重复读   (mysql的默认隔离级别)
  serializable : 串行话

*/

SELECT @@tx_isolation; -- 查看隔离级别:5.7以及5.7以前 
--  select trasaction_isolation; mysql8.0以后的查看事务的隔离级别
-- 设置隔离级别
-- set global transaction isoloation level 级别的名称;

-- 第一种级别read uncommitted:读未提交 会造成问题"脏读"
-- "脏读":是事务管理最严重的问题:一个事务读取到另一个没有提交的事务!

/*
  第二种级别:read committed; 读已提交  有效防止脏读,出现了一个问题"不可重复读"
    事务(当前本身这个事务提交)多次读取另一个提交事务的前后到的数据不一致!
*/

/*
mysql的默认级别 repeatable read 
        可重复读,有效脏读,不可重复读,出现幻读!(一般有更新操作影响了数据)
    
最高级别:serializable:串行话    (一个事务读取到另一个没提交事务,数据查不到的,这个必须提交,才能操作数据!)
*/

2.jdbc

连接的七大步骤

1)导包驱动包

2)注册驱动--加载驱动类

3)获取数据库的连接对象java.sql.Connection

4)准备sql语句

5)通过Connection连接对象获取数据库的执行对象

6)执行sql语句

7)释放资源

public class JdbcDemo {public static void main(String[] args) throws Exception {//Jdbc的操作:java连接数据库//1)导入驱动jar包//2)注册驱动---加载驱动类Class.forName("com.mysql.jdbc.Driver") ; //mysql5.5或者5.1的jar包:都是这个全限定名称//mysql8.0jar包: com.mysql.cj.jdbc.Driver//3)获取数据库连接对象//DriverManager驱动管理类--->//public static Connection getConnection(String url, 连接库地址  (统一资源定位符)//                                       String user, mysql的用户名  root用户//                                       String password) 登录MySQL的密码//                                throws SQLException//url--->组成: 协议名称 ://域名:端口号/具体的路径/** mysql的驱动jar包如果是8.0以后:url的后面           编码格式         是否启用证书登录     服务器时区         是否公钥模式* jdbc:mysql://localhost:3306/ee_2211_02?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true* *///  jdbc:mysql://localhost:3306/库名Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/ee_2211_02","root","123456");//4)准备sql语句String sql = "insert into account (name,balance) values('高圆圆',1000)" ;//5)通过数据库连接对象Connection获取数据库的执行对象//执行静态sql语句//Statement createStatement()throws SQLException创建一个Statement对象,用于将SQL语句发送到数据库Statement stmt = conn.createStatement();//6)执行sql语句//Statement--->//int executeUpdate(String sql)throws SQLException 通用的更新操作int count = stmt.executeUpdate(sql);System.out.println("影响了"+count+"行");//7)释放资源stmt.close();conn.close();}
}

11_28-12_3周总结相关推荐

  1. 20165306 第八周学习任务

    第八周学习任务 教材学习内容总结 12.1进程与线程 1.操作系统与进程 程序是一段静态的代码,进程是程序的一次动态执行过程,这个过程也是进程本身从产生.发展至消亡的过程. 可以让计算机系统中的多个进 ...

  2. Java 获取当前时间之后的第一个周几,java获取当前日期的下一个周几

    Java 获取当前时间之后的第一个周几,java获取当前日期的下一个周几 //获得入参的日期 Calendar cd = Calendar.getInstance(); cd.setTime(date ...

  3. 提高班第三周周记(中秋第一天)

    这是第三周,也是中秋节.没有月饼的中秋节.但我过得很充实.我很快乐,发自内心的. 中秋第一天早上贾琳师哥讲课.讲他为什么辞职来这里.他的确学成,有着令人羡慕的工资.可是他的问题让我触动. 提到了邓稼先 ...

  4. 《Java程序设计》第十一周学习总结

    20175334 <Java程序设计>第十一周学习总结 教材学习内容总结 第十三章 URL类 一个URL对象通常包含最基本的三部分信息:协议.地址.资源. URL对象调用 InputStr ...

  5. 20175320 2018-2019-2 《Java程序设计》第2周学习总结

    20175320 2018-2019-2 <Java程序设计>第2周学习总结 教材学习内容总结 本周学习了教材的第二章及第三章的内容.在这两章中介绍了Java编程中的基本数据类型与数组以及 ...

  6. 2018-2019-1 20165214 《信息安全系统设计基础》第六周学习总结

    20165214 2018-2019-1 <信息安全系统设计基础>第六周学习总结 教材学习内容总结 1.输入操作是从I/O设备复制数据到主存,而输出操作是从主存复制数据到I/O设备 2.U ...

  7. 2017-2018-1 20155204 《信息安全系统设计基础》第十一周学习总结

    2017-2018-1 20155204 <信息安全系统设计基础>第十一周学习总结 教材学习内容总结 9.1物理和虚拟地址 物理地址:计算机系统的主存被组织成一个人由M个连续的字节到校的单 ...

  8. 2017-2018-1 20155202 《信息安全系统设计基础》第9周学习总结

    2017-2018-1 20155202 <信息安全系统设计基础>第9周学习总结 第6章 存储器层次结构 教材学习内容总结 随机访问存储器(Random-AccessMem)分为两类:静态 ...

  9. 201621123030《Java程序设计》第4周学习总结

    1.本周学习总结 1.1写出你认为本周学习中比较重要的知识点关键词. 继承,多态,super关键字,final关键字,super关键字,Object,instanceof,重载 1.2 尝试使用思维导 ...

最新文章

  1. tacacs java客户端_思科交换机 ACS4.0 Tacacs+ 登陆验证
  2. Linux内存管理机制研究
  3. Angular元素属性绑定的一个例子
  4. ubuntu 12.10 安装mysql_Ubuntu12.10安装Mysql数据库
  5. 谷歌聊天机器人api_如何编写针对Google地图等网络应用量身定制的聊天机器人
  6. 前端页面加水印插件_没用过这7款浏览器插件,你一定是假的程序员
  7. 2016年不容错过的十五大智能家居产品
  8. iOS定位-核心定位框架CLLocation
  9. Java 简单论文查重程序(SimHash+海明距离算法)
  10. 一个程序员的心路历程
  11. 嵌入式开发--智能机械臂
  12. ERP中英文缩写汇总
  13. 2019蓝桥杯国赛总结
  14. 视频图像处理技术优势安防视频监控应用
  15. 实现文章的展开与收起
  16. 2个阶乘什么意思_阶乘是什么意思?
  17. 如何解决MySQL无法打开之——错误2013:lose connection to MySQL blablabla
  18. 2021美赛C题数据(完整有解压密码)
  19. 转:创业公司如何公平分配股权?
  20. 永劫无间创建桌面快捷方式,并添加到steam库里

热门文章

  1. 【数理逻辑】预备知识
  2. 电脑软件:非常实用的Gif动图制作工具——ScreenToGif
  3. 面试:ConcurrentHashMap线程安全吗
  4. Android framework 增加DNS检测功能
  5. Active Silicon FireBird CXP图像采集卡AS-FBD-4XCXP12-3PE4的特点
  6. 如何轻松彻底卸载电脑软件
  7. JavaSE-常用类、Stream 流式计算
  8. a标签下载在IE浏览器不兼容问题
  9. OpenFlow交换机【ACM SIGCOMM顶会论文笔记】
  10. java计算机毕业设计健身俱乐部业务关系系统源码+mysql数据库+系统+lw文档+部署