Java阶段二Day07

Java阶段二Day07

V17

利用反射机制重构DispatcherServlet,使得将来添加新的业务时DispatcherServlet不必再添加分支判断(不进行修改)

实现:

  1. 新建包com.webserver.annotation
  2. annotation包下添加两个注解
    • @Controller:用于标注哪些类是处理业务的Controller
    • @RequestMapping:用于标注处理某个业务请求的业务方法
  3. com.webserver.controller包下的所有Controller类添加注解@Controller并将里面用于处理某个业务的方法标注@RequestMapping并指定该方法处理的请求
  4. DispatcherServlet在处理请求时,先扫描controller包下的所有Controller类,并找到处理该请求的业务方法,使用反射调用

UserController

package com.birdboot.controller;

import com.birdboot.annotations.Controller;
import com.birdboot.annotations.RequestMapping;
import com.birdboot.entity.User;
import com.birdboot.http.HttpServletRequest;
import com.birdboot.http.HttpServletResponse;

import java.io.*;

/**
 * 处理与用户相关的业务
 */
@Controller
public class UserController {
    private static File userDir;//表示存放所有用户信息的目录:users
    static {
        userDir = new File("./users");
        if(!userDir.exists()){
            userDir.mkdirs();
        }
    }

    @RequestMapping("/regUser")
    public void reg(HttpServletRequest request, HttpServletResponse response){
        System.out.println("开始处理用户注册");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String nickname = request.getParameter("nickname");
        String ageStr = request.getParameter("age");
        System.out.println(username+","+password+","+nickname+","+ageStr);
        //必要的验证
        if(username==null||username.isEmpty()||
                password==null||password.isEmpty()||
                nickname==null||nickname.isEmpty()||
                ageStr==null||ageStr.isEmpty()||
                !ageStr.matches("[0-9]+")
        ){
            response.sendRedirect("/reg_info_error.html");
            return;
        }

        int age = Integer.parseInt(ageStr);//将年龄转换为int值
        //2
        User user = new User(username,password,nickname,age);
        /*
            File的构造器
            File(File parent,String child)
            创建一个File对象表示child这个子项,而它是在parent这个File对象所表
            示的目录中
         */
        File file = new File(userDir,username+".obj");
        if(file.exists()){//注册前发现以该用户名命名的obj文件已经存在,说明是重复用户
            response.sendRedirect("/have_user.html");
            return;
        }

        try (
                FileOutputStream fos = new FileOutputStream(file);
                ObjectOutputStream oos = new ObjectOutputStream(fos);
        ){
            oos.writeObject(user);//保存用户信息完毕

            //3给用户回馈注册成功页面
            //要求浏览器重新访问下述地址对应的页面
            response.sendRedirect("/reg_success.html");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @RequestMapping("/loginUser")
    public void login(HttpServletRequest request,HttpServletResponse response){
        System.out.println("开始处理登录!!!!");
        //1获取登录信息
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //必要验证
        if(username==null||username.isEmpty()||password==null||password.isEmpty()){
            response.sendRedirect("/login_info_error.html");
            return;
        }

        //根据该登录用户的名字去定位users下该用户的注册信息
        File file = new File(userDir,username+".obj");
        //判断该文件是否存在,不存在则说明该用户没有注册过
        if(file.exists()){
            //将该用户曾经的注册信息读取出来用于比较密码
            try (
                    FileInputStream fis = new FileInputStream(file);
                    ObjectInputStream ois = new ObjectInputStream(fis);
            ){
                User user = (User)ois.readObject();//读取注册信息
                //比较本次登录的密码是否与注册时该用户输入的密码一致
                if(user.getPassword().equals(password)){
                    //密码一致则登录成功
                    response.sendRedirect("/login_success.html");
                    return;
                }
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        //如果程序可以执行到这里,则说明要么是用户名没输入对,要么是密码没有输入对.都属于登录失败
        response.sendRedirect("/login_fail.html");
    }
}

DispatcherServlet

package com.birdboot.core;

import com.birdboot.annotations.Controller;
import com.birdboot.annotations.RequestMapping;
import com.birdboot.controller.UserController;
import com.birdboot.http.HttpServletRequest;
import com.birdboot.http.HttpServletResponse;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;

/**
 * V8新增内容:
 * 该类是SpringMVC框架与Tomcat整合时的一个关键类
 * Tomcat处理业务原生的都是调用继承了HttpServlet的类来完成,此时需要进行很多配置
 * 以及使用时要作很多重复性劳动。
 * SpringMVC框架提供的该类也是继承了HttpServlet的,使用它来接收处理请求的工作。
 */
public class DispatcherServlet {
    private static File baseDir;//类加载路径
    private static File staticDir;//类加载路径下的static目录

    static {
        try {
            //定位当前项目的类加载路径
            baseDir = new File( DispatcherServlet.class.getClassLoader().getResource(".").toURI());
            //定位类加载路径下的static目录
            staticDir = new File(baseDir, "static");
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    /**
     * service方法实际上是当我们继承了HttpServlet后必须重写的方法
     * 该方法要求接收两个参数:请求对象与响应对象。
     * Tomcat在处理请求时就是调用某个Servlet的service方法并将请求与响应对象传入
     * 来让其完成处理工作的。
     */
    public void service(HttpServletRequest request, HttpServletResponse response) {
        //获取请求的抽象路径
        //不能在使用uri判断请求了,因为uri可能含参数,内容不固定。
        String path = request.getRequestURI();//path:"/regUser"
        System.out.println(path);

        //判断该请求是否为请求一个业务
        /*
            V17新增内容:
            当我们得到本次请求路径path的值后,我们首先要查看是否为请求业务:
            1:扫描controller包下的所有类
            2:查看哪些被注解@Controller标注的过的类(只有被该注解标注的类才认可为业务处理类)
            3:遍历这些类,并获取他们的所有方法,并查看哪些时业务方法
              只有被注解@RequestMapping标注的方法才是业务方法
            4:遍历业务方法时比对该方法上@RequestMapping中传递的参数值是否与本次请求
              路径path值一致?如果一致则说明本次请求就应当由该方法进行处理
              因此利用反射机制调用该方法进行处理。
              提示:反射调用后要记得return,避免执行后续处理静态资源的操作
            5:如果扫描了所有的Controller中所有的业务方法,均未找到与本次请求匹配的路径
              则说明本次请求并非处理业务,那么执行下面请求静态资源的操作
         */
        //定位controller目录   使用File访问文件系统时,路径中目录的层级分割是用"/"
        try {
            File dir = new File(baseDir,"com/birdboot/controller");
            //获取该目录下的所有.class文件
            File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
            for(File sub : subs){//遍历每一个.class文件
                String fileName = sub.getName();//获取文件名
                String className = fileName.substring(0,fileName.indexOf("."));//根据文件名获取类名
                //包名的层级分割使用"."
                Class cls = Class.forName("com.birdboot.controller."+className);
                //判断该类有没有注解@Controller
                if(cls.isAnnotationPresent(Controller.class)){
                    //扫描该类的所有方法
                    Method[] methods = cls.getDeclaredMethods();
                    //遍历每一个方法
                    for(Method method : methods){
                        //判断该方法是否有注解@RequestMapping
                        if(method.isAnnotationPresent(RequestMapping.class)){
                            //获取注解
                            RequestMapping rm = method.getAnnotation(RequestMapping.class);
                            //通过注解对象获取参数
                            String value = rm.value();
                            //对比本次请求是否与该方法注解参数一致?
                            if(path.equals(value)){
                                //一致则说明本次请求应当交由该方法处理
                                //实例化该Controller
                                Object c = cls.newInstance();
                                //调用该方法处理本次请求
                                method.invoke(c,request,response);
                                return;//处理后解除本次处理请求(避免执行下面处理静态资源的部分)
                            }
                        }
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        File file = new File(staticDir, path);
        if (file.isFile()) {
            //由于响应对象中状态代码和描述默认值为200,OK因此正确情况下不用再设置
            response.setContentFile(file);
            //设置响应头
            response.addHeader("Server", "BirdServer");
        } else {
            response.setStatusCode(404);
            response.setStatusReason("NotFound");
            file = new File(staticDir, "404.html");
            response.setContentFile(file);
            response.addHeader("Server", "BirdServer");
        }
    }
}

Controller

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}

RequestMapping

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
    String value();
}

V18

重构代码
上一个版本那种DispatcherServlet每次处理请求时都要扫描controller包,这样性能低下,因此改为仅扫描一次

实现:

  1. com.webserver.core包下新建类HandlerMapping
  2. 定义静态属性Map mapping key:请求路径;value:Method记录处理该请求的方法对象
  3. 在静态块中初始化,完成原DispatcherServlet扫描controller包的工作并初始化mapping
  4. 提供静态方法:getMethod()可根据请求路径获取处理该请求的方法
  5. DispatcherServlet中处理业务时只需要根据请求获取对应的处理方法利用反射机制调用即可

DispatcherServlet

package com.birdboot.core;

import com.birdboot.annotations.Controller;
import com.birdboot.annotations.RequestMapping;
import com.birdboot.controller.UserController;
import com.birdboot.http.HttpServletRequest;
import com.birdboot.http.HttpServletResponse;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;

/**
 * V8新增内容:
 * 该类是SpringMVC框架与Tomcat整合时的一个关键类
 * Tomcat处理业务原生的都是调用继承了HttpServlet的类来完成,此时需要进行很多配置
 * 以及使用时要作很多重复性劳动。
 * SpringMVC框架提供的该类也是继承了HttpServlet的,使用它来接收处理请求的工作。
 */
public class DispatcherServlet {
    private static File baseDir;//类加载路径
    private static File staticDir;//类加载路径下的static目录

    static {
        try {
            //定位当前项目的类加载路径
            baseDir = new File(
                    DispatcherServlet.class.getClassLoader().getResource(".").toURI()
            );
            //定位类加载路径下的static目录
            staticDir = new File(baseDir, "static");
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    /**
     * service方法实际上是当我们继承了HttpServlet后必须重写的方法
     * 该方法要求接收两个参数:请求对象与响应对象。
     * Tomcat在处理请求时就是调用某个Servlet的service方法并将请求与响应对象传入
     * 来让其完成处理工作的。
     */
    public void service(HttpServletRequest request, HttpServletResponse response) {
        //获取请求的抽象路径
        //不能在使用uri判断请求了,因为uri可能含参数,内容不固定。
        String path = request.getRequestURI();//path:"/regUser"
        System.out.println(path);

        //判断该请求是否为请求一个业务
        Method method = HandlerMapping.getMethod(path);
        if(method!=null){//本次为请求业务
            //通过方法获取其所属类的类对象(某个Controller)
            try {
                Class cls = method.getDeclaringClass();
                Object obj =cls.newInstance();
                method.invoke(obj,request,response);
            } catch (Exception e) {
               //如果处理业务过程中报错,这是典型的因为服务端处理请求出现错误导致处理失败(500错误)
               response.setStatusCode(500);
               response.setStatusReason("Internal Server Error");
            }
        }else {
            File file = new File(staticDir, path);
            if (file.isFile()) {
                //由于响应对象中状态代码和描述默认值为200,OK因此正确情况下不用再设置
                response.setContentFile(file);
                //设置响应头
                response.addHeader("Server", "BirdServer");
            } else {
                response.setStatusCode(404);
                response.setStatusReason("NotFound");
                file = new File(staticDir, "404.html");
                response.setContentFile(file);
                response.addHeader("Server", "BirdServer");
            }
        }
    }
}

HandleMapping

package com.birdboot.core;

import com.birdboot.annotations.Controller;
import com.birdboot.annotations.RequestMapping;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

/**
 * SpringMVC框架使用这个类来维护所有Controller
 */
public class HandlerMapping {
    private static File baseDir;//类加载路径
    /*
        请求与对应的处理方法的映射关系
        key:请求路径(与对应方法上@RequestMapping注解参数一致)
        value:处理该请求的方法
     */
    private static Map<String, Method> mapping = new HashMap<>();

    static{
        try {
            //定位当前项目的类加载路径
            baseDir = new File(
                    HandlerMapping.class.getClassLoader().getResource(".").toURI()
            );
            initMapping();
        } catch (URISyntaxException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化mapping
     */
    private static void initMapping() throws ClassNotFoundException {
        File dir = new File(baseDir,"com/birdboot/controller");
        //获取该目录下的所有.class文件
        File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
        for(File sub : subs){//遍历每一个.class文件
            String fileName = sub.getName();//获取文件名
            String className = fileName.substring(0,fileName.indexOf("."));//根据文件名获取类名
            //包名的层级分割使用"."
            Class cls = Class.forName("com.birdboot.controller."+className);
            //判断该类有没有注解@Controller
            if(cls.isAnnotationPresent(Controller.class)){
                //扫描该类的所有方法
                Method[] methods = cls.getDeclaredMethods();
                //遍历每一个方法
                for(Method method : methods){
                    //判断该方法是否有注解@RequestMapping
                    if(method.isAnnotationPresent(RequestMapping.class)){
                        //获取注解
                        RequestMapping rm = method.getAnnotation(RequestMapping.class);
                        //通过注解对象获取参数
                        String value = rm.value();
                        //将该方法与其处理的请求路径以key,value形式存入mapping
                        mapping.put(value,method);
                    }
                }
            }
        }
    }

    /**
     * 根据请求路径获取某个Controller下的对应处理方法
     * @param path
     * @return
     */
    public static Method getMethod(String path){
        return mapping.get(path);
    }

    public static void main(String[] args) {
        Method method = getMethod("/regUser");
        System.out.println(method);
    }
}

V19

使用线程池管理线程
在主启动类BirdBootApplication中定义线程池,
并在接收客户端链接后将ClientHandler交给线程池处理

BirdBootApplication

package com.birdboot.core;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 主启动类
 */
public class BirdBootApplication {
    private ServerSocket serverSocket;
    private ExecutorService threadPool;

    public BirdBootApplication(){
        try {
            System.out.println("正在启动服务端...");
            serverSocket = new ServerSocket(8088);
            threadPool = Executors.newFixedThreadPool(50);
            System.out.println("服务端启动完毕!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start(){
        try {
            while(true) {
                System.out.println("等待客户端链接...");
                Socket socket = serverSocket.accept();
                System.out.println("一个客户端链接了!");
                //启动一个线程处理该客户端交互
                ClientHandler handler = new ClientHandler(socket);
                threadPool.execute(handler);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        BirdBootApplication application = new BirdBootApplication();
        application.start();
    }
}

线程池

  • 复用线程
  • 线程的数量控制

线程的执行过程

  1. 线程任务:Runnable
  2. 创建线程:new Thread()
  3. 启动:start()
  4. 并发执行中:Running
  5. 任务执行完毕:Dead
  6. 线程销毁:gc

线程池API

  • Executors:创建线程池的工厂类,用于创建线程池对象
  • ExecutorService:线程池接口,规定线程池相关功能方法

创建线程池ExecutorService pool = Executors.newFixedThreadPool(容量)

创建并指派任务

  1. 创建任务:实现Runnable接口重写run()方法
  2. 指派任务:调用线程池方法 pool.execute(任务)

线程池的关闭

  1. shutdown():不再接收新的任务,将现有任务执行完毕结束线程池中所以线程
  2. shutdownNow():不再接收新任务,中断线程池所有线程

数据库

数据库的基本概念

  • 数据库DataBase:保存一组数据的仓库就是数据库

  • 数据库管理系统(DBMS):一套可以独立运行的软件,用于维护磁盘上的数据,维护性好,性能好,可扩展性强

    常见的DBMS:

    • MySQL
    • MariaDB
    • Oracle
    • DB2
    • SQLServer

数据库管理系统中常见的概念

  • 库:是表的集合,一个库中可以存放若干张表。通常库是服务于项目的。

  • 表:是数据的集合,具有一组相同属性的数据存放在同一张表中。

    • 行:存放数据
    • 列:存放字段
  • 数据库的角色:数据库是一个独立运行的软件,并且是以服务端的形式体现的,我们要操作数据库则需要以客户端的角度与服务端建立连接并进行相关的操作

  • 数据库的交互:连接数据库后,向其发送SQL语句(Structured Query Language 结构化查询语言),数据库会理解该SQL语句的含义并进行对应操作

    SQL语句的标准:SQL92标准,所有DBMS都支持SQL92标准,该标准就是操作数据库的“普通话”,但不是所有的数据库操作都在SQL92标准中,不在该标准中的操作,不同的数据库提供的语法可能完全不同,此时这类SQL称为“方言”

  • 常用的客户端

    • 命令行
    • 图形化界面
    • JDBC
    • 集成开发环境(IDE)

在这里插入图片描述

SQL分类

  • DDL:数据定义语言,是操作数据库对象的语言。数据库对象(库,表,视图,索引,序列)
  • DML:数据操作语言,是操作表中数据的语言。对表中数据操作的语言(增INSERT,删DELETE,改UPDATE)
  • DQL:数据查询语言,是查询表中数据的语言。SELECT语句(学习的重点和难点)
  • DCL:数据控制语言,管理数据库的语言(权限分配等,DBA关心的)
  • TCL:事务控制语言,控制事务操作

DDL语言-数据定义语言

对数据库的操作

  • 新建一个数据库:

    CREATE DATABASE 数据库名 [charset = 字符集]
    # 指定字符集
    CREATE DATABASE mydb1 CHARSET = UTF8;
    CREATE DATABASE mydb2 CHARSET = GBK;
    
  • 查看已创建数据库:

    SHOW DATABASES;
    
  • 查看创建数据库时的信息:

    SHOW CREATE DATABASE 数据库名
    
  • 删除数据库:

    DROP DATABASE 数据库名
    
  • 切换数据库:

    USE 数据库名
    

对数据表的操作

  • 创建数据库表

    CREATE TABLE 表名(
    	字段名1 类型[(长度)][DEFALUT 默认值][约束],
        字段名2 类型[(长度)][DEFALUT 默认值][约束],
    ) [charset = 字符集]
    
  • 查看表结构:

    DESC 表名
    
  • 查看表创建时的信息:

    SHOW CREATE TABLE 表名
    
  • 查看当前数据库中创建的所有表:

    SHOW TABLES
    
  • 修改表名:

    RENAME TABLE 原表名 TO 新表名
    
  • 删除表:

    DROP TABLE 表名
    
  • 修改表结构,在表末尾追加新字段:

    ALTER TABLE 表名 ADD 字段名 类型[(长度) 默认值 约束]
    
  • 修改表结构,在表最开始添加新字段:

    ALTER TABLE 表名 ADD 字段名 类型 [(长度) 默认值 约束] FIRST
    
  • 修改表结构,在表中间插入新字段:

    ALTER TABLE 表名 ADD 字段名 类型[(长度) 默认值 约束] AFTER 表中现有字段名
    
  • 修改表结构,在表中删除字段:

    ALTER TABLE 表名 DROP 字段名
    
  • 修改表结构,在表中修改现有字段:

    ALTER TABLE 表名 CHANGE 原字段名 新字段名 类型 [(长度) 默认值 约束]
    

修改表结构的注意事项

  • 修改表结构最好在表中没有数据的情况下进行
  • 当表中含有数据时,
    • 尽量不修改表中某字段类型,否则可能因为现有数据不满足新修改的类型导致修改失败
    • 尽量不缩短字段长度
    • 若为字段新添加约束,该字段现有的数据不能违反该约束

教师总结

数据库基本概念

数据库DataBase

定义:

保存一组数据的仓库就是数据库

BirdBoot项目中,我们为了保存一组用户信息,创建了一个目录users。里面用若干个文件保存每一个用户信息

此时users目录就可以称为是一个数据库

只不过对于这些数据的维护操作,要么手动,要么通过自己编码来维护。

手动操作效率低

编码来维护:维护成本高,可扩展性差

数据库管理系统(DBMS)

定义

一套独立可运行的软件,用于维护磁盘上的数据。维护性好,性能好,可扩展性强。

常见的DBMS
  • MySQL
  • MariaDB
  • Oracle
  • DB2
  • SQLServer

在JAVA项目中与数据库的结合

在这里插入图片描述

数据库管理系统中常见的概念

是表的集合,一个库中可以存放若干张表。通常库是服务于项目的。

是数据的集合,具有一组相同属性的数据存放在同一张表中。

行:称为是记录,表中每一条数据

列:称为是字段,每一条记录的属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4VdfTYPz-1682301378131)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423180410555.png)]

BirdBoot项目中,涉及到的数据有用户信息,文章信息。用户信息就可以设计一张用户表保存。文章信息可以设计一张文章表保存

库与表的关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A3mtbWmm-1682301378131)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423180457751.png)]

库与DBMS的关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8yuC4mXQ-1682301378131)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423180526251.png)]

如何操作数据库

数据库的角色

数据库是一个独立运行的软件,并且是以服务端的形式体现的,我们要操作数据库则需要以客户端的角度与服务端建立连接并进行相关的操作

数据库的交互

我们连接上数据库后,向其发送SQL语句,数据库理解该SQL语句的含义并执行相关操作并回馈结果.

SQL语句的标准:SQL92标准。

所有的DBMS都支持SQL92标准,该标准就是操作数据库的"普通话"。

不是所有的数据库操作都在SQL92标准中,不在该标准中的操作不同的数据库提供的语法可能完全不同,此时这类SQL称为是"方言"

学习重点

学会SQL语句

SQL:全称Structured Query Language

数据库的连接方式

常用的客户端

  • 命令行
  • 图形化界面
  • JDBC
  • 集成开发环境(IDE)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fTicwFVQ-1682301378132)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423151449935.png)]

SQL语言

Structured Query Language,结构化查询语言

操作数据库的语言

SQL语句不区分大小写,但是好的书写习惯:关键字大写,非关键字小写

SQL分类

  • DDL:数据定义语言,是操作数据库对象的语言。数据库对象(库,表,视图,索引,序列)

  • DML:数据操作语言,是操作表中数据的语言。对表中数据操作的语言(增INSERT,删DELETE,改UPDATE)

  • DQL:数据查询语言,是查询表中数据的语言。SELECT语句(学习的重点和难点)

  • DCL:数据控制语言,管理数据库的语言(权限分配等,DBA关心的)

  • TCL:事务控制语言,事务控制语言。

DDL语言-数据定义语言

对数据库对象进行操作的语言, 涉及到的关键字CREATE,ALTER,DROP

对数据库的操作

新建一个数据库
语法
CREATE DATABASE 数据库名 [charset=字符集]
新建一个数据库:mydb
CREATE DATABASE mydb;

注:SQL语句不区分大小写,但是好的书写习惯:关键字大写,非关键字小写

指定字符集
创建数据库mydb1,指定字符集为UTF-8
CREATE DATABASE mydb1 CHARSET=UTF8;

创建数据库mydb2,指定字符集为GBK
CREATE DATABASE mydb2 CHARSET=GBK;
查看已创建的数据库
语法
SHOW DATABASES;
查看创建数据库时的信息
语法
SHOW CREATE DATABASE 数据库名
SHOW CREATE DATABASE mydb
删除数据库
语法
DROP DATABASE 数据库名
DROP DATABASE mydb
切换数据库
语法
USE 数据库名

USE mydb1;    //切换数据库到mydb1
USE mydb2;      //切换数据库到mydb2
练习
题干
1. 创建 db1和db2 数据库 字符集分别为utf8和gbk
2. 查询所有数据库检查是否创建成功
3. 检查两个数据库的字符集是否正确(查看创建时的SQL)
4. 先使用db2 再使用 db1
5. 删除两个数据库
答案
1. 创建 db1和db2 数据库 字符集分别为utf8和gbk
   CREATE DATABASE db1 CHARSET=UTF8
   CREATE DATABASE db2 CHARSET=GBK
2. 查询所有数据库检查是否创建成功
   SHOW DATABASES
3. 检查两个数据库的字符集是否正确(查看创建时的SQL)
   SHOW CREATE DATABASE db1
   SHOW CREATE DATABASE db2
4. 先使用db2 再使用 db1
   USE db2
   USE db1
5. 删除两个数据库
   DROP DATABASE db1
   DROP DATABASE db2

表操作

创建表
语法
CREATE TABLE 表名(
   字段名名1 类型[(长度)] [DEFALUT 默认值] [约束],
    字段名名2 类型,
    ...
)[CHARSET=字符集]
准备一个数据库mydb并使用
CREATE DATABASE mydb;        创建数据库mydb
USE mydb;                 切换到mydb,那么后面创建表都是创建到这个库中

创建一张表user,保存用户信息(用户名,密码,昵称,年龄)
CREATE TABLE user(
   id INT,                类型是方言,不同数据库不同,mysql中整数为INT,oraclet为Number
    username VARCHAR(32),   字符串类型是VARCHAR,长度为字节量,如果是UTF-8编码32字节可以存
    password VARCHAR(32),   10个汉字。
    nickname VARCHAR(32),
    age INT(3)              对于整数而言,长度表示保存的数字位数。
)

查看表结构
语法
DESC 表名
查看user表的结构
DESC user
查看表创建时的信息
语法
SHOW CREATE TABLE 表名
SHOW CREATE TABLE user
查看当前数据库中创建的所有表
语法
SHOW TABLES
修改表名
语法
RENAME TABLE 原表名 TO 新表名
user表改名为userinfo
RENAME TABLE user TO userinfo
删除表
语法
DROP TABLE 表名
删除表userinfo
DROP TABLE userinfo
练习
题干
1.创建数据库mydb3 字符集gbk 并使用
2.创建t_hero英雄表, 有名字和年龄字段
3.修改表名为hero
4.查看表hero的信息
5.查询表hero结构
6.删除表hero
7.删除数据库mydb3
答案
1.创建数据库mydb3 字符集gbk 并使用
  CREATE DATABASE mydb3 CHARSET=GBK
  USE mydb3
  
2.创建t_hero英雄表, 有名字和年龄字段
  CREATE TABLE t_hero(
   username VARCHAR(32),
    age INT(3)  
  )
  
3.修改表名为hero
  RENAME TABLE t_hero TO hero
  
4.查看表hero的信息
  SHOW CREATE TABLE hero
 
5.查询表hero结构
  DESC hero
  
6.删除表hero
  DROP TABLE hero
  
7.删除数据库mydb3
  DROP DATABASE mydb3
修改表结构

准备一张表

CREATE TABLE hero(
   name VARCHAR(32),
   age INT(3)
)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vRanYfzv-1682301378133)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423172604851.png)]

添加一个字段
在表末尾追加新字段

语法

ALTER TABLE 表名 ADD 字段名 类型[(长度) 默认值 约束]

向表hero的末尾添加一个新字段gender,它的类型是字符串,长度占10个字节
ALTER TABLE hero ADD gender VARCHAR(10)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ws0H0UZJ-1682301378133)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423172901963.png)]

