Servlet方法详解

Servlet:

Servlet是SUN公司提供的一套规范,名称就叫Servlet规范,它也是JavaEE规范之一。使用JavaEE的API。目前在Oracle官网中的最新版本是JavaEE8,

  • Servlet是一个运行在web服务端的java小程序
  • 它可以用于接收和响应客户端的请求
  • 要想实现Servlet功能,可以实现Servlet接口,继承GenericServlet或者HttpServlet
  • 每次请求都会执行service方法
  • Servlet还支持配置
Servlet执行过程:
  1. 客户端浏览器发起请求
  2. Tomcat服务器解析URL
  3. 通过URL找到对应的应用
  4. 通过应用找到web.xml
  5. 解析请求资源地址URL
  6. 找到应用的资源
  7. 执行service方法,响应给客户端浏览器
Servlet关系视图:

在这里插入图片描述

Servlet实现方式:

1、 实现Servlet接口,接口中的方法必须全部实现。

表示接口中的所有方法在需求方面都有重写的必要。这种方式支持最大程度的自定义。

2、继承GenericServlet,service方法必须重写,其他方可根据需求,选择性重写。

表示只在接收和响应客户端请求这方面有重写的需求,而其他方法可根据实际需求选择性重写,使开发Servlet变得简单。但是,此种方式是和HTTP协议无关的。

3、继承HttpServlet,它是javax.servlet.http包下的一个抽象类,是GenericServlet的子类。如果选择继承HttpServlet时,只需要重写doGet和doPost方法,不要覆盖service方法。

表示我们的请求和响应需要和HTTP协议相关。也就是说通过HTTP协议来访问的。那么每次请求和响应都符合HTTP协议的规范。请求的方式就是HTTP协议所支持的方式

实现Servlet:
public class ServletDemo03 implements Servlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("实现Servlet方式");}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {}
}
继承GenericServlet:
public class ServletDemo01 extends GenericServlet {@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("service方法执行了...");}
}
继承HttpServlet::
public class ServletDemo extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("Servlet执行了");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--Servlet配置--><servlet><servlet-name>servletDemo</servlet-name><servlet-class>com.example.demo.ServletDemo</servlet-class></servlet><!--映射配置--><servlet-mapping><servlet-name>servletDemo</servlet-name><url-pattern>/servletDemo</url-pattern></servlet-mapping><!--生命周期配置--><servlet><servlet-name>servletDemo02</servlet-name><servlet-class>com.example.demo.ServletDemo02</servlet-class></servlet><servlet-mapping><servlet-name>servletDemo02</servlet-name><url-pattern>/servletDemo02</url-pattern></servlet-mapping></web-app>
Servlet生命周期:
  • 对象的生命周期,就是对象从生到死的过程,
  • 出生:请求第一次到达Servlet时,对象就创建出来,并且初始化成功。只出生一次,就放到内存中。
  • 活着:服务器提供服务的整个过程中,该对象一直存在,每次都是执行service方法。
  • 死亡:当服务停止时,或者服务器宕机时,对象消亡。
  • Servlet对象只会创建一次,销毁一次。所以,Servlet对象只有一个实例。如果一个对象实例在应用中是唯一的存在,用了单例模式。

演示:

public class ServletDemo02 extends HttpServlet {// 对象出生@Overridepublic void init() throws ServletException {System.out.println("出生了");}// 对象服务@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("收到客户端请求");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}// 对象死亡@Overridepublic void destroy() {System.out.println("挂了");}
}
线程安全:

在Servlet中定义了类成员之后,多个浏览器都会共享类成员的数据。其实每一个浏览器端发送请求,就代表是一个线程,那么多个浏览器就是多个线程,多个线程会共享Servlet类成员中的数据,其中任何一个线程修改了数据,都会影响其他线程。因此,所以Servlet它不是线程安全的。分析产生这个问题的根本原因,其实就是因为Servlet是单例,单例对象的类成员只会随类实例化时初始化一次,之后的操作都是改变,而不会重新初始化。

解决:

在Servlet中定义类成员要慎重。如果类成员是共用的,并且只会在初始化时赋值,其余时间都是获取的话,那么是没问题。如果类成员并非共用,或者每次使用都有可能对其赋值,那么就要考虑线程安全问题了,把它定义到doGet或者doPost方法里面去就可以了。或者是直接加synchronized

演示:

