Java Web

1. Java Web

用 Java 去开发基于 Web 的应用程序,Java EE基于Java开发企业解决方案

Java Web 是 Java EE 的主要分支

用Java 开发 Web 应用

需要一个 Web 应用服务器,专门对外提供服务的,将写好的 Java 程序部署到这个 Web 应用服务器上,从而完成与客户端的交互。

Web 应用服务器,它是一个产品,是一个可以安装到服务器计算机上的一个服务产品,我们可以在 Web 应用服务器上部署一些供客户端访问的资源,然后启动该服务,那么客户端就可以通过浏览器访问这些资源。

Web 应用服务器:Tomcat、Jboss、Weblogic、Jetty

Tomcat

bin:各个平台(Windows、Mac/Linux)启动/停止 Tomcat 服务的脚本

shell脚本就是mac和Linux

conf:Tomcat 的配置文件

lib:Tomcat 需要用到 jar

logs:Tomcat 启动日志

temp:Tomcat 运行的临时文件

webapps:Tomcat 中允许客户端访问的资源

work:Tomcat 将 JSP 生成的 Servlet 放在这里

2. Servlet

Servlet 就是运行在 Tomcat 中,单独的 Servlet 无法运行,必须部署到 Tomcat 中才能运行,负责与客户端进行通信:

1、接收客户端的请求

2、创建并返回基于客户端请求的动态 HTML 页面

3、与数据库进行通信

Servlet 就是一个 Java 类,是一个接口,描述的功能是让某个 Java 类具备处理客户端请求的能力。

自定义一个 Java 类,实现 Servlet 接口,Java 类就可以处理客户端的请求。

2.1 servelt 生命周期

1、当浏览器请求 Servlet 的时候,Tomcat 会进行检索,找到 url 中映射的 Servlet,判断当前 Servlet 对象是否存在,如果不存在则创建 Servlet 对象,执行第 2 步,如果存在,则直接调用,跳过第 2 步,执行第 3 步。

Servlet 是单例模式的,通过反射机制创建 Servlet 对象。

2、执行 init 完成初始化操作(第一次创建完成 Servlet 之后会调用,如果 Servlet 已经存在则不执行)。

3、执行 service 完成相关的业务逻辑。

4、执行 destroy 方法销毁 Servlet 对象,关闭 Tomcat 服务时调用。

2.2 servlet 生命周期方法

1.构造函数只调用一次,第一次请求Servlet并且Servlet对象不存在的时候。

2.init只调用一次,Servlet创建完成之后,立即调用init。

3.service调用多次,每请求一次Servlet,就会执行一次service方法。

4.destory只调用一次,关闭tomcat服务的时候执行。

2.3 ServletConfig VS ServletContext

ServletConfig 属于某个特定的Servlet,ServletContext 是全局对象,可以表示所有的Servlet,可以用于整个Web应用,一个Web应用只有一个ServletContext,但是作为一个Web应用可以有多个ServletConfig。每创建一个Servlet就会有一个对应的ServletConfig。

一个是全局对象,一个是局部对象。

@Override
public void init(ServletConfig servletConfig) throws ServletException {
    ServletContext servletContext = servletConfig.getServletContext();
    System.out.println(servletContext.getContextPath());
    System.out.println(servletContext.getRealPath("/"));
    System.out.println(servletContext.getServerInfo());
    System.out.println("init...");
}

2.4 Servlet的体系结构

直接实现 Servlet 接口的弊端是需要实现全部的 5 个方法,但是其中的 4 个都是没有必要的。

Servlet 如何帮助开发者屏蔽掉不需要的方法?

提供了一个 GenericServlet 实现 Servlet 接口,实现 5 个方法,利用继承机制,在下一层的类就不需要重复实现了。

实际开发中不会直接使用实现 Servlet 接口的方式,有一些通用的步骤需要处理。

1、需要实现 5 个方法,但是 4 个没有用。

2、request 和 response 需要进行类型转换,父类转子类。

3、需要根据请求类型进行不同的分发处理,GET、POST。

Servlet 提供了两个类,分别完成这些通用的工作。

1、GenericServlet,实现 5 个方法。

2、HttpServlet,在 GenericServlet 的基础上完成类型转换以及请求分发。

实际开发中直接继承 HttpServlet 即可。

框架的底层依然是servlet。

postman 模拟器,模拟客户端HTTP请求,下载安装就可以了。

@webServlet("/test")
public class TestServlet etextends HttpServlet{
	@Override
	protected void doGet(HttpServletRequest req,HttpServletResponse resp){
	 resp.getWriter().write("<h1>Hello</h1>")
	}
	@Override
	protected void doPost(HttpServletRequest req,HttpServletResponse resp){
	
	}
}

资源都是加入到web-inf.

3. JSP

Java Server Page Java 服务页面

HTML CSS JavaScript

使用vue,用来Java动态生成的HTML页面

Java Web 是通过Servlet给客户端做出响应的,具体的操作就是调用response的write。

方法将要响应的内容输出给客户端。

如果响应的页面,通过response的write将所有的HTML代码一行一行的输出,工作量很大。而且很容易出错,如何解决?使用JSP。

JSP就是一个中间层的模板,允许以编写HTML代码的形式创建一个servlet。他会自动的将JSP转换为一个Servlet。自动的使用response将用户编写的HTML代码来进行输出。

index_jsp.java就是index.jsp转换之后的Servlet文件