在表最开始添加字段

语法

ALTER TABLE 表名 ADD 字段名 类型 FIRST

在hero表最开始添加id字段,类型为int
ALTER TABLE hero ADD id INT FIRST

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rCwal7ZU-1682301378134)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423173422995.png)]

在表中插入新的字段

语法

在表中现有的字段后面添加新字段
ALTER TABLE 表名 ADD 字段名 类型 AFTER 表中现有字段名

在name字段后面添加密码pwd字段
ALTER TABLE hero ADD pwd VARCHAR(32) AFTER name

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hfMXRd7R-1682301378134)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423173847976.png)]

删除字段
语法
ALTER TABLE 表名 DROP 字段名
将hero中的pwd字段删除
ALTER TABLE hero DROP pwd

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WmMkIN2L-1682301378135)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423174203769.png)]

修改表字段
语法
ALTER TABLE 表名 CHANGE 原字段名 新字段名 类型[长度 默认值 约束]
修改hero表中的年龄字段长度为5
ALTER TABLE hero CHANGE age age INT(5)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pl9hysgj-1682301378136)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423174636156.png)]

修改hero表中的年龄字段为字符串,长度为20字节
ALTER TABLE hero CHANGE age age VARCHAR(20)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kOSefdc2-1682301378136)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423174929433.png)]