public class ServletDemo03 extends HttpServlet {private String username;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {synchronized (this) {// 在这里声明的话,就是把成员变量变成局部变量,谷歌进来是一个username,火狐进来又是另一个就不会出现出数据不安全了// String username = null;// String getParameter(String name):根据参数名称获取参数值username = req.getParameter("username");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// resp.getWriter  传数据给前端PrintWriter writer = resp.getWriter();writer.println("username:" + username);writer.close();}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req,resp);}
}
Servlet映射三种方式:
  1. 指名道姓,给具体的名称,访问路径必须和配置的一样
  2. /开头+通配符的方式,只要符合目录结构,无视结尾
  3. 通配符+固定格式结尾方式,只要符合固定结尾,无视前面路径

说明:映射优先级:越具体优先级越高,1>2>3

演示:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--&lt;!&ndash;ServletHttp配置&ndash;&gt;<servlet><servlet-name>servletDemo</servlet-name><servlet-class>com.example.demo.ServletDemo</servlet-class></servlet><servlet-mapping><servlet-name>servletDemo</servlet-name><url-pattern>/servletDemo</url-pattern></servlet-mapping>--><!--    &lt;!&ndash;/开头+通配符的方式&ndash;&gt;<servlet><servlet-name>servletDemo</servlet-name><servlet-class>com.example.demo.ServletDemo</servlet-class></servlet><servlet-mapping><servlet-name>servletDemo</servlet-name><url-pattern>/servlet/*</url-pattern></servlet-mapping>--><!--通配符+固定格式结尾  结尾写什么就写什么,开心就好--><servlet><servlet-name>servletDemo</servlet-name><servlet-class>com.example.demo.ServletDemo</servlet-class></servlet><servlet-mapping><servlet-name>servletDemo</servlet-name><url-pattern>*.itzhuzhu</url-pattern></servlet-mapping>
</web-app>

实现类:

public class ServletDemo extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 定义一个商品金额int money = 1000;// 获取访问路径String uri = req.getRequestURI();// public int lastIndexOf(int ch): 返回指定字符在此字符串中最后一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。uri = uri.substring(uri.lastIndexOf("/"));// 条件判断if ("/vip".equals(uri)) {System.out.println("原价:" + money + "尊敬的Vip您的折后价是:" + money * 0.8);} else if ("/svip".equals(uri)) {System.out.println("原价:" + money + "尊敬的Sip您的折后价是:" + money * 0.1);} else {System.out.println("会员都不开还想打折?打骨折");}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
Servlet创建时机:

第一种:服务器加载时创建

优势:
在服务器启动时,就把需要的对象都创建完成了,从而在使用的时候减少了创建对象的时间,提高了首次执行的效率。
弊端:
因为在应用加载时就创建了Servlet对象,因此,导致内存中充斥着大量用不上的Servlet对象,造成了内存的浪费。

第二种:第一次访问时创建

优势:
就是减少了对服务器内存的浪费,因为那些一直没有被访问过的Servlet对象都没有创建,因此也提高了服务器的启动时间。
弊端:
如果有一些要在应用加载时就做的初始化操作,它都没法完成,从而要考虑其他技术实现。
修改创建时机:在标签中添加标签

标签里的数字越小优先级越高,正整数代表服务器加载时创建,负数不写代表第一次访问的时候创建

    <servlet><servlet-name>servletDemo</servlet-name><servlet-class>com.example.demo.ServletDemo</servlet-class><!--数字越小越高,负数或者不写就是第一次访问的时候创建--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>servletDemo</servlet-name><url-pattern>/servletDemo</url-pattern></servlet-mapping>
默认Servlet:

默认Servlet是由服务器提供的一个Servlet,它配置在Tomcat的conf目录下web.xml中。它的映射路径是<url-pattern>/<url-pattern>,在发送请求时,首先会在应用中的web.xml中查找映射配置,找到就执行。找不到对应的Servlet路径时,就去找默认的Servlet,由默认Servlet处理。

ServletConfig:

ServletConfig是Servlet的配置参数对象,在Servlet规范中,允许为每个Servlet都提供一些初始化配置。所以,每个Servlet都一个自己的ServletConfig。它的作用是在Servlet初始化期间,把一些配置信息传递给Servlet。比如servlet是个孩子,ServletConfig就是保姆

生命周期:

由于它是在初始化阶段读取了web.xml中为Servlet准备的初始化配置,并把配置信息传递给Servlet,所以生命周期与Servlet相同。需要注意的是,如果Servlet配置了1,那么ServletConfig也会在应用加载时创建。

配置ServletConfig:

<servlet>标签中,通过<init-param>标签配置,有两个子标签
<param-name>:代表初始化参数的key
<param-value>:代表初始化参数的value

ServletConfig方法:
返回值方法名说明
StringgetInitParameter(String name)根据参数名称获取参数的值
EnumerationgetInitParameterNames()获取所有参数名称的枚举
StringgetServletName获取Servlet的名称
SerlvetContextgetServletContext获取ServletContext对象
演示:

配置信息:

    <servlet><servlet-name>servletDemo05</servlet-name><servlet-class>com.example.demo.ServletDemo05</servlet-class><!--配置ServletConfig,是以键值对的形式存在的--><init-param><param-name>itz</param-name><param-value>itzhuzhu</param-value></init-param></servlet><servlet-mapping><servlet-name>servletDemo05</servlet-name><url-pattern>/servletDemo05</url-pattern></servlet-mapping>

实现类:

public class servletDemo04 extends HttpServlet {// 声明ServletConfigprivate ServletConfig config;// 因为ServletConfig是在初始化期间传递信息,所以要在init方法里去获取@Overridepublic void init(ServletConfig config) throws ServletException {// 通过init方法,对ServletConfig对象赋值this.config = config;}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// getInitParameter(String name):根据key获取valueString encodingValue = config.getInitParameter("encoding");System.out.println(encodingValue);// getInitParameterNames():获取所有keyEnumeration<String> keys = config.getInitParameterNames();while (keys.hasMoreElements()) {// 获取每一个keyString key = keys.nextElement();// 根据key获取valueString value = config.getInitParameter(key);System.out.println(key + " : " + value);}// getServletName	获取Servlet的名称String servletName = config.getServletName();System.out.println(servletName);// getServletContext	获取ServletContext对象ServletContext servletContext = config.getServletContext();System.out.println(servletContext);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

ServletContext:

ServletContext对象,它是应用上下文对象。每一个应用有且只有一个ServletContext对象。

作用:

它可以配置和获取应用的全局初始化参数,实现所有Servlet之间的数据共享。

生命周期:
  • 出生: 应用一加载,该对象就被创建出来了。一个应用只有一个实例对象。(Servlet和ServletContext都-是单例的)
  • 活着:只要应用一直提供服务,对象就一直存在。
  • 死亡:应用被卸载(或者服务器挂了),对象死亡。
域对象概念:
  • 域对象:指的是对象有作用域(作用范围)
  • 域对象的作用:域对象可以实现数据共享。
  • 不同作用范围的域对象,共享数据的能力不一样。在Servlet规范中,一共有4个域对象。ServletContext就是其中一个。也是web应用中最大的作用域,叫application域。每个应用只有一个application域(应用域),它可以实现整个应用间的数据共享功能。
ServletContext配置:

ServletContext被称之为应用上下文对象,所以它的配置是针对整个应用的配置,而非某个特定Servlet的配置。它的配置被称为应用的初始化参数配置。

配置的方式,需要在标签中使用来配置初始化参数

<param-name>:全局初始化参数的key
<param-value>:全局初始化参数的value

常用方法:
返回值方法名说明
StringgetInitParameter(String name)根据名称获取全局配置的参数
StringgetContextPath()获取当前应用访问的虚拟目录
StringgetRealPath根据虚拟目录获取应用部署的磁盘绝对路径
应用域常用方法:
返回值方法名说明
voidsetAttribute(String name,Object value)向应用域对象中存储数据
ObjectgetAttribute(String name)通过名称获取应用域对象中的数组
voidremoveAttribute(String name)通过名称移除应用域对象中的数据

配置文件:

<!--因为servletContext它不属于某一个servlet,它是配置全局的,所以不能写在servlet里--><context-param><param-name>desc</param-name><param-value>This is Ser vletContextDemo</param-value></context-param><servlet><servlet-name>servletContextDemo</servlet-name><servlet-class>com.example.demo.ServletContextDemo</servlet-class></servlet><servlet-mapping><servlet-name>servletContextDemo</servlet-name><url-pattern>/servletContextDemo</url-pattern></servlet-mapping>

实现类:

public class ServletContextDemo extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取ServletContext对象 , GenericServlet底层已经实现了getInitParameter所以可以直接调用  ServletConfig sc = this.getServletConfig();ServletContext context = getServletContext();//获取全局配置参数的descString value = context.getInitParameter("desc");System.out.println(value);//获取应用的访问虚拟目录String contextPath = context.getContextPath();System.out.println(contextPath);//根据虚拟目录获取应用部署的磁盘绝对路径String realPath = context.getRealPath("/");System.out.println(realPath);// 在src、wabapp、webinf创建三个文件获取路径//获取a.txt文件的绝对路径String a = context.getRealPath("/WEB-INF/classes/a.txt");System.out.println(a);//获取b.txt文件的绝对路径String b = context.getRealPath("/b.txt");System.out.println(b);String c = context.getRealPath("/WEB-INF/c.txt");System.out.println(c);//向域对象中存储数据context.setAttribute("username", "itzhuzhu");//移除域对象中username的数据,删除了再访问就变成null了context.removeAttribute("username");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

获取共享数据:

public class ServletDemo05 extends HttpServlet {// 声明ServletConfigprivate ServletConfig config;// 因为ServletConfig是在初始化期间传递信息,所以要在init方法里去获取@Overridepublic void init(ServletConfig config) throws ServletException {// 通过init方法,对ServletConfig对象赋值this.config = config;}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// getServletContext	获取ServletContext对象ServletContext servletContext = config.getServletContext();System.out.println(servletContext);// getAttribute(String name)	通过名称获取应用域对象中的数组Object username = servletContext.getAttribute("username");System.out.println(username);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

Request方法详解:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/572250.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

继承的实现原理

一.继承的实现原理 1.继承顺序 1.1单独分叉线路&#xff1a;经典类与新式类依次从左到右&#xff0c;深度优先 1.2多条重合线路&#xff1a;经典类一路到头&#xff0c;深度优先&#xff1b;新式类&#xff0c;广度优先。<参考MRO列表&#xff0c;仅在新式类有> class A(…

Python自动化之列表

##将首字母改成大写# name alex# v name.capitalize()# print(v)##将首字母改成小写# name Alex# v name.casefold()# print(v)###传一个值&#xff0c;两边补的是添加的字符# name Alex# v name.center(20,*)# print(v)##统计字符串出现的次数# name Alex# v name.cou…

Request请求

Request请求&#xff1a; Request请求&#xff0c;就是客户端希望从服务器端获取资源&#xff0c;向服务器发出询问。在B/S架构中&#xff0c;就是客户浏览器向服务器发出询问。在我们的JavaEE工程中&#xff0c;客户浏览器发出询问&#xff0c;要遵循HTTP协议所规定的。请求对…

MySQL编程基础

本文是关于MySQL编程中的一些基础知识&#xff0c;包括变量和运算符、常用语句、函数。 一、变量与运算符 1.用户会话变量声明&#xff1a;SET 变量名 表达式;//即&#xff1a;用户会话变量无需提前定义&#xff0c;直接用赋值语句赋值&#xff0c;就算是定义了&#xff08;也…

Response响应方法详解

Response&#xff1a; 响应&#xff1a;服务器把请求的处理结果告知客户端。在B/S架构中&#xff0c;响应就是把结果带回浏览器。响应对象&#xff1a;在项目中用于发送响应的对象 常用状态码&#xff1a; 状态码说明200执行成功302它和307一样&#xff0c;都是用于重定向的状…

perl6 HTTP::UserAgent (2)

http://www.cnblogs.com/perl6/p/6911166.html 之前这里有个小小例子&#xff0c; 这里只要是总结一下。 HTTP::UserAgent包含了以下模块: ---------------------------------------------------------------------------------------------- Module |Path-Nam…

Java会话技术

会话技术&#xff1a; 会话指的是客户端浏览器和服务端之间的度偶次请求和响应当打开浏览器&#xff0c;访问网站地址后&#xff0c;会话开始&#xff0c;当关闭浏览器&#xff08;或者到了过期时间&#xff09;&#xff0c;会话结束。就像打电话只要不挂电话就是一次会话。 会…

【调用IP宏文件进行仿真】modelsim仿真时出现 Instantiation of 'xxx' failed. The design unit was not found....

出现错误类似&#xff1a;modelsim 仿真fifo时出现 Error: (vsim-3033) E:/Programs/ModelSim/fifo/ps2_fifo.v(75): Instantiation of scfifo failed. The design unit was not found.仿真波形不对&#xff0c;调用的ip核没有输出&#xff08;白色虚线&#xff09;等情况&…

Java Server Page

JSP JSP全称是Java Server Page&#xff0c;基于Java和Servlet一样是sun公司推出的一套开发动态web资源的技术&#xff0c;称为JSP/Servlet规范。JSP的本质其实就是一个Servlet。jsp是一种动态网页技术标准&#xff0c;jsp部署在服务器上可以处理客户端的请求&#xff0c;并根据…

HDFS概述(2)————Block块大小设置

参考&#xff1a;HDFS概述&#xff08;4&#xff09;————HDFS权限HDFS概述&#xff08;3&#xff09;————HDFS FederationHDFS概述&#xff08;2&#xff09;————Block块大小设置HDFS概述&#xff08;1&#xff09;————HDFS架构问题Q: 一个常被问到的一个问题是…

PTA 01-复杂度2 Maximum Subsequence Sum (25分)

题目地址 https://pta.patest.cn/pta/test/16/exam/4/question/663 5-1 Maximum Subsequence Sum (25分) Given a sequence of KK integers { N_1N​1​​, N_2N​2​​, ..., N_KN​K​​ }. A continuous subsequence is defined to be { N_iN​i​​, N_{i1}N​i1​​, ..…

Listener

观察者设计模式&#xff1a; 它是事件驱动的一种体现形式。就好比在做什么事情的时候被人盯着。当对应做到某件事时&#xff0c;触发事件。 观察者模式通常由以下三部分组成&#xff1a; ​1. 事件源&#xff1a;触发事件的对象。 2.​ 事件&#xff1a;触发的动作&#xff0c;…

BZOJ 1083: [SCOI2005]繁忙的都市【Kruscal最小生成树裸题】

1083: [SCOI2005]繁忙的都市 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2925 Solved: 1927[Submit][Status][Discuss]Description 城市C是一个非常繁忙的大都市&#xff0c;城市中的道路十分的拥挤&#xff0c;于是市长决定对其中的道路进行改造。城市C的道 路是这样分…

Mysql介绍与安装LinuxmacOS系统

数据库&#xff1a; 用于存储和管理数据的仓库 数据库的好处&#xff1a; 可以持久化存储数据方便存储和管理数据使用了统一的方式操作数据库 – SQL 常见的数据库&#xff1a; Oracle&#xff1a;收费的大型数据库&#xff0c;Oracle公司的产品。Oracle收购SUN公司&#xff0c…

如何查看Laravel版本号的三种方法

1.PHP artisan --version 2.vim vendor/laravel/framework/src/Illuminate/Foundation/Application.php 3&#xff1a;可以写在路由里 5.4版本的路由文件夹是routes。我们可以写在routes\web.php里。 Route::get(laravel-version, function(){ $laravel app(); return…

最全的Mysql数据类型

数值类型&#xff1a; 类型大小范围&#xff08;有符号&#xff09;范围&#xff08;无符号&#xff09;用途Bit1bytes-128 ~ 120 ~ 255小整数值TINYINT1 byte-128 ~ 1270 ~ 255小整数值SMALLINT2 bytes-32768 ~ 327670 ~ 65535大整数值MEDIUMINT3 bytes-8388608 ~ 83886070 ~…

02_反汇编_反编译

实际上安卓的应用都是zip包,只不过把zip扩展名修改了,修改成了APK.所以如果你想拿到它的图片的话,实际上特别简单&#xff0c;你就把它这个.apk换成.zip.换成.zip之后这里的图片资源就都可以拿到了. 有些公司可能美工的水平或者美工的人数比较少&#xff0c;项目还比较急&#…

SQL约束语法

约束 作用&#xff1a;对表中的数据进行限定&#xff0c;保证数据的正确性、有效性、完整性&#xff01; 约束分类&#xff1a; 约束说明PRIMARY KEY主键约束PRIMARY KEY AUTO_INCREMENT主键、自动增长UNIQUE唯一约束NOT NULL非空约束FOREIGN KEY外键约束FOREIGN KEY ON UPDAT…

hdu 2489 Minimal Ratio Tree

https://vjudge.net/problem/HDU-2489 题意&#xff1a;求一个完全图的最优比率生成树&#xff0c;点的个数由题给出。最优比率生成树是边的权值之和与点的权值之和的比值最小的生成树。 思路&#xff1a;一开始用dfs枚举搜索每一种情况&#xff0c;t了&#xff0c;枚举的情况太…

SQL多表关联

多表关联&#xff1a; 多张数据表之间是可以有一定的关联关系&#xff0c;这种关联关系可以通过外键约束实现 多表的分类&#xff1a; 一对一一对多多对多 一对一&#xff1a; 一张表对应一张表 适用场景举例&#xff1a; 人和身份证。一个人只能有一个身份证&#xff0c;一个身…