9 个内置对象 Java 对象

  • request:HttpServletRequest 的一个对象,接收客户端请求
  • response:HttpServletResponse 的一个对象,给客户端做出响应
  • pageContext:PageContext 的一个对象,页面上下文,获取页面信息
  • session:HttpSession 的一个对象,代表浏览器和服务器的一次会话,保存用户信息
  • application:ServletContext 的一个对象,代表当前的 Web 应用,全局对象,保存所有用户的共享数据
  • config:当前 JSP 对应的 Servlet 的 ServletConfig 对象,获取当前 Servlet 信息
  • out:JspWriter 对象,向客户端输出信息的,相当于 Servlet 的输出流
  • page:当前 JSP 对应的 Servlet 对象
  • exception:表示 JSP 页面发生的异常

常用的是 request、response、session、application

request 的常用方法:

1、String getParameter(String name) //获取前端传来的参数

2、void setAttribute(String name,Object value) //通过键值对的形式保存数据

3、Object getAttribute(String name) //通过 name 获取数据

4、String[] getParameterValues(String name) //获取前端传来的多个参数

5、void setCharacterEncoding(String charset) //设置请求的编码

6、RequestDispatcher getRequestDispatcher(String path) //返回一个 RequestDispatcher 对象,该对象的 forward() 方法用来完成转发

package com.southwind.servlet;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;

@WebServlet("/test")
public class TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1、创建一个字符串对象
        //2、跳转到test.jsp并且将字符串传给jsp
        String str = "Hello World";
        req.setAttribute("str", str);
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("test.jsp");
        requestDispatcher.forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String name = req.getParameter("name");
        System.out.println(name);
    }
    
}
<%--
  Created by IntelliJ IDEA.
  User: ningn
  Date: 2021/7/15
  Time: 21:42
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>test.jsp</h1>
    <%
        String str = (String) request.getAttribute("str");
    %>
    <%=str%>
</body>
</html>

response 常用方法:

1、sendRedirect(String path) //重定向

2、resp.setContentType(“text/html;charset=UTF-8”) //设置响应编码

resp.sendRedirect("test.jsp");
String str = "张三";
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write(str);

3.1 转发 VS 重定向

转发和重定向都是完成资源跳转的,从某个资源跳转到另外一个资源

资源:Servlet、JSP(其实就是一个servlet)

区别:转发是同一个请求,重定向是两个不同的请求

转发是在服务器端将请求指定到另外一个资源,跳转是由服务器完成,客户端不需要进行处理,所以也叫服务器跳转,客户端的请求还是同一个请求,意味着地址栏不会发生改变。

重定向相当于服务器拒绝了当前的访问,让客户端发起一次新的请求来访问要跳转的资源,跳转是由客户端完成的,所以也叫客户端跳转,客户端是一次新的请求,意味着地址栏会发生改变。

如果使用 request 进行参数传递,那么必须是在转发的情况下才可以正常访问,重定向无法访问,因为转发是同一个请求,存取的是同一个对象,重定向是两个不同的请求,存取的不是同一个对象。

requestDispatcher.forward(req,resp)

一定要做这个动作。

3.2 Session

会话

服务器无法识别每一次 HTTP 请求的来源,就需要有一种技术来区分不同的客户端,这就是会话。

会话:浏览器和服务器之间发生的一系列连续的请求和响应的过程,打开浏览器进行操作到关闭浏览器的全过程。

服务器通过会话可以区分不同的浏览器/客户端。

实现会话的技术:

1、session 服务器技术、存在于服务器

2、cookie 客户端技术、存在于客户端

session 是 JSP 提供的内置对象,什么是内置对象?

JSP 预先创建好的对象,开发者可以直接使用,而不需要再次创建的对象。

session常用的方法:

方法解释
void setMaxInactiveInterval(int interval)设置session的失效时间,秒为单位
int getMaxInactiveInterval()获取session的有效时间,默认有效时间是30分钟
String getId()获取sessionid,服务器就是通过sessionID来区分不同的客户端。
void invaliddate()设置session失效
void setAttribute(String key,Object value)通过键值对的形式来储存数据
Object getAttribute(String key)通过key来取出对应的value
void removeAttribute(String key)通过key来删除对应的value
String sessionid = session.getId();
session.setMaxInactiveInterval(60);
session.invalidate();
int time = session.getMaxInactiveInteral;
session.setAttribute("str");
//跳转
request.getRrequestDispatcher("test.jsp").forward(request,response);
response.sendRedict("test.jsp");

request 作为载体传值,那么必须要确保两个页面使用的是同一个request,转发就是同一个request,重定向是两个request,所以转发可以获取到值,重定向不行。

session一次会话,只要浏览器不关闭,无论页面怎么跳转,所有的页面都是使用的是同一个session。

3.3 Cookie

Cookie是一个文本类型的文件,储存在浏览器中的,可以存在文本类型的数据。

Cookie的运行机制:Cookie是服务器在响应的时候附带传给浏览器的一个小文本文件。一旦流浏器保存了某个cookie,那么在以后的每次访问服务器的时候,就会把cookie再传回来,服务器在响应的时候,又会把cookie再传给浏览器。

Cookie就是这样不断地在服务器和浏览器之间来回传递,依次实现传输数据的作用。

javax.sevlet.http

java.lang

java.util

jdk中的api都是以Java开头的包名,都是在Java包的基础之上扩充出来的api

cookie的常用方法

方法解释
void setMaxAge(int age)设置Cookie的有效期,单位是秒
int getMaxAge()获取Cookie的有效期
void setVlaue(String value)对Cookie进行赋值。
String getName()获取cookie的name
String getVlaue()获取Cookie的value值
Cookie[] cookies = request.getCookies()
<%--
  Created by IntelliJ IDEA.
  User: ningn
  Date: 2021/7/17
  Time: 21:26
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        Cookie cookie = new Cookie("name", "tom");
        cookie.setValue("cat");
        cookie.setMaxAge(60);
        int age = cookie.getMaxAge();
        response.addCookie(cookie);
    %>
    <%=age%>