修改hero表中的gender字段,改名为nickname 类型为字符串,长度30字节
ALTER TABLE hero CHANGE gender nickname VARCHAR(30)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dPQX4MZp-1682301378137)(C:\Users\TEACHER\IdeaProjects\BirdBoot2303\数据库笔记\image-20230423175140181.png)]

修改表结构的注意事项
  • 修改表结构最好是在表中没有数据的情况下进行
  • 当表中含有数据时
    • 尽量不修改表中某字段的类型,否则可能因为现有数据不满足新修改的类型导致修改失败
    • 尽量不缩短字段长度
    • 若为字段新添加约束,该字段现有的数据不能违反该约束
综合练习
题干
1.创建数据库mydb4 字符集utf8并使用
2.创建teacher表 有名字(name)字段
3.添加表字段: 最后添加age 最前面添加id(int) , age前面添加salary工资(int)
4.删除age字段
5.修改表名为t
6.删除表t
7.删除数据库mydb4
答案
#创建数据库mydb4字符集utf8并使用
CREATE DATABASE mydb4 CHARSET = utf8;
# 创建teacher表有名字(name)字段
CREATE TABLE teacher(
    name VARCHAR(255) NOT NULL
);
#添加表字段:最后添加age最前面添加id(int型),age前面添加salary工资(int型)
ALTER TABLE teacher ADD age CHAR(1);
ALTER TABLE teacher ADD id INT(32) FIRST;
ALTER TABLE teacher ADD salary INT(32) AFTER id;
# 删除age字段
ALTER TABLE teacher DROP age;
# 修改表名为t
ALTER TABLE teacher RENAME TO t;
# 或
RENAME TABLE teacher TO t;
# 删除表t
DROP TABLE t;
#删除数据库mydb4
DROP DATABASE mydb4;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天你学Java了吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值