目录
3.1 TCP方式,客户端可以不断键盘录入数据,服务器端不断展示数据
3.2 TCP客户端的读取文本文件(将文本文件写入通道中),服务器端复制文本文件到指定路径中(将文本文件写入指定文件中
3.3 TCP客户端读取文本文件,服务器端复制文本文件,现在服务器端反馈给客户端,"已经复制完毕"
4.反射(前期了解,二阶段学习Servlet服务器端程序开发,都是反射)
2.反射的应用1--ArrayList--->里面如何添加字符串?
Day1
1.TCP客户端和服务器端的代码实现
package com.qf.tcp_02;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* @author 高圆圆
* @date 2022/11/28 10:47
* 有关TCP客户端 使用步骤
* 1)创建客户端的Socket对象,指定ip和端口
* 2)获取客户端通道内容字节输出流对象,写数据
* 3)释放资源
*/
public class TcpClientDemo {
public static void main(String[] args) throws IOException {
//1)创建客户端的Socket对象,指定ip和端口
//Socket(String host, int port)
Socket socket = new Socket("10.35.162.121",1888) ;
//2)获取客户端通道内容字节输出流对象,写数据
//public OutputStream getOutputStream()
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,TCP我来了".getBytes());
//客户端获取通道字节输入流对象,读服务器端的反馈的数据
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024] ;
int length = in.read(bytes);
String fkMsg = new String(bytes,0,length) ;
System.out.println(fkMsg);
//3)释放资源
outputStream.close();
}
}
package com.qf.tcp_02;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 高圆圆
* @date 2022/11/28 10:54
* TCP服务器端的代码实现
* 1)创建服务器端的Socket对象
* 2)监听客户端的连接
* 3)获取监听到的客户端的通道内的自节输入流对象,读数据
* 4)释放服务器端的资源
*/
public class TcpServerDemo {
public static void main(String[] args) throws IOException {
//1)创建服务器端的Socket对象
//public ServerSocket(int port)
ServerSocket ss = new ServerSocket(1888) ;
System.out.println("服务器正在等待客户端连接请求...");
//2)监听客户端的连接
// public Socket accept()throws IOException
Socket socket = ss.accept();//阻塞式方法,没有客户端连接,一直等待
System.out.println("客户端已连接");
//3)获取监听到的客户端的通道内的字节输入流对象,读数据
//public InputStream getInputStream()
InputStream inputStream = socket.getInputStream();
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int length = inputStream.read(bytes);
//转换成String
String receiveMsg = new String(bytes,0,length) ;
//获取ip地址对象,同时ip地址字符串形式
// public InetAddress getInetAddress()
String ip = socket.getInetAddress().getHostAddress();
System.out.println("data from --->"+ip+",content is-->"+receiveMsg);
//服务器端反馈给客户端数据
//服务器端可以获取监听客户端通道内字节输出流,写数据
OutputStream out = socket.getOutputStream();
out.write("我这边已经收到数据!".getBytes());
// * 4)释放服务器端的资源
ss.close();
}
}
2.TCP三次握手的原理--->SYNC+ACK
3.TCP的应用
3.1 TCP方式,客户端可以不断键盘录入数据,服务器端不断展示数据
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)创建客户端Socket
Socket 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();
}
}
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 {
//创建服务器端的Socket
ServerSocket 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();
}
}
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.3 TCP客户端读取文本文件,服务器端复制文本文件,现在服务器端反馈给客户端,"已经复制完毕"
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 IOException
s.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();
}
}
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.反射(前期了解,二阶段学习Servlet服务器端程序开发,都是反射)
编译某个类的时候---->获取这个类的字节码文件,然后去加载,调用里面的成员方法,访问成员变量,
通过构造方法创建对象!
编译过程:
对这个类的属性/成员/构造其进行校验---->类加载器(负责类的加载过程)
BoostrapClassLoader:启动类加载器,负责java核心库,rt.jar
如何获取一个类的字节码文件
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.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 ;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
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.String
Constructor 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);
}
}
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,高圆圆") ;
}
}
Day2
1.通过反射获取一个类的成员变量的类对象Field并去赋值
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);
}
}
4.反射---jdk动态代理
package com.qf.reflect_03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author 高圆圆
* @date 2022/11/29 11:55
* 自定义一个类----->代理实例 调用处理程序实现的接口
*
* //就完成真实角色的里面的add(),update(),findAll(),detete()这些方法调用并进行增强
*/
public class MyInvocationHandler implements InvocationHandler {
//目标对象--->真实角色
private Object target ;
public MyInvocationHandler(Object target){
this.target = target ;
}
/**
* 具体实现UserDao接口,调用里面的方法!完成业务方法增强
* @param proxy
* @param method 调用的方法 add(),update(),findAll(),detete()
* @param args 这些方法实际参数
* @return 从代理实例上的方法调用返回的值
* @throws Throwable
*/
@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;
}
}
package com.qf.reflect_03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* @author 高圆圆
* @date 2022/11/29 11:34
* 代理设计模式
* 核心思想:让代理角色帮助真实角色完成一件事情(对我们业务方法进行增强)
* 静态代理
* 代理角色和真实角色需要实现同一个接口
* 动态代理
* jdk动态代理
* 里面需要前提有一个接口
*
* java.lang.reflect.Proxy提供了创建动态代理类和实例的静态方法
*
* public static Object newProxyInstance(
* ClassLoader loader, //参数1:当前接口对象的类加载器
* Class<?>[] interfaces, //参数2:代理实现接口列表字节码文件对象的数组
* InvocationHandler h //参数3:代理实例 调用处理程序实现的接口
* ) throws IllegalArgumentException
*
*
*
* cglib动态代理
*/
public class ReflectTest {
public static void main(String[] args) {
//现在创建接口对象
UserDao ud = new UserDaoImpl() ;
ud.add();
ud.delete();
ud.findAll();
ud.update();
System.out.println("------------------------------------------");
UserDao ud2 = new UserDaoImpl2() ;//现在加入了业务增强
ud2.add();
ud2.delete();
ud2.findAll();
ud2.update();
//上面没有使用反射---代码很臃肿,所有的业务方法都需要进行权限校验,完成之后,产生日志!
//使用动态代理---->jdk动态代理来实现
System.out.println("-------------------jdk动态代理的方式实现-----------------------");
/**
* public static Object newProxyInstance(
* ClassLoader loader, //参数1:当前接口对象的类加载器
* Class<?>[] interfaces, //参数2:代理实现接口列表字节码文件对象的数组
* InvocationHandler h //参数3:代理实例 调用处理程序实现的接口
* ) throws IllegalArgumentException
*/
InvocationHandler handler = new MyInvocationHandler(ud) ;
UserDao ud3 = (UserDao) Proxy.newProxyInstance(
ud.getClass().getClassLoader(),
//public class<?>[] getInterfaces()
ud.getClass().getInterfaces(),
handler
);
ud3.add();
ud3.delete();
ud.findAll();
ud3.update();
}
}
package com.qf.reflect_03;
/**
* @author 高圆圆
* @date 2022/11/29 11:38
* 针对用户操作的数据访问接口
*/
public interface UserDao {
void add() ;
void delete() ;
void findAll() ;
void update() ;
}
package com.qf.reflect_03;
/**
* @author 高圆圆
* @date 2022/11/29 11:39
* 数据接口实现
*/
public class UserDaoImpl implements UserDao{
/**
* 添加
*/
@Override
public void add() {
System.out.println("添加用户");
}
/**
* 删除
*/
@Override
public void delete() {
System.out.println("删除用户");
}
/**
* 查询
*/
@Override
public void findAll() {
System.out.println("查询所有用户");
}
/**
* 修改
*/
@Override
public void update() {
System.out.println("更新用户");
}
}
package com.qf.reflect_03;
/**
* @author 高圆圆
* @date 2022/11/29 11:42
*/
public class UserDaoImpl2 implements UserDao{
/**
* 添加
*/
@Override
public void add() {
//执行之前
System.out.println("权限校验");
System.out.println("添加用户");
System.out.println("产生日志");
}
/**
* 删除
*/
@Override
public void delete() {
System.out.println("权限校验");
System.out.println("删除用户");
System.out.println("产生日志");
}
/**
* 查询
*/
@Override
public void findAll() {
System.out.println("权限校验");
System.out.println("查询所有用户");
System.out.println("产生日志");
}
/**
* 修改
*/
@Override
public void update() {
System.out.println("权限校验");
System.out.println("更新用户");
System.out.println("产生日志");
}
}
Day3
数据库
-- 单行注释 /*多行注释*/ # 特殊注释 -- 图形界面化(支持mysql的utf8格式的)--手动在这编辑区域书写sql语句,不要鼠标直接点--->跳过sql语句 -- 创建库 CREATE DATABASE Myee_2211; USE Myee_2211; -- 创建表 CREATE TABLE student( id INT , -- 学生的编号 NAME VARCHAR(10), -- 姓名 age INT , -- 年龄 gender VARCHAR(3), -- 性别 avg_socre DOUBLE(3,1), -- 分数 adderss VARCHAR(50) ) ; -- 查询表的结果显示列名信息 DESC student ; -- DML语句:数据库操作语句 -- 操作表的记录---插入,修改,删除,查询... -- 1.插入数据 -- 1)插入全表数据insert into 表名 values(值1,值2,值3,值3...值n); INSERT INTO student VALUES(1,'高圆圆',44,"女",99.5,'西安市南窑国际') ; -- 2)插入全表数据也支持一次插入多条 -- insert into 表名 values(值1,值2,值3,值3...值n),(值1,值2,......值n),(..) ; INSERT INTO student VALUES(1,'高圆圆',44,"女",99.5,'西安市南窑国际'), (2,'韩永辉',25,'男',90.5,'西安市南窑国际92排'), (3,'薛宇豪',22,'男',92.0,'咸阳市'), (4,'文章',35,'男',78.5,'宝鸡市') ; -- 2).插入数据--插入部分字段,没有插入的字段值就是null(空值) -- 也可以支持一次插入多条数据,部分字段 -- insert into 表名(字段名称1,字段名称2.,等部分字段)values(值1,值2,值3...),(值1,值2,值3...),(...); INSERT INTO student(id,NAME,age,gender,avg_socre) VALUES (10,'马伊琍',44,'女',89.0), (5,'马保国',65,'男',87.9); INSERT INTO student(id,NAME,age,gender,avg_socre) VALUES (6,'马苏',36,'',77.5); -- 2.修改数据 -- 2.1)带条件修改(一次修改一个或者多个)--->条件:一般都是非业务字段去修改 -- update 表名 set 字段名称= 值 where 字段名称= 值; -- update 表名 set 字段名称1= 值1,字段名称2=值2,.... where 字段名称= 值; -- 需求:将id为2的学生的姓名修改为"韩伟" UPDATE student SET NAME = '韩伟' WHERE id = 2 ; -- 需求:将id为4的学生姓名改为"张三丰",年龄30,平均成绩改为 80.5 UPDATE student SET NAME = '张三丰', age = 30, avg_socre = 80.5 WHERE id = 4 ; -- 2.2)修改的时候如果不带where条件,属于批量修改(很少用) -- 修改姓名为高圆圆 UPDATE student SET NAME = '高圆圆'; DROP TABLE student ; CREATE TABLE student( id INT PRIMARY KEY AUTO_INCREMENT, -- 主键(非空且唯一)+自增长(不插入值,下一次自己自增1) NAME VARCHAR(20), gender VARCHAR(3), age INT , address VARCHAR(50) ) ; INSERT INTO student(NAME,gender,age,address) VALUES('文章','男',35,'西安市'), ('高圆圆','女',32,'渭南市'), ('张佳宁','女',32,'咸阳市') ; -- insert into student values(4,'高圆圆','男',33,'西安市') ; -- DML语句删除表的记录 -- 1)带条件删除 -- delete from 表名 where 字段名称 = 值; (条件一般使用非业务字段删除) -- delete from 表名 where 字段名称1 = 值1 and 字段名称2 = 值2 ....多个条件删除 -- 需求:删除id为的学生信息 DELETE FROM student WHERE id = 1 ; -- 需求: 删除姓名为高圆圆,年龄是男的学生信息 DELETE FROM student WHERE NAME = '高圆圆' AND gender = '男' ; -- 2)删除全表数据 -- delete from 表名; 是删除全表数据,表结构还在 DELETE FROM student ; -- 删除全表数据:truncate table 表名; TRUNCATE TABLE student ; /* 面试题: delete from 表名 和 truncate table 表名都是删除全表,有啥区别? 前者:仅仅是删除表的全部数据,表结构还在 如果表中的id有自增长约束存在,不会影响自增长约束的值,下一次插入数据之后 在上一次id的基础之上继续自增! 后者:不仅仅将表的全部数据删除, 而且它会删除这个表,会在创建一个创建空表,直接影响了这种(非业务字段id)自增长 主键的值,下一次插入数据的时候,从1开始继续自增! */ -- 基本的查询:查询全表 -- select * from 表名; -- *代表全部字段 (实际开发中禁用*) SELECT * FROM student ; INSERT INTO student (NAME,gender,age,address)VALUES ('王宝强','男',32,'上海市'); INSERT INTO student(NAME,gender,age,address)VALUES ('ez','男',30,'艾欧尼亚'); /* 如果在dos窗口查询表的记录---dos乱码,临时更改字符集 */ -- 模糊查询数据库每个端字符集 -- show variables like '%character%' ; -- set character_set_clinet/server/results=gbk ;在dos窗口就不乱码了 -- 创建表 CREATE TABLE student2 ( id INT, -- 编号 NAME VARCHAR(20), -- 姓名 age INT, -- 年龄 sex VARCHAR(5), -- 性别 address VARCHAR(100), -- 地址 math INT, -- 数学 english INT -- 英语 ); INSERT INTO student2(id,NAME,age,sex,address,math,english) VALUES (1,'马云',55,'男',' 杭州',66,78), (2,'马化腾',45,'女','深圳',98,87), (3,'马景涛',55,'男','香港',56,77), (4,'柳岩 ',20,'女','湖南',76,65), (5,'柳青',20,'男','湖南',86,NULL), (6,'刘德华',57,'男','香港 ',99,99), (7,'马德',22,'女','香港',99,99), (8,'德玛西亚',18,'男','南京',56,65); -- 查询语句DQL语句---使用最频繁的 -- 基本查询 -- 1)查询全表:select 全部字段名称 from表名; 自己玩的---使用 select * from 表名; -- 2)带条件查询 /* where 比较运算符 <=,>=,<,>,!=(在mysql使用 <>) and && /or || between 值1 and 值2 where 模糊条件 like关键字 排序查询 聚合函数查询 分组查询 帅选查询 */ -- 1)基本查询---查询全表字段并且给别名 给别名as (省略) SELECT id AS '编号', NAME AS '姓名', age AS '年龄', sex AS '性别', address AS '住址', math AS '数学成绩', english AS '英语成绩' FROM student2 ; -- 基本查询---查询时候指定部分字段 -- 查询学生的编号,姓名,数学和英语成绩 SELECT id '编号', NAME '姓名', math '数学成绩', english '英语成绩' FROM student2; -- 查询指定字段如何去重呢?关键字distinct -- 查询住址字段 SELECT DISTINCT address '住址' FROM student2; /* 基本带条件查询 where 比较运算符 <=,>=,<,>,!=(在mysql使用 <>),=赋值 and && /or || between 值1 and 值2 */ -- 需求:查询年龄是20的学生的编号,姓名,年龄,住址信息 SELECT id '编号', NAME '姓名', age '年龄', address '住址' FROM student2 WHERE age = 20 ; -- 查询年龄在18到20岁之间学生的所有信息 SELECT * FROM student2 WHERE age >=18 && age<=20; -- 逻辑双与&& 并列关系 SELECT * FROM student2 WHERE age >=18 AND age<=20; -- mysql提供的关键字 and 并列关系 SELECT * FROM student2 WHERE age BETWEEN 18 AND 20; SELECT * FROM student2 ;
2.市面上常见的数据库
数据库分为两大类:
关系型数据库--->MySQL,SqlServer,Oracle,SQLite,MariaDB(和mysql是同一个数据库引擎)
sqlServer,oracle:收费
Oracle-->中大型公司使用居多--->金融方面互联网公司oracle
Mysql--->免费产品----> 中小型公司使用居多
非关系型数据库--->Redis,Memcache,MongoDb,HBase
redis:后面讲(做数据缓存用的)
DDL语句的基础语法---库的操作
DDL语句:数据库定义语句 库和表的基本操作
库的操作:
1)查询所有库 show databases;
mysql> show databases ;
+--------------------+
| Database |
+--------------------+
| information_schema | mysql5.7对数据库元数据(创建时间,名称,访问权限..)的访问
| mysql | mysql的核心库,负责存储数据库的用户,权限,关键字等等
| performance_schema | mysql性能相关库---提供mysql性能相关的参数
| sys | 主要还是降低数据库各个之间的复杂度,让数据库运行更快
+--------------------+
11 rows in set (0.00 sec)2)创建库的语法
2.1)create database if not exists 库名 ; 如果没有这个库,则创建该库
mysql> create database if not exists EE_2211;
Query OK, 1 row affected (0.00 sec)mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| ee_2208_01 |
| ee_2208_02 |
| ee_2208_projects |
| ee_2211 | 创建的新库
| mybatis_01 |
| mybatis_02 |
| myee_2208 |
| mysql |
| performance_schema |
| racemall |
| sys |
+--------------------+
12 rows in set (0.00 sec)
2.2) 直接创建库 create database 库名;
mysql> create database javaee_2211_mysql;
Query OK, 1 row affected (0.00 sec)mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| ee_2208_01 |
| ee_2208_02 |
| ee_2208_projects |
| ee_2211 |
| javaee_2211_mysql | 创建辛苦
| mybatis_01 |
| mybatis_02 |
| myee_2208 |
| mysql |
| performance_schema |
| racemall |
| sys |
+--------------------+
13 rows in set (0.00 sec)
3)查询指定库的信息--包括它的字符集
show create database 库名;
mysql> show create database ee_2211;
+----------+------------------------------------------------------------------------------------------------+
| Database | Create Database |
+----------+------------------------------------------------------------------------------------------------+
| ee_2211 | CREATE DATABASE `ee_2211` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ |
+----------+------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)4)修改库的字符集
alter database 库名 default(省略) character set 字符集格式;
mysql> alter database ee_2211 character set gbk;
Query OK, 1 row affected (0.00 sec)mysql> show create database ee_2211;
+----------+-----------------------------------------------------------------+
| Database | Create Database |
+----------+-----------------------------------------------------------------+
| ee_2211 | CREATE DATABASE `ee_2211` /*!40100 DEFAULT CHARACTER SET gbk */ |
+----------+-----------------------------------------------------------------+
1 row in set (0.00 sec)
5)删除库
5.1)drop database if exists 库名; 如果存在库名,则删除
mysql> drop database if exists ee_2211;
Query OK, 0 rows affected (0.01 sec)mysql> show databases;
没有这个库了
+--------------------+
| Database |
+--------------------+
| information_schema |
| ee_2208_01 |
| ee_2208_02 |
| ee_2208_projects |
| javaee_2211_mysql |
| mybatis_01 |
| mybatis_02 |
| myee_2208 |
| mysql |
| performance_schema |
| racemall |
| sys |
+--------------------+
12 rows in set (0.00 sec)
5.2)drop databse 库名 ; 直接删除库
mysql> drop database javaee_2211_mysql;
Query OK, 0 rows affected (0.00 sec)mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| ee_2208_01 |
| ee_2208_02 |
| ee_2208_projects |
| mybatis_01 |
| mybatis_02 |
| myee_2208 |
| mysql |
| performance_schema |
| racemall |
| sys |
+--------------------+
11 rows in set (0.00 sec)
DDL语句的基础语法--表的操作
-- 普通注释 单行注释
# 特殊注释
/*多行注释*/-- 创建表的前提------------------>必须现在使用库----相当于进入到库(库就是文件夹)
-- use 库名;
mysql> use myee_2211;
Database changed -- 数据库改变了:进入到指定库中
mysql>/*
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;
Empty set (0.00 sec)-- 创建表的语法
/*
create table 表名(
字段名称1 字段类型1,
字段名称2 字段类型2,
字段名称3 字段类型3,
....
字段名称n 字段类型n
) ;*/
mysql> create table student(
-> id int,
-> name varchar(10),
-> age int,
-> gender varchar(5),
-> avg_socre double(3,1)
-> );
Query OK, 0 rows affected (0.05 sec)mysql> show tables;
+---------------------+
| Tables_in_myee_2211 |
+---------------------+
| student |
+---------------------+
1 row in set (0.00 sec)-- 查询表的结构
-- desc 表名; -- 看到表的字段有哪些
mysql> desc student;
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(10) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| gender | varchar(5) | YES | | NULL | |
| avg_socre | double(3,1) | YES | | NULL | |
+-----------+-------------+------+-----+---------+-------+
5 rows in set (0.01 sec)-- 修改表的字段类型
-- alter table 表名 modify 字段名称 修改后字段类型;
mysql> alter table student modify name varchar(8);
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc student;
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(8) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| gender | varchar(5) | YES | | NULL | |
| avg_socre | double(3,1) | YES | | NULL | |
+-----------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)-- 修改字段名称, (注意这个语法不要直接同时修改字段类型)
-- alter table 表名 change 以前的字段名称 现在的字段名称 以前的字段类型;
mysql> alter table student change gender sex varchar(5) ;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc student;
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(8) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| sex | varchar(5) | YES | | NULL | |
| avg_socre | double(3,1) | YES | | NULL | |
+-----------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)-- 修改表--->添加一个新的字段
-- alter table 表名 add 字段名称 字段类型;mysql> alter table student add address varchar(50) ;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc student ;
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(8) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| sex | varchar(5) | YES | | NULL | |
| avg_socre | double(3,1) | YES | | NULL | |
| address | varchar(50) | YES | | NULL | |
+-----------+-------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
-- 修改表--- 删除表中某个字段
-- alter table 表名 drop 字段名称 ;
mysql> alter table student drop avg_socre;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> desc student ;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(8) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| sex | varchar(5) | YES | | NULL | |
| address | varchar(50) | YES | | NULL | |
+---------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)
-- 修改表名
-- alter table 表名 rename to 新表名; 也可以用 rename table 以前表名 to 新表名;
mysql> alter table student rename to stu;
Query OK, 0 rows affected (0.02 sec)mysql> show tables;
+---------------------+
| Tables_in_myee_2211 |
+---------------------+
| stu |
+---------------------+
1 row in set (0.00 sec)
-- 查询表的字符集
-- show create table 表名;
-- 修改表的字符集
-- alter table 表名 character set 字符集格式;-- 复制表---快速去创建有一个结构相同的表
-- create table 新表名 like 旧表名;
mysql> create table teacher like student;
Query OK, 0 rows affected (0.02 sec)mysql> show tables;
+---------------------+
| Tables_in_myee_2211 |
+---------------------+
| student |
| teacher |
+---------------------+
2 rows in set (0.00 sec)
-- 删除表
-- drop table if exists 表名;如果存在表删除
mysql> drop table if exists teacher;
Query OK, 0 rows affected (0.02 sec)mysql> show tables;
+---------------------+
| Tables_in_myee_2211 |
+---------------------+
| student |
+---------------------+
1 row in set (0.00 sec)
-- drop table 表名; 直接删除表名
mysql> drop table student ;
Query OK, 0 rows affected (0.02 sec)mysql> show tables;
Empty set (0.00 sec)
Day4
MySQL的DQL语句
-- mysql基本查询
-- 如果两个数据int类型字段求和的时候,如果某个字段是null,结果是null
-- mysql的ifnull(字段名称,预期值) 函数
-- 需求:查询学生的姓名以及学生的总成绩
SELECT
NAME '姓名',
(math+english) '总成绩'
FROM
student2;
SELECT
NAME '姓名',
(math+IFNULL(english,0)) '总成绩'
FROM
student2;
-- 需求:查询年龄是20或者年龄是18或者年龄是45的学生所有信息
-- where条件可以使用 or 或者java语言||,in(值1,值2.....)
SELECT
*
FROM
student2
WHERE age = 20
OR age = 18
OR age = 45 ;
-- 另一种写法
SELECT
*
FROM
student2
WHERE age = 20 || age = 18 || age = 45 ;
-- 另一种写法:in(值1,值2.....)
SELECT
*
FROM
student2
WHERE age IN (20, 18, 45) ;
-- 查询某个字段为null的信息---->is null
-- 查询字段不为null---->is not null
-- 需求:查询英语成是null的学生的所有信息
/*
select
*
from
student2
where english = null;
*/
SELECT
*
FROM
student2
WHERE
english IS NOT NULL ;
-- 查询某个字段不等于某个值 ---使用!=或者mysql的 <>
-- 需求:查询年龄不是20岁的学生所有信息
SELECT
*
FROM
student2
WHERE age != 20 ;
-- 另一种写法
SELECT
*
FROM
student2
WHERE age <> 20 ;
-- 模糊查询mysql中所有的带有character字符集
SHOW VARIABLES LIKE '%character%' ;
-- DQL之模糊条件查询 --- 关键字 like
-- 语法 select 字段列表 from 表名 where 字段名称 like '%xx%'
/*
%:代表任意多个字符 (开发中使用居多)
_:代表任意一个字符
'字符%' '%字符%' 也可以
*/
-- 需求:查询学生中所有姓马的学生信息
SELECT
*
FROM
student2
WHERE
NAME LIKE '%马%'
-- 查询学生的姓名是三个字符的人的信息
SELECT
*
FROM
student2
WHERE NAME LIKE '___' ;
-- DQL之聚合查询 --->结果是单行单例的
/*
COUNT(字段名称) ---->使用最多 统计表的记录
count里面 字段名称:一般非业务字段 (id:一般主键字段)
如果字段某个值是null,不会统计
max(列名称):求最大值
min(列名称):求最小值
avg(列名称):求当前列的平均值
sum(列名称):求当前这列的总和
*/
-- 统计学生表studnet2的总记录数(总条数)
/*
select
count(ifnull(english,0)) 'total'
from
student2 ;
*/
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
*
from
student2
where math > 79.5000 ;
*/
-- 一步走
SELECT
*
FROM
student2
WHERE
math >
(SELECT
AVG(math)
FROM
student2) ;
-- DQL语句之排序查询 order by
-- 单独使用order by
-- select 字段列表 from 表名 order by 字段名称 排序规则;
/*
排序规则:默认asc ,升序排序
desc 降序
如果有条件where,还有order by,where在前面满足条件,才排序!
*/
-- 插入一个学生
INSERT INTO student2 VALUES(9,'文章',35,'男','西安',73,98) ;
-- 针对某个字段排序
-- 需求:数学成绩升序排序
SELECT
*
FROM
student2
ORDER BY math ASC ; -- asc可以省略不写
-- 需求:数学成绩大于70的学生按照降序排序
SELECT
*
FROM
student2
WHERE math > 70
ORDER BY math DESC ;
-- 同时多个条件排序
-- 需求:学生的数学成绩升序,英语成绩降序
SELECT
*
FROM
student2
ORDER BY math ASC,-- 先按照数学排
english DESC ;
-- DQL语句之分组查询 group by
/*
注意:
1)分组查询里面可以select 查询分组字段
2)分组group by后面不能使用聚合函数
*/
-- 单独使用
-- select 字段列表 from 表名 group by 分组字段名称;
-- 需求:按照性别分组,查询数学成绩的平均分 (显示的查出分组字段)
SELECT
sex '性别',
AVG(math) '数学平均分'
FROM
student2
GROUP BY sex ;
-- 如果分组查询带where条件,
-- 需求:按照性别分组,查询数学成绩平均分,
-- 条件:学生数学成绩大于70的人参与分组
/*
where条件和group by,where条件的在group by的前面
group by的后面不能使用where,先满足where条件,才参与分组!
*/
/*
select
sex '性别',
avg(math) '数学平均分'
from
student2
group by sex
where math > 70 ;
*/
SELECT
sex '性别',
AVG(math) '数学平均分'
FROM
student2
WHERE math > 70
GROUP BY sex ;
-- 筛选having
/*
注意
having的后面可以跟聚合函数,having在group by ,
where是gruop by的前面;
*/
-- 需求:按照性别分组,查询数学成绩平均分,
-- 条件:学生数学成绩大于70的人参与分组,同时筛选出人数大于2的一组!
SELECT
sex '性别',
AVG(math) '数学平均分',
COUNT(id) total
FROM
student2
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;
-- 约束
-- 约束用户操作数据库的一种行为(非法行为)
-- 默认约束 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 (声明)
外键名--->起名字 主表名_从表名_fk
foriegn 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号部门的员工 --- 改为部门编号3
UPDATE 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 ;
Day5
数据库表的关系问题
多表查询(使用最多)
-- 表和表的关系问题
-- 一对多
/*
用户和订单的关系
一个用户可以有多个订单,
某个订单从属于某个用户
员工和部门的关系
一个部门有多个员工
一个员工属于某个部门的
*/
-- 多对多
/*
订单表和商品表
一个订单包含多个商品
一个商品被多个订单包含
学生表和选课表
一个学生可以选多个课程
一个课程被多个学生选择
*/
-- 一对一是一种特例
/*
人和身份证
一个人对应一个身份证
一个身份证从属于某个人的
人和电话...
*/
-- 多表关系---设计一个库,满足数据库的范式(就是数据库设计的一种规范要求)
/*
1NF:第一范式 数据库表中每一列是不能在拆分的原子性!(最基本的要求)
(表中每一个列是单独的,不能在拆分)
2NF:第二范式
在满足1NF基础上,
1)一张描述一件事情
2)非主键字段必须完全依赖于主键字段
3NF:第三范式
在满足2NF基础上
非主键字段中间不能产生传递依赖
A字段--->依赖B字段--->依赖于C字段 A字段--->依赖C字段
学生表
学生id 学生的姓名 学生其他信息 学院id 学生所在的学院 系主任
学生表和选课
*/
-- 多表查询
-- 多张同时查询
/*
笛卡尔乘积
内连接
外连接
子查询: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.*
FROM
employee e,
dept d ;
/*
上面查询的结果不符合实际要求,7个员工,现在出现了21个
这个就是笛卡尔乘积,针对A表的记录 和B的记录数,两个表的记录相乘
出现笛卡尔乘积的原因:没有设置连接条件!
针对多表查询
1)查询哪张表!
2)查询指定表的哪些字段!
3)他们表和表之间的关系!
*/
-- 多表查之内连接()
/*
隐式内连接:where条件---多去使用这种查!
select
字段列表
from
表名1,表名2...表名n
where
这些表之间的连接条件;
*/
-- 需求:查询员工表和部门表的所有信息
SELECT
e.`id` '员工编号',
e.`name` '姓名',
e.`gender` '性别',
e.`salary` '工资',
e.`join_date` '入职日期',
e.`dept_id` '员工所在的部门',
d.id '部门编号',
d.`name` '部门名称'
FROM
employee e,
dept d
WHERE e.`dept_id` = d.`id` ;
-- 内连接---显示内连接 (inner可以省略) join
/*
select
字段列表
from 表名1
(inner) join
表名2
on 连接条件
*/
-- 需求:查询员工的姓名,工资,入职日期以及各他的部门名称信息
SELECT
e.`name` '姓名',
e.`salary` '工资',
e.`join_date` '入职日期',
d.`name` '部门名称'
FROM
employee 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 可以右外连接
表名2
on
连接条件;
*/
-- 查询所有的员工信息以及员工所在的部门名称信息,没有部门员工的也得查出来
/*
select
e.*,
d.`name` '部门名称'
from
employee e,
dept d
where
e.`dept_id` = d.`id` ;
*/
SELECT
e.*,
d.`name` "部门名称"
FROM
employee 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` '部门名称'
FROM
employee e,
dept d
WHERE e.`dept_id` = d.`id`
AND e.`salary` = 15000 ;
-- 上面的sql一步走
SELECT
e.*,
d.`name` '部门名称'
FROM
employee e,
dept d
WHERE e.`dept_id` = d.`id`
AND e.`salary` =
(SELECT
MAX(salary)
FROM
employee) ;
-- 查询大于平均工资所有员工信息以及部门名称信息
-- 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` '部门名称'
FROM
employee e,
dept d
WHERE e.`salary` >
(SELECT
AVG(salary)
FROM
employee)
AND e.`dept_id` = d.`id` ;
-- 情况2:利用in集合语句 (使用最多)
-- 需求:查询在"市场部"和销售部的员工信息
-- 分步走
-- 1)查询市场部和销售部的部门编号
SELECT
id
FROM
dept
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` '部门名称'
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:
-- 查询某个表的结果集----->
-- 当前"虚表"继续和其他进行关联查询(按照连接条件)
-- 查询入职日期大于"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
*
FROM
employee e
WHERE e.`join_date` > '2021-11-11') t LEFT JOIN
dept d
ON t.dept_id = d.id ; -- 左外连接,没有员工的部门需要查询
-- 另一种写法(不考虑没有部门的员工)
SELECT
e.*,
d.`name` '部门名称'
FROM
employee e,
dept d
WHERE e.`join_date` > '2021-11-11'
AND e.`dept_id` = d.`id` ;
SELECT * FROM dept ;
SELECT * FROM employee ;
Day6
事务
`student`-- 数据库的事务
/*
什么是数据库事务(Transaction)
在一个业务中执行多个sql(多张表的sql),这多个sql句要么同时执行成功,
要么同时执行失败!
`student`
举例
转账操作 多个账户同时操作,一个减钱,一个加钱
提交订单
订单表和订单项表 同时添加数据
*/
-- 创建一个账户表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT , -- 账户id
NAME 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 ;
-- 事务特点 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:串行话 (一个事务读取到另一个没提交事务,数据查不到的,这个必须提交,才能操作数据!)
*/
JDBC
package com.qf.jdbc_demo1;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @author 高圆圆
* @date 2022/12/3 11:13
* 七大步骤
* 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();
}
}