</body>
</html>
<%--
  Created by IntelliJ IDEA.
  User: ningn
  Date: 2021/7/17
  Time: 22:00
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            String name = cookie.getName();
            String value = cookie.getValue();
            out.write(name+"-"+value);
            out.write("<br/>");
        }
    %>
</body>
</html>

3.4 Cookie Session

储存用户信息

Cookie和Session的区别

1.Session是保存在服务器端,JAVA对象,cookie是保存在客户端,跟Java程序无关。

2.Session可以储存任意类型的数据Object,cookie只能存文本类型。

3.Session会随着会话的结束而销毁,cookie可以长期保存在客户端。

4.Session存储重要信息(服务器端),Cookie存储不重要的信息。

超链接和浏览器发送的都是get请求,表单是自己选择的。

用户登录登出

session

一般是使用的重定向的方式,跳转就是跳转。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/sessionlogin" method="post">
        <table>
            <tr>
                <td>用户名:</td>
                <td>
                    <input type="text" name="username"/>
                </td>
            </tr>
            <tr>
                <td>密码:</td>
                <td>
                    <input type="password" name="pwd"/>
                </td>
            </tr>
            <tr>
                <td>
                    <input type="submit" value="登录"/>
                </td>
                <td>
                    <input type="reset" value="重置"/>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
    <h1>首页</h1>
    <%
      String username = (String) session.getAttribute("username");
      //判断是否登录
      if(username == null){
        response.sendRedirect("session_login.jsp");
      }
    %>
    欢迎回来!<%=username%><a href="/sessionlogout">退出</a>
  </body>
</html>
package com.southwind.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/sessionlogin")
public class SessionLoginServlet extends HttpServlet {

    private final String USERNAME = "admin";
    private final String PWD = "123";

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取参数
        String username = req.getParameter("username");
        String pwd = req.getParameter("pwd");
        //验证
        if(username.equals(USERNAME) && pwd.equals(PWD)){
            //登录成功,存储用户信息
            //获取session
            HttpSession session = req.getSession();
            session.setAttribute("username", username);
            //跳转到首页
            resp.sendRedirect("session_index.jsp");
        }
    }
}
package com.southwind.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/sessionlogout")
public class SessionLogoutServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //销毁session
        HttpSession session = req.getSession();
        session.invalidate();
        //跳转页面
        resp.sendRedirect("session_login.jsp");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }
}

Cookie

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/cookielogin" method="post">
        <table>
            <tr>
                <td>用户名:</td>
                <td>
                    <input type="text" name="username"/>
                </td>
            </tr>
            <tr>
                <td>密码:</td>
                <td>
                    <input type="password" name="pwd"/>
                </td>
            </tr>
            <tr>
                <td>
                    <input type="submit" value="登录"/>
                </td>
                <td>
                    <input type="reset" value="重置"/>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>首页</h1>
    <%
        Cookie[] cookies = request.getCookies();
        String username = null;
        for (Cookie cookie : cookies) {
            if(cookie!=null){
                if (cookie.getName().equals("username")){
                    username = cookie.getValue();
                }
            }
        }
        if(username == null){
            response.sendRedirect("cookie_login.jsp");
        }
    %>
    欢迎回来!<%=username%><a href="/cookielogout">退出</a>
</body>
</html>
package com.southwind.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/cookielogin")
public class CookieLoginServlet extends HttpServlet {

    private final String USERNAME = "admin";
    private final String PWD = "123";

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String pwd = req.getParameter("pwd");
        if(username.equals(USERNAME) && pwd.equals(PWD)){
            Cookie cookie = new Cookie("username", username);
            //设置有效期10分钟
            cookie.setMaxAge(600);
            resp.addCookie(cookie);
            resp.sendRedirect("cookie_index.jsp");
        }
    }
}
package com.southwind.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/cookielogout")
public class CookieLogoutServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie[] cookies = req.getCookies();
        for (Cookie cookie : cookies) {
            if(cookie!=null){
                if(cookie.getName().equals("username")){
                    cookie.setMaxAge(0);
                    resp.addCookie(cookie);
                    resp.sendRedirect("cookie_login.jsp");
                    return;
                }
            }
        }
    }
}

核心的话就是把cookie的值直接给他赋予成0了,就可以去销毁这个cookie了。

3.5 过滤器

过滤器是服务端代码,用于拦截传入的请求和传出的响应,可以对请求/响应进行判断,比如是否登录,是否拥有权限等等。

验证通过之后再发送到目标资源,否则直接进行相应的处理。

package com.southwind.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter("/session_index.jsp")
public class LoginFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //判断是否登录
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpSession session = request.getSession();
        String username = (String) session.getAttribute("username");
        if(username == null){
            response.sendRedirect("session_login.jsp");
        }else{
            //放行
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

}

3.6 EL 表达式

Expression Language 表达式语言,简称 EL 表达式

可以替代 JSP 页面中数据访问时的复杂编码,简化代码

语法:${目标数据的key}

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--    <%--%>
<%--        String str = (String) request.getAttribute("str");--%>
<%--    %>--%>
<%--    <h1><%=str%></h1>--%>
    <h1>${str}</h1>
</body>
</html>
package com.southwind.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/el")
public class ELServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String str = "Hello World";
        req.setAttribute("str", str);
        req.getRequestDispatcher("el.jsp").forward(req, resp);
    }
}

4. MySQL

两类数据库:

1、关系型数据库:MySQL、Oracle、SQLServer

2、非关系型数据库 NoSQL Not Only SQL:Redis、MongoDB

数据库管理工具

是安装在电脑上的一个服务,3306

数据库管理工具提供了可视化的界面,用来管理数据库

SQLyog、Navicate、DataGrip

IDEA 集成了 DataGrip

