网络的相关概念
网络通信
1.概念:两台设备之间通过网络实现数据传输
2.网络通信:将数据通过网络从一台设备传输到另一台设备
3.java.net包下提供了一系列的类或接口,供程序员使用,完成网络通信
网络的相关概念
ip地址
1.概念:用于唯一标识网络中的每台计算机/主机
2.查看ip地址: ip config
3. ip地址的表示形式:点分十进制XX.XX.XX.XX4.每一个十进制数的范围:0~255
5. ip地址的组成=网络地址+主机地址,比如:192.168.16.69
6. iiPv6是互联网工程任务组设计的用于替代IPv4的下一代IP协议,其地址数量号称可以为全世界的每一粒沙子编上一分地址 。
7.由于IPv4最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备连入互联网的障碍
两个字节表示一个端口
InetAddress类
●相关方法
1.获取本机InetAddress对象getLocalHost
2.根据指定主机名/域名获取ip地址对象getByName
3.获取InetAddress对象的主机名getHostName
4.获取InetAddress对象的地址getHostAddress
package com.api;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* InetAddress的使用
*/
public class API_ {
public static void main(String[] args) throws UnknownHostException {
// 获取本机的InetAddress对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
//2.根据指定主机名获取InetAddress对象
InetAddress byName = InetAddress.getByName("DESKTOP-6CV6H2R");
System.out.println("host1 = " + byName);
// 根据域名返回InetAddress对象,比如www.baidu.com
InetAddress host = InetAddress.getByName("www.baidu.com");
System.out.println("host = " + host);
// 通过InetAddress对象,获取对应地址
String hostAddress = host.getHostAddress();
System.out.println("host对应的IP = " + hostAddress);
// 通过InetAddress对象,获取对应的主机名/或者是域名
String hostName = host.getHostName();
System.out.println("host对应的主机名/域名 = " + hostName);
}
}
Socket
基本介绍
1.套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准。
2.通信的两端都要有Socket,是两台机器间通信的端点
3.网络通信其实就是Socket间的通信。
4.Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。
5.一般主动发起通信的应用程序属客户端,等待通信请求的为服务端
客户端和服务器通常情况下,是在不同主机的.
难点:要兼顾服务器端和客户端
package com.api;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author
* @version 1.0
*/
public class SockTcpServer {
public static void main(String[] args) throws IOException {
// 在本机的9999端口监听,等待连接
// 细节,要求本机没有其他服务在监听9999
// 细节:这个ServerSocket 可以通过accept()返回多个Socket[多个客户端来连接服务器的并发]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接。。。。");
// 当没有客户端连接9999端口时,程序会 阻塞,等待连接
// 如果有客户端连接,会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("socket = " + socket.getClass());
// 通过 socket.getInputStream() 读取
// 客户端写入到数据通道的数据,显示
InputStream inputStream = socket.getInputStream();
// IO读取
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLen));
}
inputStream.close();
socket.close();
serverSocket.close();//关闭
}
}
package com.api;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* @author
* @version 1.0
* 客户端,发送“hello,server”给服务器
*/
public class SocketTcpClient {
public static void main(String[] args) throws IOException {
// 连接服务端(IP,端口)
// 连接本机的9999端口,连接成功,就返回Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
System.out.println("socket返回 = " + socket.getClass());
// 连接上后,生成Socket,通过socket.getOutputStream()
// 得到和socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
// 通过输入流,写入到数据到 通道
outputStream.write("hello,server".getBytes());
// 关闭流对象和socket,必须关闭
outputStream.close();
socket.close();
System.out.println("客户端退出....");
}
}
字节流
package com.api;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author
* @version 1.0
* 服务器端
*/
public class SockTcpServer {
public static void main(String[] args) throws IOException {
// 在本机的9999端口监听,等待连接
// 细节,要求本机没有其他服务在监听9999
// 细节:这个ServerSocket 可以通过accept()返回多个Socket[多个客户端来连接服务器的并发]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接。。。。");
// 当没有客户端连接9999端口时,程序会 阻塞,等待连接
// 如果有客户端连接,会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("socket = " + socket.getClass());
// 通过 socket.getInputStream() 读取
// 客户端写入到数据通道的数据,显示
InputStream inputStream = socket.getInputStream();
// IO读取
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLen));
}
// 获取输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,client".getBytes());
//设置结束标记
socket.shutdownOutput();
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();//关闭
}
}
package com.api;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* @author
* @version 1.0
* 客户端,发送“hello,server”给服务器
*/
public class SocketTcpClient {
public static void main(String[] args) throws IOException {
// 连接服务端(IP,端口)
// 连接本机的9999端口,连接成功,就返回Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
System.out.println("socket返回 = " + socket.getClass());
// 连接上后,生成Socket,通过socket.getOutputStream()
// 得到和socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
// 通过输入流,写入到数据到 通道
outputStream.write("hello,server".getBytes());
// 设置结束标记
socket.shutdownOutput();
// 获取socket关联的输入流
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLen));
}
// 关闭流对象和socket,必须关闭
inputStream.close();
outputStream.close();
socket.close();
System.out.println("客户端退出....");
}
}
字符流
package com.api;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author
* @version 1.0
* 服务器端 使用字符流
*/
public class SockTcpServer {
public static void main(String[] args) throws IOException {
// 在本机的9999端口监听,等待连接
// 细节,要求本机没有其他服务在监听9999
// 细节:这个ServerSocket 可以通过accept()返回多个Socket[多个客户端来连接服务器的并发]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接。。。。");
// 当没有客户端连接9999端口时,程序会 阻塞,等待连接
// 如果有客户端连接,会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("socket = " + socket.getClass());
// 通过 socket.getInputStream() 读取
// 客户端写入到数据通道的数据,显示
InputStream inputStream = socket.getInputStream();
// IO读取 使用字符流 使用了转换流,将 inpputStream 转成了字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
// 获取输出流
OutputStream outputStream = socket.getOutputStream();
// 使用字符流的方式回送信息
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello,client,字符流!");
bufferedWriter.newLine();//表示回复内容结束
bufferedWriter.flush();//手动刷新
//设置结束标记
// socket.shutdownOutput();
// outputStream.close();
// inputStream.close();
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();//关闭
}
}
package com.api;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
* @author
* @version 1.0
* 客户端,发送“hello,server”给服务器
* 使用字符流
*/
public class SocketTcpClient {
public static void main(String[] args) throws IOException {
// 连接服务端(IP,端口)
// 连接本机的9999端口,连接成功,就返回Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
System.out.println("socket返回 = " + socket.getClass());
// 连接上后,生成Socket,通过socket.getOutputStream()
// 得到和socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
// 通过输入流,写入到数据到 通道 使用字符流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello,server,字符流");
bufferedWriter.newLine();//插入一个换行符,表示写入内容结束,要求对方使用readLine()读取
bufferedWriter.flush();//如果使用的字符流,需要使用手动刷新,否则数据不会写入数据通道
// 设置结束标记
// socket.shutdownOutput();
// 获取socket关联的输入流
InputStream inputStream = socket.getInputStream();
// 使用字符流接收信息
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
// 关闭流对象和socket,必须关闭
// inputStream.close();
// 关闭外层流 后开的先关
bufferedReader.close();
// outputStream.close();
bufferedWriter.close();
socket.close();
System.out.println("客户端退出....");
}
}
package com.api;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author
* @version 1.0
* 文件上传到服务器
*/
public class TCPFileUploadServer {
public static void main(String[] args) throws IOException {
//服务端在本机监听8888端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务端在8888端口监听。。。。");
// 等待连接
Socket socket = serverSocket.accept();
// 读取客户端发送的数据
// 通过Socket得到一个输入流
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
// 读取数据
byte[] bytes = StreamUtils.streamToByteArray(bis);
// 将得到的bytes数组,写入到指定的路径,就得到文件
String destFilePath = "E:\\Java_study\\2.png";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
bos.write(bytes);
bos.close();
// 向客户端回复“收到图片”
// 通过socket 获取到输出流(字符)
BufferedWriter Writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Writer.write("收到图片");
Writer.flush();//把内容刷新到数据通道
socket.shutdownOutput();//设置结束标记
Writer.close();
bis.close();
socket.close();
serverSocket.close();
}
}
package com.api;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
* @author
* @version 1.0
*/
public class TCPFileUploadClient {
public static void main(String[] args) throws IOException {
//客户端连接服务器,得到Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
// 创建读取磁盘文件的输入流
String filePath = "E:\\Java_study\\1.png";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
// bytes就是文件filePath对应的字节数组
byte[] bytes = StreamUtils.streamToByteArray(bis);
// 将socket获取到的输出流,将bytes数据发送给服务端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);//将文件对应的字节数组的内容,写入到数据通道
// 设置结束的标志
bis.close();
socket.shutdownOutput();//写入数据的结束标志
// ===========接收从服务器回复的消息
InputStream inputStream = socket.getInputStream();
// 使用StreamUtils 的方法,直接将 inputStream 读取到的内容,转成字符串
String s = StreamUtils.streamToString(inputStream);
System.out.println(s);
// 关闭相关流
bos.close();
socket.close();
}
}
package com.api;
import java.io.*;
/**
* @author
* @version 1.0
* 关于流的读写方法
*/
public class StreamUtils {
/**
* 功能:将输入流转换成byte[],即可以把文件的内容读入到byte[]
* @param is
* @return
* @throws IOException
*/
public static byte[] streamToByteArray(InputStream is) throws IOException {
// 创建一个输出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];//字节数组
int len;
while ((len = is.read(b)) != -1){//循环读取
bos.write(b,0,len);//把读取的数据,写入bos
}
byte[] array = bos.toByteArray();//r然后将bos转成字节数组
bos.close();
return array;
}
/**
* 功能:将InputStream 转成String
* @param is
* @return
*/
public static String streamToString(InputStream is) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null){//当读取到空时,就结束
builder.append(line + "\r\n");
}
return builder.toString();
}
}
说明:
(1) Listening表示某个端口在监听
(2)如果有一个外部程序(客户端)连接到该端口,就会显示一条连接信息.
(3)可以输入ctrl +c退出指令
TCP网络通信编程
TCP网络通讯不为人知的密码
1.当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,这个端口是TCP/IP来分配的,是不确定的,是随机的
2.示意图
3.程序验证
UDP网络通信编程[了解]
●基本介绍
1.类 DatagramSocket和 DatagramPacket [数据包/数据报] 实现了基于UDP协议网络程序。
2.UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
3. DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
4.UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。
package com.api;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* @author
* @version 1.0
* UDP接收端
*/
public class UDPReceiverA {
public static void main(String[] args) throws IOException {
// 创建一个DatagramSocket 对象,准备在9999接收数据
DatagramSocket socket = new DatagramSocket(9999);
// 构建一个DatagramPacket 对象,准备接收数据
// UDP协议,最大为64K
byte[] buf = new byte[64 * 1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
// 准备接收数据,调用接收方法,将通过网络传输的DatagramPacket对象
// 填充到 packet 对象
// 当有数据包发送到 本机的9999端口时,就会接收到数据
// 如果没有数据包发送到 本机的 9999 端口,就会阻塞等待
System.out.println("接收端A 等待接收数据..");
socket.receive(packet);
// 可以把packet 进行拆包,取出数据,并显示
int length = packet.getLength();//实际接收到数据的长度
byte[] data = packet.getData();//接收数据
String s = new String(data,0,length);
System.out.println(s);
// =========回复信息=======
byte[] datasend = "好的,明天见~~~".getBytes();
DatagramPacket packet1 =
new DatagramPacket(datasend, datasend.length, InetAddress.getByName("202.115.166.168"), 9998);
socket.send(packet1);
// 关闭资源
socket.close();
System.out.println("A 端退出!!!!");
}
}
package com.api;
import java.io.IOException;
import java.net.*;
/**
* @author
* @version 1.0
* 发送端B===》也可以是接收端
*/
public class UDPSenderB {
public static void main(String[] args) throws IOException {
// 创建 DatagramSocket 对象,准备发送和接收数据
DatagramSocket socket = new DatagramSocket(9998);
// 将需要发送的数据,封装到DatagramPacket对象
byte[] data = "hello,明天吃火锅~~".getBytes();
// 封装 DatagramPacket 对象,data 内容字节数组,data.length,主机(IP),端口
DatagramPacket packet =
new DatagramPacket(data,data.length, InetAddress.getByName("202.115.166.168"),9999);
socket.send(packet);
// =============接收回复信息==========
byte[] buf = new byte[64 * 1024];
DatagramPacket packet1 = new DatagramPacket(buf, buf.length);
socket.receive(packet1);
int len = packet1.getLength();
byte[] datarec = packet1.getData();
String s = new String(datarec,0,len);
System.out.println(s);
socket.close();
System.out.println("B 端退出!!!!");
}
}
服务端
package com.api;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author
* @version 1.0
* 先写文件下载的服务端
*/
public class HomeWorkServer {
public static void main(String[] args) throws IOException {
// 创建 9999 端口
ServerSocket serverSocket = new ServerSocket(9999);
// 等待客户端连接
Socket socket = serverSocket.accept();
// 读取客户端发送的要下载的文件名
InputStream inputStream = socket.getInputStream();
byte[] b = new byte[1024];
int len = 0;
String downLoadFileName = "";
while ((len = inputStream.read(b)) != -1){
downLoadFileName += new String(b,0,len);
}
System.out.println("客户端希望下载的文件名:" + downLoadFileName);
//服务器上有两个文件,无名.mp3高山流水.mp3
//如果客户下载的是 高山流水我们就返回该文件,否则一律返回无名.mp3
String resFileName = "";
if ("高山流水".equals(downLoadFileName)){
resFileName = "E:\\Java_study\\高山流水.mp3";
}else {
resFileName = "E:\\Java_study\\无名.mp3";
}
// 创建一个输入流,读取文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(resFileName));
// 使用工具类StreamUtils,读取文件到一个字节数组
byte[] bytes =StreamUtils.streamToByteArray(bis);
// 得到Socket关联的输出流
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
// 写入到数据通道,返回给客户端
bos.write(bytes);
socket.shutdownOutput();
// 关闭相关资源
bos.close();
bis.close();
inputStream.close();
socket.close();
serverSocket.close();
System.out.println("服务器端退出、、、、");
}
}
客户端
package com.api;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/**
* @author
* @version 1.0
* 客户端
*/
public class HomeWorkClient {
public static void main(String[] args) throws IOException {
// 接收用户输入,指定下载的文件名
Scanner scanner = new Scanner(System.in);
System.out.println("请输入下载的文件名:");
String downloadFileName = scanner.next();
// 客户端连接服务器,准备发送
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
// 获取和Socket关联的输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write(downloadFileName.getBytes());
// 设置写入结束标志
socket.shutdownOutput();
// 读取服务端返回的文件(字节数据)
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] buf = StreamUtils.streamToByteArray(bis);
String filePath = "E:\\Java_study\\" + downloadFileName + "1" + ".mp3";
// 得到一个输出流,准备将bytes写入到磁盘文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
bos.write(buf);
bos.close();
bis.close();
outputStream.close();
socket.close();
System.out.println("客户端下载完毕退出。。。。。。。");
}
}
工具类
package com.api;
import java.io.*;
/**
* @author
* @version 1.0
* 关于流的读写方法
*/
public class StreamUtils {
/**
* 功能:将输入流转换成byte[],即可以把文件的内容读入到byte[]
* @param is
* @return
* @throws IOException
*/
public static byte[] streamToByteArray(InputStream is) throws IOException {
// 创建一个输出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];//字节数组
int len;
while ((len = is.read(b)) != -1){//循环读取
bos.write(b,0,len);//把读取的数据,写入bos
}
byte[] array = bos.toByteArray();//r然后将bos转成字节数组
bos.close();
return array;
}
/**
* 功能:将InputStream 转成String
* @param is
* @return
*/
public static String streamToString(InputStream is) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null){//当读取到空时,就结束
builder.append(line + "\r\n");
}
return builder.toString();
}
}
反射机制
万物皆对象
package com;
/**
* @author
* @version 1.0
*/
public class Cat {
private String name = "招财猫";
public void hi(){
System.out.println("黑黑,澳毛" +name);
}
public void cry(){
System.out.println("喵喵叫" + name);
}
}
package com;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* @author
* @version 1.0
*/
public class RefleationQuestion {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// Cat cat = new Cat();
// cat.hi(); 调用cry方法,传统方式需要修改源码,但是反射机制不需要修改源码,
// 可以通过修改配置文件实现
// 1.使用Properties类,可以读写配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("E:\\Java_study\\src\\com\\re.properties"));
String classfullpath = properties.get("classfullpath").toString();
String methodName = properties.get("method").toString();
System.out.println("classfullpath= " + classfullpath);
System.out.println("method= " + methodName);
// 2.创建对象,传统的方法行不通 =》 反射机制
// new classfullpath();
// 3.使用反射机制解决
// (1)加载类 返回一个Class类型的对象
Class cls = Class.forName(classfullpath);
// (2)通过cls 得到加载的类 com.Cat 的对象实例
Object o = /*(Cat)*/cls.newInstance();//也可以不转
System.out.println("o 的运行类型 = " + o.getClass());
// (3) 通过 cls 得到加载的类 com.Cat 的对象的 methodName 的方法对象
// 即在反射中,可以将方法视为对象(万物皆对象)
Method method1 = cls.getMethod(methodName);
// (4)通过method1 调用方法:即通过方法对象来实现调用方法
System.out.println("========================");
method1.invoke(o);//传统方法 对象.方法(),反射机制 方法.invoke(对象)
}
}
反射机制
Java Reflection
1.反射机制允许程序在执行期借助于Reflection
API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
2.加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射
反射机制
Java反射机制可以完成
1.在运行时判断任意一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时得到任意一个类所具有的成员变量和方法
4.在运行时调用任意一个对象的成员变量和方法
5.生成动态代理
反射机制
反射相关的主要类:
反射机制
反射相关的主要类:
- java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
- java.lang.reflect.Method:代表类的方法, Method对象表示某个类的方法
- java.lang.reflect.Field: 代表类的成员变量, Field对象表示某个类的成员变量
- java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
这些类在java.lang.reflection
package com;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* @author
* @version 1.0
*/
public class RefleationQuestion {
public static void main(String[] args) throws Exception {
// Cat cat = new Cat();
// cat.hi(); 调用cry方法,传统方式需要修改源码,但是反射机制不需要修改源码,
// 可以通过修改配置文件实现
// 1.使用Properties类,可以读写配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("E:\\Java_study\\src\\com\\re.properties"));
String classfullpath = properties.get("classfullpath").toString();
String methodName = properties.get("method").toString();
System.out.println("classfullpath= " + classfullpath);
System.out.println("method= " + methodName);
// 2.创建对象,传统的方法行不通 =》 反射机制
// new classfullpath();
// 3.使用反射机制解决
// (1)加载类 返回一个Class类型的对象
Class cls = Class.forName(classfullpath);
// (2)通过cls 得到加载的类 com.Cat 的对象实例
Object o = /*(Cat)*/cls.newInstance();//也可以不转
System.out.println("o 的运行类型 = " + o.getClass());
// (3) 通过 cls 得到加载的类 com.Cat 的对象的 methodName 的方法对象
// 即在反射中,可以将方法视为对象(万物皆对象)
Method method1 = cls.getMethod(methodName);
// (4)通过method1 调用方法:即通过方法对象来实现调用方法
System.out.println("========================");
method1.invoke(o);//传统方法 对象.方法(),反射机制 方法.invoke(对象)
// java.lang.reflect.Field:代表类的成员变量,Field 对象表示某个类的成员变量
// 取得name字段
// getField 不能得到私有的属性
Field nameField = cls.getField("age");
System.out.println(nameField.get(o));
// java.lang.reflect.Constructor: 代表类的构造方法,Constructor对象表示构造器
Constructor constructor = cls.getConstructor();//()中可以指定构造器参数类型,返回无参构造器
System.out.println(constructor);
Constructor constructor1 = cls.getConstructor(String.class);//String.class 为形参类别的Class
System.out.println(constructor1);
}
}
反射机制
·反射优点和缺点
1.优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
2.缺点:使用反射基本是解释执行,对执行速度有影响.
package com;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author
* @version 1.0
*/
public class Reflection02 {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
m1();
m2();
m3();
}
// 传统方法调用hi
public static void m1(){
Cat cat = new Cat();
long start = System.currentTimeMillis();
for (int i = 0; i < 900000; i++) {
cat.hi();
}
long end = System.currentTimeMillis();
System.out.println("传统方法调用hi耗时为:" + (end - start));
}
// 使用反射机制
public static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class aClass = Class.forName("com.Cat");
Object o = aClass.newInstance();
Method hi = aClass.getMethod("hi");
long start = System.currentTimeMillis();
for (int i = 0; i < 900000; i++) {
hi.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("反射机制调用hi耗时为:" + (end - start));
}
//反射优化 + 关闭访问检查
public static void m3() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class cls = Class.forName("com.Cat");
Object o = cls.newInstance();
Method hi = cls.getMethod("hi");
hi.setAccessible(true);//在反射调用方法时,取消访问检测
long start = System.currentTimeMillis();
for (int i = 0; i < 900000; i++) {
hi.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("优化后的反射调用时长:" + (end - start));
}
}
Class类
●基本介绍:
1.Class也是类,因此也继承Object类
2. Class类对象不是new出来的,而是系统创建的
3.对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
4.每个类的实例都会记得自己是由哪个Class 实例所生成
5.通过Class对象可以完整地得到一个类的完整结构,通过一系列API
6. Class对象是存放在堆的
7.类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码,变量名,方法名,访问权限等等)
package com;
/**
* @author
* @version 1.0
*/
public class Class01 {
public static void main(String[] args) throws ClassNotFoundException {
// 传统方法
/* ClassLoader
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
*/
// Cat cat = new Cat();
// 反射方式,不注销就拿不到是因为上面 Cat cat = new Cat();已经加载; loadclass,类只加载一次
/* ClassLoad类,任然通过 ClassLoader 类加载Cat 类的Class 对象
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
*/
Class cls = Class.forName("com.Cat");
Class cls1 = Class.forName( "com.cat" );
//3.对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
Class cls2= Class.forName( "com.cat" );
System.out.println(cls1.hashCode());
System.out.println(cls2.hashCode());
}
}
package com;
import java.lang.reflect.Field;
/**
* @author
* @version 1.0
*/
public class Class02 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String classfullpath = "com.Car";
// 获取到Car类对应的Class对象
// <?>表示不确定的Java类型
Class<?> aClass = Class.forName("com.Car");
// 输出aClass
System.out.println(aClass);//显示aClass对象,是哪个类的Class对象,com.Car
System.out.println(aClass.getClass());//运行类型
// 得到包名
System.out.println(aClass.getPackage().getName());
// 得到全类名
System.out.println(aClass.getName());
// 通过aClass创建对象实例
Car o = (Car)aClass.newInstance();
System.out.println(o);
// 通过反射获取属性
Field brand = aClass.getField("brand");//无法获取私有属性
System.out.println(brand.get(o));
// 设置属性值
brand.set(o,"奔驰");
System.out.println(brand.get(o));
// 遍历得到所有的属性
Field[] fields = aClass.getFields();
for(Field f: fields){
System.out.println(f);
}
}
}
获取Class类对象
1.前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException,
实例: Class cls1 =Class.forName( “java.lang.Cat””);
应用场景:多用于配置文件,读取类全路径,加载类.
2.前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能
最高实例: Class cls2 = Cat.class;
应用场景:多用于参数传递,比如通过反射得到对应构造器对象.
3.前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象,实例:
Class clazz=对象.getClass0);
应用场景:通过创建好的对象,获取Class对象
.4、其他方式
ClassLoader cl =对象.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);
5、基本数据(int, char,boolean,float,double,byte,long,short)按如下方式得到Class类对象
Class cls =基本数据类型.class
6.基本数据类型对应的包装类,可以通过.type得到Class类对象
Class cls =包装类.TYPE
package com;
/**
* @author
* @version 1.0
* 不同获取Class类对象的方式
*/
public class GetClass {
public static void main(String[] args) throws ClassNotFoundException {
// 1.forName
String classfullpath = "com.Car";
Class<?> cls1 = Class.forName(classfullpath);
System.out.println(cls1);
// 2.类名.class,应用场景:用于参数传递
Class cls2 = Car.class;
System.out.println(cls2);
// 3.运行类型 对象.getClass(),已经知道有对象实例
Car car = new Car();
Class cls3 = car.getClass();
System.out.println(cls3);
// 4.通过类加载器(4种)来获取类的Class对象
// (1)先得到类加载器 car
ClassLoader classLoader = car.getClass().getClassLoader();
// (2)通过类加载器得到Class对象
Class<?> cls4 = classLoader.loadClass(classfullpath);
System.out.println(cls4);
// cls1-4都是同一个class类
System.out.println(cls1.hashCode());
System.out.println(cls2.hashCode());
System.out.println(cls3.hashCode());
System.out.println(cls4.hashCode());
// 基本数据类型
Class<Integer> integerClass = int.class;
Class<Character> characterClass = char.class;
System.out.println(integerClass);
// 基本数据类型的包装类
Class<Integer> type = Integer.TYPE;
Class<Character> type1 = Character.TYPE;
System.out.println(type);
// 是同一个
System.out.println(integerClass.hashCode());
System.out.println(type.hashCode());
}
}
package com;
import java.io.Serializable;
/**
* @author
* @version 1.0
* 哪些类有class对象
*/
public class AllTypeClass {
public static void main(String[] args) {
Class<String> stringClass = String.class;//外部类
Class<Serializable> serializableClass = Serializable.class;//接口
Class<Integer[]> aClass = Integer[].class;//数组
Class<float[][]> aClass1 = float[][].class;//二维数组
Class<Deprecated> deprecatedClass = Deprecated.class;//注解
// 枚举
Class<Thread.State> stateClass = Thread.State.class;
Class<Long> longClass = long.class;//基本数据类型
Class<Void> voidClass = void.class;//void数据类型
Class<Class> classClass = Class.class;//Class类
}
}
类加载
●基本说明
反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。
1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
2动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性
●类加载时机
1.当创建对象时(new)—静态加载
2.当子类被加载时,父类也加载–静态加载
3.调用类中的静态成员时–静态加载
4.通过反射===动态加载
Class.forName(“com.test.Cat”);
package com;
import org.junit.jupiter.api.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author
* @version 1.0
* 如何通过反射获取类的结构信息
*/
public class ReflectionUtils {
public static void main(String[] args) {
}
// 第一组 方法 API
@Test
public void api_02() throws ClassNotFoundException {
// 得到Class对象
Class<?> personCls = Class.forName("com.Person");
// 所有public修饰的属性(包括本类和父类)
// 获取本类所有属性
Field[] declaredFields = personCls.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println("本类中所有属性=" + field + "该属性的修饰符值= "
+ field.getModifiers() + "该属性的类型= " + field.getType());
}
}
// 第一组 方法 API
@Test
public void api_01() throws ClassNotFoundException {
// 得到Class对象
Class<?> personCls = Class.forName("com.Person");
// 全类名
System.out.println(personCls.getName());
// 简单类名
System.out.println(personCls.getSimpleName());
// 所有public修饰的属性(包括本类和父类)
Field[] fields = personCls.getFields();
for (Field field:fields){
System.out.println("本类及父类的属性 = " + field.getName());
}
// 获取本类所有属性
Field[] declaredFields = personCls.getDeclaredFields();
for (Field field:declaredFields){
System.out.println("本类中所有属性=" + field);
}
// 获取本类和父类的public修饰的方法
Method[] methods = personCls.getMethods();
for (Method method1 : methods){
System.out.println("本类和父类的方法=" + method1.getName());
}
// 获取本类中所有方法
Method[] declaredMethods = personCls.getDeclaredMethods();
for (Method decl : declaredMethods){
System.out.println("本类中所有方法= " + decl.getName());
}
// getConstructors:获取所有public修饰的构造器,包含本类以及父类的
Constructor<?>[] constructors = personCls.getConstructors();
for (Constructor constructor:constructors){
System.out.println("本类及父类的构造器= " + constructor);
}
// getDeclaredConstructors:获取本类中所有构造器
Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
for (Constructor constructor: declaredConstructors){
System.out.println("本类所有的构造器= " + constructor.getName());
}
// getPackage : 以Package形式返回包信息
System.out.println(personCls.getPackage());
// getSuperClass:以Class形式返回父类信息
Class<?> superclass = personCls.getSuperclass();
System.out.println(superclass);
// getInterfaces:以Class[]形式返回接口信息
Class<?>[] interfaces = personCls.getInterfaces();
for (Class in : interfaces){
System.out.println("接口信息= " + in.getName());
}
// getAnnotations:以Annotation[]形式返回注解信息
Annotation[] annotations = personCls.getAnnotations();
for (Annotation annotation : annotations){
System.out.println("注解信息:" + annotation);
}
}
}
class A{
public String hobby;
public A() {
}
public A(String hobby) {
this.hobby = hobby;
}
public void hi(){
}
}
interface IA{}
interface IB{}
@Deprecated
class Person extends A implements IA,IB{
// 属性
public String name;
protected int age;
String job;
private double sal;
public Person() {
}
public Person(String name) {
this.name = name;
}
private Person(String name,int age){
}
// 方法
public void m1(){
}
protected void m2(){
}
void m3(){
}
private void m4(){
}
}
package com;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @author
* @version 1.0
*/
public class ReflecCreateInstance {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 现获取到User类的Class 对象
Class<?> userClass = Class.forName("com.User");
// 通过public的无参构造器创建实例
Object o = userClass.newInstance();
System.out.println(o);
// 通过public 的有参构造器创建实例
/*
constructor 对象就是
public User(String name){
this.name = name;
}
*/
// 先得到对应的构造器
Constructor<?> constructor = userClass.getConstructor(String.class);
// 再创建实例,并传入实参
Object lili = constructor.newInstance("lili");
System.out.println("lili = " + lili);
// 通过public 的无参构造器创建实例
// 得到private的构造器对象
Constructor<?> declaredConstructor = userClass.getDeclaredConstructor(int.class, String.class);
// 创建实例
declaredConstructor.setAccessible(true);//爆破【暴力破解】,使用反射可以访问private构造器/私有方法、私有属性,反射面前,一切都是纸老虎
Object zhangsan = declaredConstructor.newInstance(100, "zhangsan");
System.out.println(zhangsan);
}
}
class User{
private int age = 10;
private String name = "lili";
public User() {
}
public User(String name) {
this.name = name;
}
private User(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
package com;
import java.lang.reflect.Field;
/**
* @author
* @version 1.0
*/
public class refection_ {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
// 得到Student对应的Class对象
Class<?> stuClass = Class.forName("com.Student");
// 创建对象
Object o = stuClass.newInstance();//o 的运行类型就是Student
System.out.println(o.getClass());//Student
// 使用反射得到age 属性对象
Field age = stuClass.getField("age");
age.set(o,88);
System.out.println(o);
System.out.println(age.get(o));//返回age属性的值
// 使用反射操作name属性
Field name = stuClass.getDeclaredField("name");
name.setAccessible(true);
name.set(o,"老安徽00");
System.out.println(name.get(o));
name.set(null,"lili");//因为name是static属性,因此 o 也可以写成null
System.out.println(name.get(o));
System.out.println(name.get(null));//写成null需要要求name是static的
}
}
class Student{
public int age;
private static String name;
public Student() {
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
}
package com;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author
* @version 1.0
*/
public class ReflecAccessMethod {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 得到Boss类对应的Class对象
Class<?> bossClass = Class.forName("com.Boss");
// 创建对象
Object o = bossClass.newInstance();
// 调用public 的hi 方法
// Method hi = bossClass.getMethod("hi",String.class);
Method hi1 = bossClass.getDeclaredMethod("hi", String.class);
// 调用hi方法
hi1.invoke(o,"理论");
// 调用 private static 方法
// 得到say 方法对象
Method say = bossClass.getDeclaredMethod("say", int.class, String.class, char.class);
// 方法是私有的,要进行爆破
say.setAccessible(true);
System.out.println(say.invoke(o,12,"hfej",'o'));
// say方法是static的,可以调用方式
System.out.println(say.invoke(null,1,"憨憨",'女'));
// 在反射中,如果方法有返回值,统一返回Object。但是他的运行类型和方法定义的返回类型值一样
Object ii = say.invoke(null, 200, "fe", '男');
System.out.println("ii 的运行类型= " + ii.getClass());//String
}
}
class Boss{
public int age;
private static String name;
public Boss(){
}
private static String say(int n, String s,char c){
return n + " " + s + " " + c;
}
public void hi(String s){
System.out.println("hi " + s);
}
}
package com;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author
* @version 1.0
*
*/
public class HomeWork {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
// 得到PrivateTest对应的Class对象
Class<PrivateTest> privateTestClass = PrivateTest.class;
// 创建对象实例
PrivateTest privateTest = privateTestClass.newInstance();
// 得到name属性对象
Field name = privateTestClass.getDeclaredField("name");
// 爆破
name.setAccessible(true);
name.set(privateTest,"fjej");
// 得到getName方法对象
Method getName = privateTestClass.getMethod("getName");
// 因为是pubulic,直接调用
Object invoke = getName.invoke(privateTest);
System.out.println("name = " +invoke);
}
}
class PrivateTest{
private String name = "fekg";
public PrivateTest() {
}
public PrivateTest(String name) {
this.name = name;
}
public String getName(){
return name;
}
}
package com;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author
* @version 1.0
*
*/
public class HomeWork {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
Class<?> fileCls = Class.forName("java.io.File");
// 得到构造器
Constructor<?>[] declaredConstructors = fileCls.getDeclaredConstructors();;
for (Constructor declCon : declaredConstructors){
System.out.println(declCon);
}
// 指定得到 public java.io.File(java.lang.String)
Constructor<?> constructor = fileCls.getConstructor(String.class);
String fileOPath = "E:\\Java_study\\mynew.txt";
Object file = constructor.newInstance(fileOPath);//创建File对象
// 得到createNewFile 的方法对象
Method createNewFile = fileCls.getMethod("createNewFile");
createNewFile.invoke(file);
System.out.println(file.getClass());
System.out.println("创建文件成功 " + fileOPath);
}
}
**
数据库mysql
**
create table t06(
num1 float,
num2 double,
num3 decimal(30,20)
);
insert into t06 values(88.264124879721631211,98.264124879721631211,108.2645985254124879721631211);
select * from t06;
gbk编码是两个字节表示一个编码,所以要除以2.
Mysql常用数据类型
●字符串使用细节
1.细节
char(4)//这个4表示字符数(最大255),不是字节数,不管是中文还是字母都是放四个,按字符计算.
varchar(4)//这个4表示字符数,不管是字母还是中文都以定义好的表的编码来存放数据. gbk 2*4
不管是中文还是英文字母,都是最多存放4个,是按照字符来存放的.
char(4)和 varchar(4)这个4表示的是字符,而不是字节
2.细节2
char(4)是定长(固定的大小),就是说,即使你插入’aa’,也会占用分配的4个字符.
varchar(4)是变长,就是说,如果你插入了’aa’,实际占用空间大小并不是4个字符,而是按照实际占用空间来分配(varchar本身还需要占用1-3个字节来记录存放内容长度) L(实际占用的字节大小) + (1-3)个字节
3.细节3
什么时候使用char,什么时候使用varchar
1.如果数据是定长,推荐使用char,比如md5的密码,邮编,手机号,身份证号码等. char(32)
2.如果一个字段的长度是不确定,我们使用varchar,比如留言,文章
查询速度:char > varchar
#如果varchar不够用,可以考试使用mediumtext或者longtext,
#如果想简单点,可以使用直接使用text
create table t14(
birthday DATE,
job_time datetime,
login_time timestamp not null default current_timestamp on update current_timestamp
);
use dxl_db01;
select * from t14;
insert into t14 (birthday, job_time)
values (‘2011-11-11’,‘2022-11-11 10:12:15’)
use dxl_db01;
create table `emp`(
id INT,
`name` varchar(32),
sex char(1),
birthday date,
entry_date datetime,
job varchar(32),
salary double,
`resume` text)charset utf8 collate utf8_bin engine innodb;
)
--添加---
insert into `emp`
values (100,'小样','男','2000-11-11','2020-11-23 4:5:6','写作',3000,
'写出好的作品');
select * from `emp`;
use dxl_db01;
#修改表的操作练习
--员工表emp的上增加一个image列,varchar类型(要求在resume后面)。
alter table emp
add image varchar(32) not null default ''
after resume
desc emp #显示表结构,可以查看表的所有列
#修改job列,使长度为60
alter table emp
modify job varchar(60) not null default ''
-- 删除sex
alter table emp
drop sex
-- 修改表名
rename table emp to employee
desc employee
-- 修改表的字符集为utf8
alter table employee character set utf8
-- 列名name修改为user_name
alter table employee change name user_name varchar(32) not null default ''
use dxl_db01;
create table goods
(
id int,
goods_name varchar(10),
price double);
– 添加数据
insert into goods
(id ,goods_name, price)
values (10,‘华为手机’,2000)
lnsert语句细节说明
1.插入的数据应与字段的数据类型相同。
比如把’abc’添加到int类型会错误
2.数据的长度应在列的规定范围内,例如:不能将一个长度为80的字符串加入到长度为40的列中。
3.在values中列出的数据位置必须与被加入的列的排列位置相对应。
4.字符和日期型数据应包含在单引号中。
5.列可以插入空值[前提是该字段允许为空],insert into table value(null)
6. insert into tab_name(列名…)values 0.0.(形式添加多条记录
7.如果是给表中的所有字段添加数据,可以不写前面的字段名称
8.默认值的使用,当不给某个字段值时,如果有默认值就会添加,否则报错
–如果某个列没有指定not null ,那么当添加数据时,没有给定值,则会默认给null–如果我们希望指定某个列的默认值,可以在创建表时指定
use dxl_db01;
-- 1.将所有员工薪水修改为5000元。[如果没有带where 条件,会修改所有的记录,因此要小心
update employee set salary = 5000
update employee
set salary = 3000
where user_name = '小样'
insert into employee
values(200,'老妖怪','1984-12-2','1548-2-6 10:12:1','垂腿的',6000,'给大王捶腿','d:\a.jpg');
update employee
set salary = salary + 1000
where user_name = '老妖怪'
-- 可以修改多个列
update employee
set salary = salary + 1000,job = '出主意的'
where user_name = '老妖怪'
select * from employee;
use dxl_db01;
-- 删除表中名称为‘老妖怪’的记录
delete from employee
where user_name = '老妖怪';
insert into employee
values(200,'老妖怪','1984-12-2','1548-2-6 10:12:1','垂腿的',6000,'给大王捶腿','d:\a.jpg');
-- 删除表中全部数据
-- Delete语句不能删除某一列的值(可使用update设为null或者''
update employee set job = '' where user_name = '老妖怪';
delete from employee
select * from employee
-- 删除这个表
drop table employee ;
use dxl_db01
create table student(
id INT NOT NULL DEFAULT 1,
NAME VARCHAR(20) NOT NULL DEFAULT '',
chinese FLOAT NOT NULL DEFAULT 0.0,
english FLOAT NOT NULL DEFAULT 0.0,
math FLOAT NOT NULL DEFAULT 0.0
);
INSERT INTO student(id,NAME,chinese,english,math) VALUES(1,'优于',89,78,90);
INSERT INTO student(id,NAME,chinese,english,math) VALUES(2,'张飞',67,98,56);
INSERT INTO student(id,NAME,chinese,english,math) VALUES(3,'宋江',87,78,77);
INSERT INTO student(id,NAME,chinese,english,math) VALUES(4,'关羽',88,98,90);
INSERT INTO student(id,NAME,chinese,english,math) VALUES(5,'赵云',82,84,67);
INSERT INTO student(id,NAME,chinese,english,math) VALUES(6,'欧阳锋',55,85,45);
INSERT INTO student(id,NAME,chinese,english,math) VALUES(7,'黄蓉',75,65,30);
INSERT INTO student(id,NAME,chinese,english,math) VALUES(8,'韩信',45,65,99);
SELECT * FROM student;
select `name`,english from student ;
-- --过滤表中重复数据distinat
select distinct english from student ;
-- --要查询的记录,每个字段都相同,才会去重
select distinct `name`,english from student
use dxl_db01
select `name`,(chinese + english + math) from student;
select `name`,(chinese + english + math + 10) from student;
select `name`,(chinese+english+math+10) as total_score from student ;
select `name` as '名字' ,(chinese+english+math+10) as total_score
from student ;
use dxl_db01
select * from student
where `name` = '赵云'
select * from student
where english > 90
select * from student
where (chinese+english+math) >200
select *from student
where math > 60 and id > 4
select * from student
where english > chinese
select * from student
where (chinese+english+math) > 200 and
math < chinese and `name` like '张%'
select * from student
where english >= 80 and english <= 90
-- between and 是闭区间
select * from student
where english between 80 and 90
select * from student
where math = 89 or math = 90 or math = 91
select * from student
where math in (89,90,91)
select * from student
where `name` like '韩%'
select * from student
where math>80 and chinese > 80
use dxl_db01
select * from student
order by math;
select * from student
order by math desc;
select `name`,(chinese + english +math) as total_socre from student
order by total_socre desc ;
select * from student
where `name` like '韩%'
order by math
select `name`,(chinese + english + math) as total_score from student
where `name` like '韩%'
order by total_score
select `name`,(chinese + english + math) as total_score from student
where `name` like '韩%'
order by (chinese + english + math)
– count()和count(列)的|区别
–解释: count()返回满足条件的记录的行数
– count(列):统计满足条件的某列有多少个,但是会排除为null
对多列求和不能少了逗号
use dxl_db01
select count(*) from student
select count(*) from student
where math >90
select count(*) from student
where (english+chinese+math) > 250
create table t15(
`name` varchar(15));
insert into t15 values ('tom');
insert into t15 values ('jack');
insert into t15 values ('mary');
insert into t15 values ('lili');
insert into t15 values (null);
select * from t15
select count(*) from t15;
select count(`name`) from t15;
select sum(math) from student
select sum(math) as math_total_score, sum(english),sum(chinese) from student
select sum(math + chinese+english) from student
select sum(chinese)/count(*) from student
select avg(math) from student
select avg(math+chinese+english) from student
select max(math+english+chinese),min(math+english+chinese) from student;
CREATE TABLE dept( /*部门表*/
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
dname VARCHAR(20) NOT NULL DEFAULT "",
loc VARCHAR(13) NOT NULL DEFAULT ""
);
INSERT INTO dept VALUES(10, 'ACCOUNTING', 'NEW YORK'),
(20, 'RESEARCH', 'DALLAS'),
(30, 'SALES', 'CHICAGO'),
(40, 'OPERATIONS', 'BOSTON');
SELECT * FROM dept;
-- 员工表
CREATE TABLE emp
(empno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*编号*/
ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/
job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/
mgr MEDIUMINT UNSIGNED ,/*上级编号*/
hiredate DATE NOT NULL,/*入职时间*/
sal DECIMAL(7,2) NOT NULL,/*薪水*/
comm DECIMAL(7,2) ,/*红利 奖金*/
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/
);
-- 添加测试数据
INSERT INTO emp
VALUES(7369, 'SMITH', 'CLERK', 7902, '1990-12-17', 800.00,NULL , 20),
(7499, 'ALLEN', 'SALESMAN', 7698, '1991-2-20', 1600.00, 300.00, 30),
(7521, 'WARD', 'SALESMAN', 7698, '1991-2-22', 1250.00, 500.00, 30),
(7566, 'JONES', 'MANAGER', 7839, '1991-4-2', 2975.00,NULL,20),
(7654, 'MARTIN', 'SALESMAN', 7698, '1991-9-28',1250.00,1400.00,30),
(7698, 'BLAKE','MANAGER', 7839,'1991-5-1', 2850.00,NULL,30),
(7782, 'CLARK','MANAGER', 7839, '1991-6-9',2450.00,NULL,10),
(7788, 'SCOTT','ANALYST',7566, '1997-4-19',3000.00,NULL,20),
(7839, 'KING','PRESIDENT',NULL,'1991-11-17',5000.00,NULL,10),
(7844, 'TURNER', 'SALESMAN',7698, '1991-9-8', 1500.00, NULL,30),
(7900, 'JAMES','CLERK',7698, '1991-12-3',950.00,NULL,30),
(7902, 'FORD', 'ANALYST',7566,'1991-12-3',3000.00, NULL,20),
(7934,'MILLER','CLERK',7782,'1992-1-23', 1300.00, NULL,10);
SELECT * FROM emp;
-- 工资级别
#工资级别表
CREATE TABLE salgrade
(
grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*工资级别*/
losal DECIMAL(17,2) NOT NULL, /* 该级别的最低工资 */
hisal DECIMAL(17,2) NOT NULL /* 该级别的最高工资*/
);
INSERT INTO salgrade VALUES (1,700,1200);
INSERT INTO salgrade VALUES (2,1201,1400);
INSERT INTO salgrade VALUES (3,1401,2000);
INSERT INTO salgrade VALUES (4,2001,3000);
INSERT INTO salgrade VALUES (5,3001,9999);
SELECT * FROM salgrade;
SELECT * FROM dept;
SELECT * FROM emp;
use dxl_db01;
select * from emp;
-- 按部门分组
select avg(sal),max(sal),deptno
from emp group by deptno
-- 每个部门每种岗位的平均工资和最低工资
select avg(sal),min(sal),deptno,job
from emp group by deptno ,job
select avg(sal),deptno
from emp group by deptno
having avg(sal) < 2000;
select avg(sal) as avg_sal,deptno
from emp group by deptno
having avg_sal < 2000;
use dxl_db01;
select charset(ename) from emp;
-- 将多列拼成一列
select concat(ename, 'job is',job) from emp
select instr('hanshunping','ping') from dual
-- dual 亚元表 系统表,可以作为测试表使用
-- 转成大写
select ucase(ename) from emp
select lcase(ename) from emp
select left(ename,2) from emp
select right(ename,2) from emp
-- 按字节返回长度
select length(ename) from emp
select ename, replace(job,'MANAGER','经理') from emp
select strcmp('hsp','HpP') from dual
-- 从ename的第一个位置开始取出2个字符
select substring(ename,1,2) from emp
select ltrim(' 教育') from dual
select rtrim('教育 ') from dual
select trim(' 教育 ')from dual
-- 首字母小写显示姓名
select concat(lcase(substring(ename,1,1) ),substring(ename,2))
from emp
select concat(lcase(left(ename,1)),substring(ename,2))
from emp
 from dual
select bin(10) from dual
select ceiling(1.1) from dual
select conv(5,10,2) from dual
select floor(10.9) from dual
select format(12.58795665,3) from dual
select hex(1536) from dual
select least(12,85,1,-6) from dual
select mod(10,3) from dual
-- 想要固定随机数,加一个随机数种子
select rand(3) from dual
王实际开发中,我们也经常使用int来保存一个unix时间戳,然后使用from_unixtime(进行转换
select current_date() from dual
select current_time() from dual
select current_timestamp() from dual
create table mes(
id int,
content varchar(30),
send_time datetime
);
select * from mes
insert into mes
values(1,'南京新闻',current_timestamp());
insert into mes values(2,'成都新闻',now());
insert into mes values(3,'广州新闻',now());
select now() from dual;
select id,content,date(send_time)
from mes
select *
from mes
where date_add(send_time,interval 10 minute) >= now()
select *
from mes
where date_sub(now(),interval 10 minute) >= send_time
-- 相差多少天
select datediff('2011-11-11','1990-1-1') from dual
select datediff(now(),'1996-06-30') from dual
select datediff(date_add('1997-01-31 10:11:23',interval 80 year),now()) from dual
select datediff('10:12:23','03:2:23')from dual
select year(now()) from dual
select month (now()) from dual
select day (now()) from dual
select month ('2012-12-5')from dual
-- 1970-1-1到现在的秒数
select unix_timestamp() from dual
select from_unixtime(1748654549,'%Y-%m-%d') from dual
select from_unixtime(1748654549,'%Y-%m-%d %H:%i:%s') from dual
select user() from dual
select database() from dual
select MD5('hhs')from dual
select length(MD5('hhs'))from dual
create table dxl_user(
id int,
`name` varchar(32) not null default '',
pwd char(32) not null default ''
);
insert into dxl_user
values(100,'玉玉',md5('yuyu'));
select * from dxl_user
select password('dxl') from dual
select * from mysql.user
use dxl_db01;
select if (true,'北京','上海')from dual
select ifnull(null,'教育')from dual
select case
when true then 'jian'
when false then 'tom'
else 'mary' end
from dual
select ename,if(comm is null,0.0,comm)
from emp
select ename,ifnull(comm,0.0)
from emp
select ename, (select case
when job = 'CLERK' then '职员'
when job = 'MANAGER' then '经理'
when job = 'SALESMAN' then '销售人员'
else job end)
from emp;
select * from emp
order by empno
limit 每页显示的记录数 * (第几页-1),每页显示的记录数
use dxl_db01;
select * from emp
where hiredate > '1992-01-01'
select ename,sal from emp
where ename like 'S%'
select ename,sal from emp
where ename like '__O%'
select ename,sal from emp
where mgr is null;
desc emp
select * from emp
order by sal
select * from emp
order by deptno asc,sal desc
select * from emp
limit 10
select * from emp
order by empno
limit 0,3
select * from emp
order by empno
limit 3,3
-- 公式
select * from emp
order by empno
limit 每页显示的记录数 * (第几页-1),每页显示的记录数
select * from emp
order by empno
limit 20,25
select count(*) from emp
group by job
select count(*),avg(sal),job
from emp
group by job
select count(*)
from emp
where comm is not null
select count(*),count(comm)
from emp
select count(*),count(if(comm is null,1,null))
from emp
select count(*),count(*)-count(comm)
from emp
select count(distinct mgr)
from emp
select max(sal)-min(sal)
from emp
select deptno,avg(sal) as avg_sal
from emp
group by deptno
having avg_sal > 1000
order by avg_sal desc
limit 0,2
写出正确的过滤条件
select ename,sal,dname from emp,dept
where emp.deptno = dept.deptno
select ename,sal,dname,emp.deptno from emp,dept
where emp.deptno = dept.deptno and emp.deptno = 10
select * from emp,salgrade
where sal between salgrade.losal and salgrade.hisal
自连接:把一张表当做两张表来使用,要取别名 表名 表别名
列名不明确,可以指定列的别名 列名 as 列的别名
-- 自连接
use dxl_db01;
select worker.ename as '职员名', boss.ename as '上级名'
from emp as worker,emp as boss
where worker.mgr = boss.empno;
select deptno
from emp
where ename = 'SMITH'
select *
from emp
where deptno =(
select deptno
from emp
where ename = 'SMITH'
)
select distinct job
from emp
where deptno = 10;
select ename ,job,sal,deptno
from emp
where job in (
select distinct job
from emp
where deptno = 10
) and deptno <> 10
子查询可以当做临时表使用
select goods_id,cat_id,goods_name,shop_price
from ecs_goods;
select cat_id,max(shop_price)
from ecs_goods
group by cat_id
select goods_id,ecs_goods.cat_id,goods_name,shop_price
from (
select cat_id,max(shop_price) as max_price
from ecs_goods
group by cat_id
)temp,ecs_goods
where temp.cat_id = ecs_goods.cat_id
and temp.max_price = ecs_goods.shop_price
all和any
select ename,sal,deptno
from emp
where sal > all (
select sal
from emp
where deptno = 30)
select ename,sal,deptno
from emp
where sal > (
select max(sal)
from emp
where deptno = 30)
select ename,sal,deptno
from emp
where sal > any (
select sal
from emp
where deptno = 30)
select ename,sal,deptno
from emp
where sal > (
select min(sal)
from emp
where deptno = 30)
多列子查询
select deptno,job
from emp
where ename = 'SMITH'
select * from emp
where (deptno,job) = (
select deptno,job
from emp
where ename = 'ALLEN')and ename != 'ALLEN'
select * from student
where (math,english,chinese) = (
select math,english,chinese
from student
where `name` = '宋江')
select deptno,avg(sal)
from emp group by deptno
select ename,sal,temp.avg_sal,emp.deptno
from emp,(
select deptno,avg(sal) as avg_sal
from emp group by deptno )temp
where emp.deptno = temp.deptno and emp.sal > temp.avg_sal
select ename,sal,temp.max_sal,emp.deptno
from emp,(
select deptno,max(sal) as max_sal
from emp group by deptno )temp
where emp.deptno = temp.deptno and emp.sal = temp.max_sal
-- --查询每个部门的信息(包括:部门名,编号,地址)和人员数量,我们一起完成。
-- --1.部门名,编号,地址来自dept表
-- -- 2.各个部门的人员数量-》构建一个临时表
select count(*),deptno
from emp
group by deptno
select dname,dept.deptno ,loc,temp.numberman
from dept,(
select count(*) as numberman,deptno
from emp
group by deptno
)temp
where dept.deptno = temp.deptno
--还有一种写法表.*表示将该表所有列都显示出来,可以简化sql语句
--在多表查询中,当多个表的列不重复时,才可以直接写列名
select dname,loc,temp.*
from dept,(
select count(*) as numberman,deptno
from emp
group by deptno
)temp
where dept.deptno = temp.deptno
表复制
自我复制数据(蠕虫复制)
有时,为了对某个sql语句进行效率测试,我们需要海量数据时,可以使用此法为表创建海量数据。
create table my_tab01
(
id int,
`name` varchar(32),
sal double,
job varchar(32),
deptno int
);
-- 自我复制
insert into my_tab01
(id,`name`,sal,job,deptno)
select empno,ename,sal,job,deptno from emp;
-- 自我复制
insert into my_tab01
select * from my_tab01
select * from my_tab01;
-- 删除一张重复记录
create table my_tab02
like emp;
insert into my_tab02
select * from emp;
-- 去重
-- 思路
-- (1)外创建一张临时表my_tmp ,该表的结构和 my _tab02一样
-- (2)把my_tmp 的记录通过distinct 关键字处理后把记录复制到my_tmp
-- (3)清除掉my _tab02记录
-- (4)把my _tmp―表的记录复制到my _tab02
-- (5) drop掉临时表my_tmp
create table my_tmp like my_tab02
insert into my_tmp
select distinct * from my_tab02;
delete from my_tab02;
insert into my_tab02
select * from my_tmp;
drop table my_tmp ;
select * from my_tab02;
union all就是将两个查询结果合并,不会去重
select ename,sal,job from emp where sal >2500
union all
select ename ,sal,job from emp where job = 'MANAGER'
select ename,sal,job from emp where sal >2500
union
select ename ,sal,job from emp where job = 'MANAGER'
mysql表外连接
外连接
.1.左外连接(如果左侧的表完全显示我们就说是左外连接)
2.右外连接(如果右侧的表完全显示我们就说是右外连接)
select dname,ename,job
from emp,dept
where emp.deptno = dept.deptno
order by dname
create table stu(
id int,
`name` varchar(32));
insert into stu values(1,'huh'),(2,'eff'),(3,'kity'),(4,'yueyue');
create table exam(
id int,
grade int);
insert into exam values(1,25),(2,89),(3,85);
insert into exam values(6,25);
-- 使用左连接(显示所有人的成绩,如果没有成绩,也要显示该人的姓名和id号,成绩显示为空)
select `name`,stu.id,grade
from stu,exam
where stu.id = exam.id
select `name`,stu.id,grade
from stu left join exam
on stu.id = exam.id
select `name`,stu.id,grade
from stu right join exam
on stu.id = exam.id
select dname ,ename,job
from dept left join emp
on dept.deptno = emp.deptno
绝大多数使用前面的连接
mysql约束
基本介绍
约束用于确保数据库的数据满足特定的商业规则。
在mysql中,约束包括: not null、unique,primary key,foreign key,和check五种.
在实际开发中,都需要有一个主键
create table t17(
id int primary key,
`name` varchar(32),
email varchar(32));
-- 主键不可以重复
insert into t17
values(1,'jack','eekg@qq.com')
insert into t17
values(1,'jack','eekg@qq.com')
-- 复合主键
create table t18(
id int,
`name` varchar(32),
email varchar(32),
primary key (id,`name`)
);
insert into t18
values(1,'jack','eekg@qq.com')
insert into t18
values(1,'tom','eekg@qq.com')
insert into t18
values(1,'tom','eekg@qq.com')
create table t19(
id int,
`name` varchar(32),
email varchar(32),
primary key (id)
);
desc t19
unqiue使用细节
–如果没有指定not null ,则unique字段可以有多个null
–如果一个列(字段),是unique not null使用效果类似primary key
– 2.一张表可以有多个unique字段
有外键指向主表不能删除,要先删除从表的指向数据,才能在删除主表的数据
create table my_class(
id int primary key,
`name` varchar(32) not null default '');
create table my_stu(
id int primary key,
`name` varchar(32) not null default '',
class_id int,
foreign key (class_id) references my_class(id))
insert into my_class
values(100,'java'),(200,'web');
insert into my_stu
values (1,'tom',100),(2,'kax',200);
create table goods (
goods_id int primary key,
goods_name varchar(64) not null default '',
unitprice decimal(10,2) not null default 0
check(unitprice >= 1.0 and unitprice <= 9999.99),
catefgory int not null default 0,
provider varchar(64) not null default ''
);
create table customer(
customer_id char(8) primary key,
`name` varchar(64) not null default '',
address varchar(64) not null default '',
email varchar(64) unique not null,
sex enum('男','女') not null,
-- 枚举类型
card_Id char(18) unique
);
create table purchase(
order_id int unsigned primary key,
customer_id char(8) not null default '',
goods_id int not null default 0,
nums int not null default 0,
foreign key (customer_id) references customer(customer_id),
foreign key (goods_id) references goods(goods_id)
);
desc purchase ;
自增长
●自增长使用细节
1.一般来说自增长是和primary key配合使用的
2自增长也可以单独使用[但是需要配合一个unique
3.自增长修饰的字段为整数型的(虽然小数也可以但是非常非常少这样使用)
4.自增长默认从1开始,你也可以通过如下命令修改alter
table表名auto_increment = 新的开始值;
5.如果你添加数据时,给自增长字段(列)指定的有值,则以指定的值为准
create table t24(
id int primary key auto_increment,
emil varchar(32) not null default ''
);
insert into t24
values (null,'ajfe@qq.com');
mysql索引
说起提高数据库性能,索引是最物美价廉的东西了。不用加内存,不用改程序,不用调sql,查询速度就可能提高百倍干倍。
–使用索引来优化一下,体验索引的牛
–在没有创建索引前, emp.ibd文件大小是524m-- empno_index索引名称
– ONemp(empno):表示在 emp表的empno列创建索引
create index empno_index on emp(empno)
create index ename_index on emp(ename);
select *
from emp
where ename = ‘axJxCs’
mysql索引
索引的原理
没有索引为什么会慢?
●使用索引为什么会快?
索引的代价
磁盘占用
对dml(update delete insert)语句的效率影响
create table t25(
id int,
`name` varchar(32)
);
-- 查询表是否有索引
show indexes from t25;
-- 添加索引
-- 添加唯一索引
create unique index id_index on t25(id);
-- 普通索引
create index id_index on t25(id);
alter table t25 add primary key (id)
show index from t25;
-- 删除索引
drop index id_index on t25
-- 删除主键索引
alter table t25 drop primary key
mysql事务
·回退事务
在介绍回退事务前,先介绍一下保存点(savepoint).保存点是事务中的点.用于取消部分事务,当结束事务时(commit),会自动的删除该事务所定义的所有保存点.当执行回退事务时,通过指定保存点可以回退到指定的点,这里我们作图说明
·提交事务
使用commit语句可以提交事务.当执行了commit语句子后,会确认事务的变化、结束事务、删除保存点、释放锁,数据生效。当使用commit语句结束事务子后,其它会话将可以查看到事务变化后的新数据[所有的数据正式生效]
create table t27(
id int,
`name` varchar(32)
);
-- 开启事务
start transaction
-- 设置保存点
savepoint a
insert into t27 values(100,'tom');
savepoint b;
insert into t27 values(200,'jack');
-- 回退到b
rollback to b
select * from t27
rollback to a
-- 表示直接回退到事务开始的状态
rollback
commit
-- 查看当前会话隔离级别
select @@tx_isolation;
-- 查看系统当前隔离级别
select @@global.tx_isolation;
-- 设置当前会话隔离级别
set session transaction isolation level read uncommitted
-- 设置系统当前隔离级别
set global transaction isolation level [你设置的级别]
mysql表类型和存储引擎
●细节说明
我这里重点给大家介绍三种:MylSAM、InnoDB、MEMORY
- My!SAM不支持事务、也不支持外键,但其访问速度快,对事务完整性没有要求
- InnoDB存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是比起MylSAM存储引擎,InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引。
- MEMORY存储引擎使用存在内存中的内容来创建表。每个MEMORY表只实际对应一个磁盘文件。MEMORY类型的表访问非常得快,因为它的数据是放在内存中的,并且默认使用HASH索引。但是一旦mysql服务关闭,表中的数据就会丢失掉,表的结构还在。
show engines;
-- innodb 存储引擎,
-- 1.支持事务 2.支持外键 3.支持行级锁
drop table t27
-- myisam 存储引擎
create table t27(
id int,
`name` varchar(32)
)engine myisam
-- 1.添加速度快 2.不支持外键和事务 3.支持表级锁
start transaction;
savepoint t1
insert into t27 values(1,'jack');
select * from t27
-- 不能回滚
rollback to t1
-- memory 存储引擎
-- 1.数据存储在内存中[关闭了mysql服务,数据丢失,但是表结构还在], 2.执行速度很快(没有IO读写) 3.默认支持索引(hash表)
create table t28(
id int,
`name` varchar(32)
)engine memory
insert into t28
values(1,'tom'),(2,'jack'),(3,'hhh');
select * from t28
如何选择表的存储引擎
1.如果你的应用不需要事务,处理的只是基本的CRUD操作,那么MylSAM是不二选择.速度快
2.如果需要支持事务,选择lnnoDB。
3. Memory存储引擎就是将数据存储在内存中,由于没有磁盘I/O的等待,速度极快。但由于是内存存储引擎,所做的任何修改在服务器重启后都将消失。(经典用法用户的在线状态())
视图(view)
●基本概念
1.视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含列,其数据来自对应的真实表(基表)
2.视图和基表关系的示意图
视图(view)
●视图的基本使用
- create view视图名as select语句
- alter view视图名as select语句
- SHOW CREATE VIEW 视图名
- drop view视图名1,视图名2
-- 视图的使用
-- 创建视图
create view emp_view01
as
select empno,ename,job,deptno from emp;
-- 查看视图
desc emp_view01
select * from emp_view01 ;
-- 查看创建视图的指令
show create view emp_view01
-- 删除视图
drop view emp_view01
视图中可以再使用视图,数据仍然来自基表
-- 视图的使用
-- 创建视图
create view emp_view01
as
select empno,ename,job,deptno from emp;
update emp_view01
set job = 'MANAGER'
where empno = 7369
select * from emp
select * from emp_view01
-- 修改基表,会影响到视图
update emp
set job = 'SALESMAN'
where empno = 7369
desc emp_view01
create view emp_view02
as
select empno,ename from emp_view01
select * from emp_view02
create view emp_view03
as
select empno, ename, dname,grade
from emp,dept,salgrade
where emp.deptno = dept.deptno and
(sal between losal and hisal)
desc emp_view03;
desc dept
desc emp
select dname
from dept
select ename,(sal + ifnull(comm,0) )*13 as "年收入"
from emp
select ename,sal
from emp
where sal < 1500 or sal > 2850
select ename,sal
from emp
where not (sal >= 1500 and sal <= 2850)
select ename,deptno
from emp
where empno = 7566
select ename,job
from emp
where (deptno = 10 or deptno = 30) and sal>1500
select ename,job
from emp
where mgr is null
select ename ,job ,hiredate
from emp
where hiredate >= '1991-02-01'and hiredate <= '1991-05-01'
order by hiredate
select ename,sal,comm
from emp
order by sal desc
select *
from emp
where deptno = 30
select ename,empno ,deptno ,job
from emp
where job = 'CLERK'
select * from
emp
where ifnull(comm,0) > sal
select * from
emp
where ifnull(comm,0)>sal*0.6
select * from
emp
where (deptno = 10 and job = 'MANAGER') or (deptno = 20 and job = 'CLERK')
select * from
emp
where (deptno = 10 and job = 'MANAGER')
or (deptno = 20 and job = 'CLERK')
or (job != 'MANAGER' and job != 'CLERK' and sal >= 2000)
select distinct job
from emp
where comm is not null
select distinct *
from emp
where comm is null or ifnull(comm,0) < 100
select last_day('2011-11-11')
-- ------9.找出各月倒数第3天受雇的所有员工.
--- last day(日期),~可以返回该日期所在月份的最后一天
-- last_day(日期)-2得到日期所有月份的倒数第3天
select *
from emp
where last_day(hiredate) - 2 == hiredate
select *
from emp
where date_add(hiredate,interval 12 year)
select concat(lcase(substring(ename,1,1)),substring(ename,2))
from emp
select *
from emp
where length(ename) = 5
select *
from emp
where ename not like '%R%'
select left(ename,3)
from emp
select replace (ename,'A','a')
from emp
select ename,hiredate
from emp
where date_add(hiredate,interval 10 year) <= now()
select *
from emp
order by ename
select ename,hiredate
from emp
order by hiredate
select ename,job,sal
from emp
order by job desc,sal
select ename,concat(year(hiredate),'-', month(hiredate))
from emp
order by month(hiredate),year(hiredate)
select floor(sal/30),sal/30
from emp;
select *
from emp
where month(hiredate) = 2
select *
from emp
where ename like '%A%'
select ename,floor(datediff(now(),hiredate)/365) as "工作年" ,
floor(datediff(now(),hiredate)%365 / 31) as "工作月",
datediff(now(),hiredate)%31 as "工作天数"
from emp;
select count(*) as c,deptno
from emp
group by deptno
having c > 1
select *
from emp
where sal >(
select sal
from emp
where ename = 'SMITH'
)
select worker.ename as '员工名', worker.hiredate as '员工入职时间',
leader.ename as '上级名',leader.hiredate as '上级入职时间'
from emp worker , emp leader
where worker.hiredate > leader.hiredate
and worker.mgr = leader.empno;
select dname,emp.*
from dept left join emp on dept.deptno = emp.deptno
select dname,emp.*
from dept
left join emp on dept.deptno = emp.deptno
select ename,dname
from emp,dept
where job = 'CLERK' and emp.deptno = dept.deptno
select min(sal) as min_sal,job
from emp
group by job
having min_sal > 1500
select ename,dname
from emp,dept
where emp.deptno = dept.deptno and dname = 'SALES'
select *
from emp
where sal > (
select avg(sal)
from emp
)
select *
from emp
where job = (
select job
from emp
where ename = 'SCOTT' )
select ename,sal
from emp
where sal > (
select max(sal)
from emp
where deptno = 30
)
select count(*) as '部门员工数量',deptno,avg(sal) as '部门平均工资',
format(avg(datediff(now(),hiredate)/365),2) as '平均服务期限(年)'
from emp
group by deptno
select count(*) as c,deptno
from emp
group by deptno
select dept.*,tmp.c
from dept,(
select count(*) as c,deptno
from emp
group by deptno )tmp
where dept.deptno = tmp.deptno
select min(sal) ,job
from emp
group by job
select min(sal),job
from emp
where job = 'MANAGER'
select ename, (sal + ifnull(comm,0))*12 year_sal
from emp
order by year_sal
create table department(
departmentid varchar(32) primary key,
deptname varchar(32) unique not null
);
create table `class`(
classid int primary key,
`subject` varchar(32) not null default '',
deptname varchar(32),
enrolltime int not null default 2000,
num int not null default 0,
foreign key (deptname) references department(deptname)
);
create table student_d(
studentid int primary key,
`name` varchar(32) not null default '',
age int not null default 0,
classid int,
foreign key (classid) references `class`(classid)
);