DataGrip 连接失败常见原因:

1、MySQL 服务没有启动,手动开启/控制面板-管理工具-服务-MySQL-启动

2、缺少驱动 jar,下载即可

3、时区问题

set global time_zone='+8:00';

4.1 什么是数据库?

database 安装在计算机上的一个专门用来存储数据的仓库、也是一种服务

4.2 数据库存储引擎

存储引擎是如何存储数据,如何为数据建立索引,如何更新,查询数据等技术的具体实现方法。

MySQL提供了多种存储引擎,默认的存储引擎?InnoDB

show engines;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xfRlGYTp-1650551559123)(C:\Users\村头\AppData\Roaming\Typora\typora-user-images\image-20210731142208579.png)]

MySQL 默认使用 InnoDB 存储引擎,InnoDB 对事务的处理能力非常强大,是其他存储引擎所不能比的。

事务是数据库中最重要的一个东西。

4.3 MySQL 运算符

SQL 是一种编程语言,专门用来操作数据的

以命令行的形式完成对于数据的增删改查

CRUD

Create 增

Read 读

Update 更新

Delete 删除

4.3.1 算术运算符

执行运算符

加减乘除

select id/10 from student;

比较运算符

比大小,0表示false。1表示true

select id >= 6 from student;

逻辑运算符

与或非

只会对结果进行运算,不会对其他数据的进行运算。

select id >= && cid > 1 from student;
select id >= and cid > 1 from student;

4.3.2 特殊运算符

1、is null 判断值是否为空

​ 空值和null都不是真正的null。

select name is null from student;

2、between and 判断值是否在某个区间内,某个区间的话都是可以取到临界值

select id,id between 1 and 5 from student;
select id,id >= 1 and id <= 5 from student;

3、in 判断值是否在某个特定的集合内

select id,id in (1,2,3) from student;
select id,id = 1 or id = 2 or id = 3 from student;

4、like 模糊查询

​ 要加上百分号

select name from student where name like '%三%';

查询 name 中包含”三“的所有数据

以”三“开头

select name from student where name like '三%';

以”三“结束

select name from student where name like '%三';

name 长度为 2

一个_表示一个长度

select name from student where name like '__';

name 长度为 3 ,同时中间的字是 三

select name from student where name like '_三_';

主要还是利用模糊查询。

4.4 MySQL 函数

4.4.1 数学函数

abs() 求绝对值

select abs(score) from student;

floor() 返回小于参数的最大整数

select floor(score) from student;

ceil() 返回大于参数的最小整数

select ceil(score) from student;

4.4.2 日期函数

curdate() 获取当前日期

select curdate();

curtime() 获取当前时间

select curtime();

now() 获取当前日期+时间

select now();

4.4.3 字符串函数

insert(s1,index,len,s2)

s1 中 index 位置开始,长度为 len 的字符串替换为 s2。

index 从 1 开始

SQL语言中正常使用的就是单引号。

select insert(name,2,3,'test') from student where id = 1;

upper() 将字母转为大写

select upper(name) from student where id = 1;

lower() 将字母转为小写

select lower(name) from student where id = 1;

left(s,len) 返回 s 字符串的前 len 个字符

select left(name,3) from student where id = 1;

right(s,len) 返回 s 字符串的后 len 个字符

select right(name,3) from student where id = 1;

substring(s,index,len) 截取 s 字符串,从 index 开始,长度为 len,index 从 1 开始

select substring(name,2,3) from student where id = 1;

reverse() 反序输出

select reverse(name) from student where id = 1;

4.4.4 日期函数

通过 SQL 语句获取系统时间相关的信息

curdate() 获取当前日期

select curdate();

curtime() 获取当前时间

select curtime();

now() 获取当前日期+时间

select now();

adddate(d,n) 返回 d 日期 n 天之后的日期

select adddate('2021-6-22',100);

subdate(d,n) 返回 d 日期 n 天之前的日期

select subdate('2021-6-22',100);

datediff(d1,d2) 计算 d1 和 d2 之间相隔的天数

select datediff('2021-6-22','2018-1-1');

4.4.5 聚合函数

count() 根据某个字段统计数据库的总记录数

一般是通过id来查,MySQL中的索引是有用的,中用的是B+树

select count(id) from product_info;

sum() 计算某个字段值的总和

select sum(product_id) from product_info;

非数值字段 sum 的和是 0

avg() 计算某个字段值的平均值

select avg(product_id) from product_info;

max() 计算某个字段的最大值

select max(product_id) from product_info;

min() 计算某个字段的最小值

select min(product_id) from product_info;

4.5 MySQL 建表

1、创建数据库

create database 数据库名称
create database test1;

2、创建数据表

行和列

列就是用来描述数据表结构的

行就表示每一条不同的数据

create table 数据表名称(
	//列信息
	id int,
	name varchar(11),
	age int
)

create table user(
    id int,
    name varchar(11),
    password varchar(11),
    age int,
    score double,
    type int
);

3、对数据进行操作 增删改查 CRUD

新增

insert into 数据表(字段列表) values(值列表);
insert into user values (1,'张三','123',23,100,1);

如果添加全部的字段,则数据表之后的字段列表可以直接省略,不写就等于写全部字段。

修改

update 数据表 set 字段列表(字段名=字段值);
update user set name='张三',age=3 where id=2;

修改时需要慎重,一般要添加 where 条件,否则会把整张表的数据全部改掉,安全性较差。

删除

delete from 数据表;
delete from user where id = 1;

删除更是一个要慎之又慎的操作,一旦操作不当,就得删库跑路,一定要添加 where,否则就会清空所有的数据,后果非常严重。

实际开发中,一般不会直接使用 delete 物理删除,因为风险太大,为了稳妥起见,一般会采用逻辑删除的形式来完成删除业务。

给表中追加一个字段,用不同的值来表示是否为删除状态,deleted:0/1

0 表示未删除

1 表示删除

update user set deleted = 1 where id = 3;
update user set deleted = 0 where id = 3;

查询

select 字段列表 from 数据表 where 条件;
select * from user where id = 2;

‘*’ 表示全部字段进行查询

select * from user where deleted = 0;

4.6 MySQL 索引

数据结构、原理

MySQL 数据量很大的时候,如何来提高查询效率?

最有效直接的方式就是添加索引,索引的作用就是用来提高数据库的查询速度。

什么是索引?

索引就是帮助数据库快速查询数据的一种数据结构,索引是一种数据结构。

没有索引的情况下,select * from user where id = 11,逐行遍历,需要查找 9 次才能找目标数据,需要进行 9 次的磁盘读取,速度很慢,效率很低。

每一个字段都可以添加索引,给 id 添加索引,存储数据的同时去维护一个存储了 id 值的数据结构。

数据结构:二叉树、红黑树、B 树、B+ 树

数据结构在线画图工具:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

二叉树

id = 11,5 次找到

索引树种存储的是 key-value 结构的数据,key 就是索引的值,11,value 存储的是 id = 11 这行数据在磁盘中的地址 data,查找的顺序就是先找到索引对应的 key 值,进而获取 value,拿到了地址,读取磁盘,把数据读到内存中,展示出来。

二叉树的劣势

此时对应的二叉树如下所示。

此时的二叉树就是个链表,id = 10 需要查找 10 次,和不建立索引直接逐行查找的效率是一样的,单纯使用二叉树,肯定不行。

红黑树

可以有效避免二叉树退化成链表的情况,红黑树生成数据。

id = 10,只需要查找 5 次就可以找到。

红黑树的弊端,当数据量很大的时候,千万级别数据量,红黑树虽然可以保持平衡,但是此时树的高度会非常大。

B 树

红黑树的弊端是树的高度太大了,限制它的高度,就可以解决问题。

1、需要存储大量的数据

2、限制树的高度

纵向没有办法扩展,只能横向扩展,在同一层上存储多个节点。

B 树

B+ 树

非叶子节点不存储 data,只存储索引值,为什么?

为了存储更多的索引,降低树的结构

B+ 树就是非叶子节点只存储索引值,叶子节点存储完整的索引+data,data 就是 MySQL 数据库中对应的数据行在磁盘中的地址。

MySQL 分配给每一级的空间是 16 KB,非叶子节点单位大小是 14 byte,非叶子节点可以存储的索引个数是 16 KB / 14 byte = 1170

叶子节点因为会存储 data,所以占用空间会较大,1 KB,一层叶子节点可以存储 16 个元素

非叶子节点可以存 1170 个,叶子节点可以存 16 个

构建 3 层的 B+ 树,那么可以存储多少个索引呢?

2 层非叶子节点,1 成叶子节点

1170*1170*16 = 2190W

B+树就是一个数据结构,MySQL就是一个B+树。

4.6.1 索引的分类

普通索引、唯一性索引、全文索引、单列索引、多列索引、空间索引

虽然索引可以加快查询的速度,但是创建和维护索引需要消耗物理空间,所以不能创建太多的索引,否则反而会降低数据库的检索速度。

任何事情都要有一个度。

唯一性索引是指索引值是唯一的,比如主键索引。

全文索引:只能创建在 char、varchar、text 数据类型的字段上,查询数据量较大的字符串类型的字段,使用全文索引可以提升效率。

InnoDB 不支持全文索引。

单列索引:把索引添加到一个字段上

多列索引:把索引添加到多个字段上

空间索引:只能建立在空间数据类型上,(GIS,地理信息系统)

InnoDB 不支持空间索引

索引的设计原则:

1、出现在 where 语句后面的字段,添加索引

2、索引的值,要尽量唯一,效率更高

3、不要添加太多索引,维护成本很高

SQL

alter table user add index id_index(id);

电脑中安装了 MySQL 服务 — 数据库 — 数据表 — 数据

SQL 分为四类

1、DML(数据操作语言)操作数据库中的数据(insert、update、delete)

2、DDL(数据定义语言)创建、 删除、修改数据库、数据表

3、DQL(数据查询语言)对数据库中的数据进行查询(select)

4、DCL(数据控制语言)用来提交数据库事务(commit、rollback)

学习数据库,需要从两方面入手

1、掌握数据库的使用(CRUD),在建立好数据库/数据表的基础上,对数据进行操作,程序员日常最多的工作。

2、设计数据库,根据项目的需求,设计数据表和数据表之间的关系,建立连接。

数据表由两部分组成:

1、表结构:表的设计 //列信息

2、表数据:表中保存的数据 //行信息

4.7 创建数据库

create database name;
create database mytest1 default character set utf8 collate utf8_general_ci;
create database mytest2 default character set utf8 collate utf8_bin;

order by name

校验字符集?查询的时候对字符数据进行排序

mytest1:utf8_general_ci a B

mytest2:utf8_bin B a

utf8_general_ci:不区分大小写,B 排在 a 后面,正常也是通过时间来进行排序的。

utf8_bin:按照字符的 asc 码的大小进行排序 a 排在 B 后面

B 66

a 97

4.8 删除数据

drop database name;

4.9 创建表

create table name(
	//字段信息
    字段名 数据类型 主键/外键 默认值 是否为null
);

MySQL 数据类型

1、整数类型:tinyint(1个byte)、smallint(2个byte)、mediumint(3个byte)int(4个byte)、bigint(8个byte)主要就是用int。

2、浮点型/定点型

浮点型:float(4个byte)、double(8个byte)

定点型:decimal(14个byte)decimal(M,D) BigDecimal

M 数字的最大长度

D 小数点后的长度

3、日期和时间类型

year(1个byte) 表示年

time(3个byte) 表示时间

date(3个byte) 表示日期

datetime(8个byte) 日期+时间

timestamp(4个byte) 时间戳 1970年1月1号 00:00:00 到现在的毫秒数,不会有重复的。

4、字符串类型

char(2个byte)

varchar(4个byte)

text(8个byte)

5、二进制类型

bit(2个byte)

binary(4个byte)

tinyblob(255个byte)

mediumblob(2^24-1个byte)

longblob(2^32-1个byte)

create table sutdent
(
   id int default 100 auto_increment comment '编号'
);

create unique index sutdent_id_uindex
   on sutdent (id);

alter table sutdent
   add constraint sutdent_pk
      primary key (id);

自增和默认值不可以同时存在。

设置默认值 100

自动生成,每一行记录的值都是 100,

同时设置自增,每一行记录的值都是递增的

主键自增。

unique 设置该字段的值不能有重复的,每个值都必须是唯一的。

create table student
(
   id int primary key auto_increment comment '编号',
   name varchar(11) not null comment '姓名',
   age int default 22 comment '年龄'
);

4.10 删除表

drop table name;

4.11 查看表结构

desc name;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tijtlsTZ-1650551559124)(C:\Users\村头\AppData\Roaming\Typora\typora-user-images\image-20210801195443061.png)]

4.12 修改表

修改表中的字段

添加字段

alter table student add title varchar(11);

删除字段

alter table student drop title;

修改字段

alter table student change age title varchar(11);

4.13 主键

表中的一个字段,该字段的值是每一行数据的唯一标识。

一张表只能有一个主键。

主键是添加到字段上的,并不是独立存在的。

主键生成策略:采用代理主键,与业务无关,仅仅是用来标识一行数据。

一般定义为 int 类型,因为 int 类型存储空间小,同时可以设置自增,设置自增就可以保证数据的唯一性。

主键的值不能为 null。

主键必须是唯一的,主键自带索引,提高查询效率。

如何设置主键

create table test1(
	id int primary key
);

create table test2(
	id int
);

alter table test2
   add constraint test2_pk
      primary key (id);

删除主键

alter table test1 drop primary key;
create table test1(
	id int primary key auto_incremen);

4.14 外键

外键:将表中的某一个字段设置为外键,需要跟另外一张表的主键进行关联,从而构建不同数据表之间的某种关系。

外键需要和主键结合起来使用,A 表的外键需要和 B 表的主键结合起来使用,不能一张表的外键和自己的主键结合使用。

外键一定是两张表的关系。

数据表一共有三种关系:

1、一对一:A 表的一条记录对应 B 表的一条记录,B 表的一条记录对应 A 表的一条记录

2、一对多:A 表的一条记录对应 B 表的多条记录,B 表的一条记录对应 A 表的一条记录

3、多对多:A 表的一条记录对应 B 表的多条记录,B 表的一条记录对应 A 表的多条记录

一对一:人和身份证号,一个人只能有一个身份号,一个身份证号只能对应一个人

一对多:班级和学生,一个班级对应多个学生,一个学生只能对应一个班级

多对多:选课和学生,一门课程可以被多个学生选择,一个学生也可以选择多门课程

用户和订单 是什么关系?一对多

商品和订单/用户 是什么关系?多对多

实际开发中,使用更多的是 一对多和多对多关系,一对一一般不用

person:id name age

cardid:value

一对一的关系一般可以直接合成一张表。

4.15 一对多

1、创建两张数据表

2、通过某种设置构建两张表的一对多关系

逻辑:主从关系,一张主表、一张从表

一的一方是主表,多的一方是从表

班级是一,班级是主表

学生是多,学生是从表

关联两个表的关联字段要存储在多的一方(从表)

关联字段一般设置为外键,外键需要被主表中的主键所约束

外键可以取的值必须是主表中存在的值

实际开发中设计数据库的时候一般不建议使用外键,因为添加外键之后,会消耗额外的资源,必然会导致数据库性能降低。

从表是被别人约束的表。被表格约束的表格。

初学者可以添加外键,因为一旦建立外键关系,数据库层面就会自动进行校验,外键的值是否正确。

create table class(
    id int primary key auto_increment,
    name varchar(11)
);

create table student(
    id int primary key auto_increment,
    name varchar(11),
    cid int
);

alter table student add foreign key(cid) references class(id);

因为维护主外键约束,需要耗费大量的资源,导致数据库速度变慢,所以一般为了提升速度,不推荐使用主外键约束,唯一一对多关系的任务完全交给业务逻辑,就对我们写代码提出了更高的要求。

删除外键

alter table student drop foreign key student_ibfk_1;

没有外键的话或者没有逻辑处理,出现了一堆脏数据。

4.16 多对多

多对多的关系,需要借助于一张中间表建立两张目标表的关系

中间表就是从表,添加两个外键

两张目标都是主表,同时约束中间表

create table course(
    id int primary key auto_increment,
    name varchar(11)
);

create table user(
    id int primary key auto_increment,
    name varchar(11)
);

create table course_user(
    id int primary key auto_increment,
    uid int,
    cid int
);

alter table course_user add foreign key(uid) references user(id);
alter table course_user add foreign key(cid) references course(id);

MySQL 中的多对多关系其实就是由两个一对多关系来组成的。

4.17 多表关联查询

  • 嵌套查询

将两个 SQL 语句进行嵌套查询

查询张三所在的班级

select * from class where id = (select cid from student where name='张三');
  • 连接查询

    • 内连接

    查询的时候将两张表进行关联

    查询张三的信息(包括班级信息)

    笛卡尔积

    笛卡尔积把数据中所有的情况都给他联系起来。就是进行1*3所有情况

    select * from student inner join class where student.name='张三' and student.cid = class.id
    

    进行简化

    select * from student s,class c where s.name='张三' and c.id = s.cid
    
    • 外连接
      • 左连接
      • 右连接

左表是指写到左边的表(写到前边的表)

右表是指写到右边的表(写到后边的表)

左连接:左表所有数据和右表满足条件的数据

左表:张三 李四 王五

右表:2班 3班

左表&右表

select * from student s left join class c on s.cid = c.id;

右连接:右表所有数据和左表满足条件的数据

右表:1班 2班 3班

左表:张三 李四

select * from student s right join class c on s.cid = c.id;

4.18 关联查询

, 就是inner join的简写。

4.18.1 一对多

select s.id sid,s.name sname,c.id cid,c.name cname from student s,class c where s.cid = c.id and s.id = 1;
select s.id sid,s.name sname,c.id cid,c.name cname from student s,class c
where s.cid = c.id and c.id = 1;

4.18.2 多对多

select u.id uid,u.name uname,c.id cid,c.name cname from user u,course c,course_user cu where
u.id = cu.uid and c.id = cu.cid and u.id = 7;
select u.id uid,u.name uname,c.id cid,c.name cname from user u,course c,course_user cu where
u.id = cu.uid and c.id = cu.cid and c.id = 1;

去重:去掉重复的数据。使用一个distinct。

select distinct u.id uid,u.name uname,c.id cid,c.name cname from user u,course c,course_user cu where
u.id = cu.uid and c.id = cu.cid and u.id = 8;

所查询的结果集中,字段值的重复率是 100%,MySQL 才会认为是重复字段,distinct 才会生效。

分页:数据量很大的时候,分页展示数据。减少的只是一个后台交互的东西。

limit index(下标),length(长度)

index 起始下标

length 截取的长度

从多少开始,然后截取多少个。

select * from course limit 10,5;

length = 5;

page = ?

page 1 2 3

index 0 5 10

index = (page-1)*length

4.19 视图 View

视图就是一张虚拟的表,专门用来做查询,自定义要展示的数据

创建视图

create view view_common as select * from user;

使用视图

select * from view_common;

删除视图

drop view view_common;

4.20 触发器 Trigger

类似于一个监听器。

触发器定义了一系列操作,可以在对指定表进行插入、更新或者删除操作的同时自动执行这些操作。

触发器在数据库中所定义的一个方法。

触发器的优点:

1、开发更快,因为触发器是存储在数据库中的,不需要再应用程序中进行调用

2、更容易维护,定义触发器之后,访问目标表时,会自动进行调用

3、业务全局实现,如果修改业务,只需要修改触发器即可,不需要修改任何的业务代码

创建触发器

create trigger t_afterinsert_on_tab1
    after insert on tab1
    for each row
    begin
        insert into tab2(tab2_id) values(new.tab1_id);
    end;
create trigger t_afterdelete_on_tab1
    after delete on tab1
    for each row
    begin
        delete from tab2 where tab2_id = old.tab1_id;
    end;

删除

drop trigger t_afterinsert_on_tab1;

4.21 存储过程 Procedure

存储过程是一组为了完成特定功能的 SQL 语句的集合,存储在数据库中的,用户可以直接进行调用,类似于方法的调用。

一次编写,多次使用,避免开发人员重复编写相同的 SQL。

创建存储过程

参数:

1、输入输出类型:入参、出参

入参是指传到存储过程中的参数,类似于 Java 中的参数

出参是指存储过程返回的数据,类似于 Java 中的返回值

2、参数名称

3、参数类型

create procedure add_name(in target int)
begin
    declare name varchar(20);
    if target = 1 then
       set name = 'MySQL';
       else
        set name = 'Java';
    end if;
    insert into user(name) values (name);
end;

调用存储过程

call add_name(2);

删除存储过程

drop procedure add_name;

出参

create procedure count_of_course(out num int)
begin
    select count(*) into num from course;
end;
call count_of_course(@num);
select @num;
create procedure test(in num int,out val int)
begin
    if num = 1 then
        select id into val from user;
        else
        select money into val from user;
    end if;
end;
call test(2,@val);

select @val;

if

create procedure example_if(in x int)
begin
    if x = 1 then
        select id from student;
        elseif x = 2 then
        select name from student;
    end if;
end;
call example_if(2);

case-when

create procedure example_case(in x int)
begin
    case x
        when 1 then select id from student;
        when 2 then select name from student;
        else select cid from student;
        end case;
end;
call example_case(6)

while

create procedure example_while(out sum int)
begin
    declare i int default 1;
    declare s int default 0;
    while i<=100 do
        set s = s+i;
        set i = i+1;
        end while;
    set sum = s;
end;
call example_while(@sum);
select @sum;

4.22 JDBC

java DataBase Connectivity 是一个独立于特定数据库的管理系统,通用的SQL数据库存储和操作的公共接口

独立于特定的数据库

公共接口

JDBC 就是一套由 Java 提供的可以作用大部分数据库的接口

定义了一组标准,为访问不同数据库提供了统一途径

4.22.1 JDBC 体系结构

JDBC接口包括两个层面:

1.面向应用的API,供程序员调用

2.面向数据库的API,供数据库开发厂商调用的驱动程序

1.JDBC API Java 官方提供,供程序员调用的接口方法

在 java.sql、javax.sql 包中

  • Connection
  • Statement
  • ResultSet

2.DriverManager Java 官方提供,管理各种不同的 JDBC

3.JDBC 驱动,数据库厂商提供,负责连接不同的数据库

4.22.2 使用流程

1、加载数据库驱动

2、获取 Connection,表示一次连接

3、创建 Statement,由 Connection 产生,执行 SQL 语句

4、ResultSet 保存 Statement 执行查询后所产生的结果(增、删、改不需要)

增删改

 //加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //获取连接
        // url user password
        String url = "jdbc:mysql://localhost:3306/test1?serverTimezone=UTC";
        String user = "root";
        String password = "123456";
        Connection connection = DriverManager.getConnection(url,user,password);
        String sql = "insert into student(name,age) values('JDBC',1)";
        // 增删改 都是使用的executeUpdate
        // 查询用的executeQuery
        Statement statement = connection.createStatement();
        int i = statement.executeUpdate(sql);
        System.out.println(i);

查询

package com.southwind.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class Test {
    public static void main(String[] args) throws Exception {
        //获取连接
        //url user password
        String url = "jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8";
        String user = "root";
        String password = "123456";
        Connection connection = DriverManager.getConnection(url, user, password);
        //SQL
//        String sql = "insert into student(name,cid) values('JDBC1',1),('JDBC2',1),();";
//        String sql = "update student set name = 'MySQL' where id = 4";
//        String sql = "delete from student where cid = 2";
        String sql = "select * from user";
        Statement statement = connection.createStatement();
        //增 删 改 都用 executeUpdate
        //查询用 executeQuery
        ResultSet resultSet = statement.executeQuery(sql);
        while (resultSet.next()){
            int id = resultSet.getInt(1);
            String name = resultSet.getString(2);
            int money = resultSet.getInt(3);
            System.out.println(id + "-" + name + "-" + money);
        }
//        int i = statement.executeUpdate(sql);
//        System.out.println(i);
    }
}

execute 方法返回值是 boolean 类型,不是表示 SQL 是否执行成功,而是表示

SQL 执行的结果类型,如果是 ResultSet,则返回 true,否则返回 false。

实际开发中,并不会直接使用 Statement,而是会使用它的子类 PreparedStatement

1、提供占位符的功能,避免拼接字符串

2、防止 SQL 注入,安全性更高

package com.southwind.test;

import java.sql.*;

public class Test {
    public static void main(String[] args) throws Exception {
        test("Test", 2);
    }

    public static void test(String name,int cid) throws Exception{
        //获取连接
        //url user password
        String url = "jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8";
        String user = "root";
        String password = "123456";
        Connection connection = DriverManager.getConnection(url, user, password);
        //SQL
        String sql = "insert into student(name,cid) values("+name+","+cid+")";
        sql = "insert into student(name,cid) values(?,?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1, name);
        preparedStatement.setInt(2, cid);
        int i = preparedStatement.executeUpdate();
        System.out.println(i);
//        String sql = "update student set name = 'MySQL' where id = 4";
//        String sql = "delete from student where cid = 2";
//        String sql = "select * from user";
//        Statement statement = connection.createStatement();
        //增 删 改 都用 executeUpdate int
        //查询用 executeQuery ResultSet
//        boolean execute = statement.execute(sql);
//        System.out.println(execute);
        //boolean 表示statement返回值是否为 ResultSet 类型
//        ResultSet resultSet = statement.executeQuery(sql);
//        while (resultSet.next()){
//            int id = resultSet.getInt(1);
//            String name = resultSet.getString(2);
//            int money = resultSet.getInt(3);
//            System.out.println(id + "-" + name + "-" + money);
//        }
//        int i = statement.executeUpdate(sql);
//        System.out.println(i);
    }
}

SQL 注入:利用某些系统没有对用户输入的信息进行充分检查,从而在用户输入的信息中注入 SQL 语句,利用系统的 SQL 引擎完成恶意行为的操作

select * from student where name = 'aaa' or '1=1' and password = '111' or '1=1';

先进性拼凑

如何去规避风险。

使用prepared

开发中,并不会直接使用 Statement,而是会使用它的子类 PreparedStatement

1、提供占位符的功能,避免拼接字符串

2、防止 SQL 注入,安全性更高

package com.southwind.test;

import java.sql.*;

public class Test {
    public static void main(String[] args) throws Exception {
        test("Test", 2);
    }

    public static void test(String name,int cid) throws Exception{
        //获取连接
        //url user password
        String url = "jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8";
        String user = "root";
        String password = "123456";
        Connection connection = DriverManager.getConnection(url, user, password);
        //SQL
        String sql = "insert into student(name,cid) values("+name+","+cid+")";
        sql = "insert into student(name,cid) values(?,?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1, name);
        preparedStatement.setInt(2, cid);
        int i = preparedStatement.executeUpdate();
        System.out.println(i);
//        String sql = "update student set name = 'MySQL' where id = 4";
//        String sql = "delete from student where cid = 2";
//        String sql = "select * from user";
//        Statement statement = connection.createStatement();
        //增 删 改 都用 executeUpdate int
        //查询用 executeQuery ResultSet
//        boolean execute = statement.execute(sql);
//        System.out.println(execute);
        //boolean 表示statement返回值是否为 ResultSet 类型
//        ResultSet resultSet = statement.executeQuery(sql);
//        while (resultSet.next()){
//            int id = resultSet.getInt(1);
//            String name = resultSet.getString(2);
//            int money = resultSet.getInt(3);
//            System.out.println(id + "-" + name + "-" + money);
//        }
//        int i = statement.executeUpdate(sql);
//        System.out.println(i);
    }
}

SQL 注入:利用某些系统没有对用户输入的信息进行充分检查,从而在用户输入的信息中注入 SQL 语句,利用系统的 SQL 引擎完成恶意行为的操作

select * from student where name = 'aaa' or '1=1' and password = '111' or '1=1';

先进性拼凑

如何去规避风险。

使用prepared

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值