[Java]Session机制

news2024/11/28 6:44:44

 

什么是Session

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

实现用户登录

Session对应的类为javax.servlet.http.HttpSession类。每个来访者对应一个Session对象,所有该客户的状态信息都保存在这个Session对象里。Session对象是在客户端第一次请求服务器的时候创建的。Session也是一种key-value的属性对,通过getAttribute(Stringkey)和setAttribute(String key,Objectvalue)方法读写客户状态信息。Servlet里通过request.getSession()方法获取该客户的Session,例如:

HttpSession session = request.getSession();       // 获取Session对象
session.setAttribute("loginTime", new Date());     // 设置Session中的属性
 
out.println("登录时间为:" +(Date)session.getAttribute("loginTime"));      // 获取Session属性

request还可以使用getSession(boolean create)来获取Session。区别是如果该客户的Session不存在,request.getSession()方法会返回null,而getSession(true)会先创建Session再将Session返回。

Servlet中必须使用request来编程式获取HttpSession对象,而JSP中内置了Session隐藏对象,可以直接使用。如果使用声明了<%@page session="false" %>,则Session隐藏对象不可用。下面的例子使用Session记录客户账号信息。

session.jsp:

<%@ page language="java" pageEncoding="UTF-8"%>
<jsp:directive.page import="com.helloweenvsfei.sessionWeb.bean.Person"/>
<jsp:directive.page import="java.text.SimpleDateFormat"/>
<jsp:directive.page import="java.text.DateFormat"/>
<jsp:directive.page import="java.util.Date"/>
<%!
    DateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd");         // 日期格式化器
%>
<%
    response.setCharacterEncoding("UTF-8");        // 设置request编码
    Person[] persons =
    {           
       // 基础数据,保存三个人的信息
        new Person("Liu Jinghua","password1", 34, dateFormat.parse
        ("1982-01-01")),
        new Person("Hello Kitty","hellokitty", 23, dateFormat.parse
        ("1984-02-21")),
        new Person("Garfield", "garfield_pass",23, dateFormat.parse
        ("1994-09-12"))
     };
 
    String message = "";                      // 要显示的消息
 
    if(request.getMethod().equals("POST"))
    { 
        // 如果是POST登录       
        for(Person person :persons)
        {           
           // 遍历基础数据,验证账号、密码
           // 如果用户名正确且密码正确
           if(person.getName().equalsIgnoreCase(request.getParameter("username"))&&person.getPassword().equals(request.getParameter("password")))
           {              
               // 登录成功,设置将用户的信息以及登录时间保存到Session
               session.setAttribute("person", person);                   // 保存登录的Person
               session.setAttribute("loginTime", new Date());          // 保存登录的时间              
               response.sendRedirect(request.getContextPath() + "/welcome.jsp");
               return;
            }
        }      
        message = "用户名密码不匹配,登录失败。";       // 登录失败
    }
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">
<html>
    // ... HTML代码为一个FORM表单,代码略,请看随书光盘
</html>

登录界面验证用户登录信息,如果登录正确,就把用户信息以及登录时间保存进Session,然后转到欢迎页面welcome.jsp。welcome.jsp中从Session中获取信息,并将用户资料显示出来。 welcome.jsp:

<%@ page language="java" pageEncoding="UTF-8"%>
<jsp:directive.pageimport="com.helloweenvsfei.sessionWeb.bean.Person"/>
<jsp:directive.page import="java.text.SimpleDateFormat"/>
<jsp:directive.page import="java.text.DateFormat"/>
<jsp:directive.page import="java.util.Date"/>
<%!
    DateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd");         // 日期格式化器
%>
<%
    Person person =(Person)session.getAttribute("person");                       // 获取登录的person
    Date loginTime =(Date)session.getAttribute("loginTime");                     // 获取登录时间
%>
    // ... 部分HTML代码略
            <table>
               <tr><td>您的姓名:</td>
                   <td><%= person.getName()%></td>
               </tr>
               <tr><td>登录时间:</td>
                   <td><%= loginTime%></td>
               </tr>
               <tr><td>您的年龄:</td>
                   <td><%= person.getAge()%></td>
               </tr>
               <tr><td>您的生日:</td>
                   <td><%=dateFormat.format(person.getBirthday()) %></td>
               </tr>
            </table>

注意:程序中Session中直接保存了Person类对象与Date类对象,使用起来要比Cookie方便。当多个客户端执行程序时,服务器会保存多个客户端的Session。获取Session的时候也不需要声明获取谁的Session。Session机制决定了当前客户只会获取到自己的Session,而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。

提示:Session的使用比Cookie方便,但是过多的Session存储在服务器内存中,会对服务器造成压力。

Session的生命周期

Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。

Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。

Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。

Session的有效期

由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。

Session的超时时间为maxInactiveInterval属性,可以通过对应的getMaxInactiveInterval()获取,通过setMaxInactiveInterval(longinterval)修改。

Session的超时时间也可以在web.xml中修改。另外,通过调用Session的invalidate()方法可以使Session失效。

Session的常用方法

Session中包括各种方法,使用起来要比Cookie方便得多。Session的常用方法如下所示。

void setAttribute(String attribute, Object value):设置Session属性。value参数可以为任何Java Object。通常为Java Bean。value信息不宜过大 
String getAttribute(String attribute):返回Session属性 Enumeration 
getAttributeNames():返回Session中存在的属性名 
void removeAttribute(String attribute):移除Session属性 
String getId():返回Session的ID。该ID由服务器自动创建,不会重复 
long getCreationTime():返回Session的创建日期。返回类型为long,常被转化为Date类型,例如:Date createTime = new Date(session.get CreationTime()) 
long getLastAccessedTime():返回Session的最后活跃时间。返回类型为long 
int getMaxInactiveInterval():返回Session的超时时间。单位为秒。超过该时间没有访问,服务器认为该Session失效 void 
setMaxInactiveInterval(int second):设置Session的超时时间。单位为秒 
void putValue(String attribute, Object value):不推荐的方法。已经被setAttribute(String attribute, Object Value)替代 
Object getValue(String attribute):不被推荐的方法。已经被getAttribute(String attr)替代 
boolean isNew():返回该Session是否是新创建的 
void invalidate():使该Session失效

Tomcat中Session的默认超时时间为20分钟。通过setMaxInactiveInterval(int seconds)修改超时时间。可以修改web.xml改变Session的默认超时时间。例如修改为60分钟:

<session-config>
   <session-timeout>60</session-timeout>      <!-- 单位:分钟 -->
</session-config>

注意:<session-timeout>参数的单位为分钟,而setMaxInactiveInterval(int s)单位为秒。

在server.xml中定义context时采用如下定义(单位为秒):

<Context path="/livsorder" docBase="/home/httpd/html/livsorder" defaultSessionTimeOut="3600" isWARExpanded="true"
    isWARValidated="false" isInvokerEnabled="true"
    isWorkDirPersistent="false"/>

Session对浏览器的要求

虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为Session需要使用Cookie作为识别标志。HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。

该Cookie为服务器自动生成的,它的maxAge属性一般为–1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。

因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,因此会共享一个Session。

注意:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在链接上右击,在弹出的快捷菜单中选择“在新窗口中打开”时,子窗口便可以访问父窗口的Session。

如果客户端浏览器将Cookie功能禁用,或者不支持Cookie怎么办?例如,绝大多数的手机浏览器都不支持Cookie。Java Web提供了另一种解决方案:URL地址重写。

URL地址重写

URL地址重写是对客户端不支持Cookie的解决方案。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。HttpServletResponse类提供了encodeURL(Stringurl)实现URL地址重写,例如:

<td>
    <a href="<%=response.encodeURL("index.jsp?c=1&wd=Java") %>"> 
    Homepage</a>
</td>

该方法会自动判断客户端是否支持Cookie。如果客户端支持Cookie,会将URL原封不动地输出来。如果客户端不支持Cookie,则会将用户Session的id重写到URL中。重写后的输出可能是这样的:

<td>
    <a href="index.jsp;jsessionid=0CCD096E7F8D97B0BE608AFDC3E1931E?c=1&wd=Java">Homepage</a>
</td>

即在文件名的后面,在URL参数的前面添加了字符串“;jsessionid=XXX”。其中XXX为Session的id。分析一下可以知道,增添的jsessionid字符串既不会影响请求的文件名,也不会影响提交的地址栏参数。用户单击这个链接的时候会把Session的id通过URL提交到服务器上,服务器通过解析URL地址获得Session的id。

如果是页面重定向(Redirection),URL地址重写可以这样写:

<%
    if(“administrator”.equals(userName)) {
        response.sendRedirect(response.encodeRedirectURL(“administrator.jsp”));
        return;
    }
%>

效果跟response.encodeURL(String url)是一样的:如果客户端支持Cookie,生成原URL地址,如果不支持Cookie,传回重写后的带有jsessionid字符串的地址。

对于WAP程序,由于大部分的手机浏览器都不支持Cookie,WAP程序都会采用URL地址重写来跟踪用户会话。

注意:TOMCAT判断客户端浏览器是否支持Cookie的依据是请求中是否含有Cookie。尽管客户端可能会支持Cookie,但是由于第一次请求时不会携带任何Cookie(因为并无任何Cookie可以携带),URL地址重写后的地址中仍然会带有jsessionid。当第二次访问时服务器已经在浏览器中写入Cookie了,因此URL地址重写后的地址中就不会带有jsessionid了。

由于Cookie可以被人为的禁止,必须有其他机制以便在Cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面,附加方式也有两种: 一种是作为URL路径的附加信息,表现形式为http://...../xxx;jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764 一种是作为查询字符串附加在URL后面,表现形式为http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764

这两种方式对于用户来说是没有区别的,只是服务器在解析的时候处理的方式不同,采用第一种方式也有利于把session id的信息和正常程序参数区分开来。为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。

另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如下面的表单:

<form name="testform" action="/xxx">
    <input type="text">
</form>

在被传递给客户端之前将被改写成:

<form name="testform" action="/xxx">
    <input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
    <input type="text">
</form>

这种技术现在已较少应用。

在谈论session机制的时候,常常听到这样一种误解“只要关闭浏览器,session就消失了”。其实可以想象一下会员卡的例子,除非顾客主动对店家提出销卡,否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的,除非程序通知服务器删除一个session,否则服务器会一直保留,程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所以会有这种错觉,是大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个 session id就消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求头,把原来的session id发送给服务器,则再次打开浏览器仍然能够找到原来的session。

恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为seesion设置了一个失效时间,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。

Session中禁止使用Cookie

既然WAP上大部分的客户浏览器都不支持Cookie,索性禁止Session使用Cookie,统一使用URL地址重写会更好一些。Java Web规范支持通过配置的方式禁用Cookie。下面举例说一下怎样通过配置禁止使用Cookie。

打开项目sessionWeb的WebRoot目录下的META-INF文件夹(跟WEB-INF文件夹同级,如果没有则创建),打开context.xml(如果没有则创建),编辑内容如下: /META-INF/context.xml:

<?xml version='1.0' encoding='UTF-8'?>
    <Context path="/sessionWeb"cookies="false">
</Context>

或者修改Tomcat全局的conf/context.xml,修改内容如下: context.xml:

<!-- The contents of this file will be loaded for eachweb application -->
<Context cookies="false">
    <!-- ... 中间代码略 -->
</Context>

 

部署后TOMCAT便不会自动生成名JSESSIONID的Cookie,Session也不会以Cookie为识别标志,而仅仅以重写后的URL地址为识别标志了

注意:该配置只是禁止Session使用Cookie作为识别标志,并不能阻止其他的Cookie读写。也就是说服务器不会自动维护名为JSESSIONID的Cookie了,但是程序中仍然可以读写其他的Cookie。

Cookie与Session的区别

cookie数据存放在客户的浏览器上,session数据放在服务器上;
cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session;
session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用COOKIE;
单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能超过3K;

Cookie和Session的方案虽然分别属于客户端和服务端,但是服务端的session的实现对客户端的cookie有依赖关系的,上面我讲到服务端执行session机制时候会生成session的id值,这个id值会发送给客户端,客户端每次请求都会把这个id值放到http请求的头部发送给服务端,而这个id值在客户端会保存下来,保存的容器就是cookie,因此当我们完全禁掉浏览器的cookie的时候,服务端的session也会不能正常使用(注意:有些资料说ASP解决这个问题,当浏览器的cookie被禁掉,服务端的session任然可以正常使用,ASP我没试验过,但是对于网络上很多用php和jsp编写的网站,我发现禁掉cookie,网站的session都无法正常的访问)。

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

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

相关文章

基于springboot和ajax的简单项目 04.html文件的js用来分页功能,有专门的分页页面html文件(下)

01&#xff0c;因为分页的功能是很多场景都需要使用的&#xff0c;所以可以单独提出来&#xff0c;到时候加载到相关html的div中就好了。 最开始初始化分页html文件&#xff08;page.html&#xff09;的全部代码&#xff1a;&#xff08;直接使用的是ul&#xff0c;li&#xff…

LeetCode算法小抄--快速排序详解及应用

LeetCode算法小抄--快速排序详解及应用快速排序详解及应用代码实现快速选择算法&#xff08;Quick Select&#xff09;-- 变体[215. 数组中的第K个最大元素](https://leetcode.cn/problems/kth-largest-element-in-an-array/)[剑指 Offer II 076. 数组中的第 k 大的数字](https…

LCMXO2-2000HC-4FTG256I FPGA lattice 深力科MachXO2系列超低功耗非易失PLD器件特性及原理图

LCMXO2-2000HC-4FTG256I FPGA lattice 深力科MachXO2系列超低功耗非易失PLD器件特性及原理图 lattice莱迪斯深力科电子 MachXO2系列 LCMXO2-2000HC-4FTG256I 超低密度FPGA现场可编程门阵列&#xff0c;适用于低成本的复杂系统控制和视频接口设计开发&#xff0c;满足了通信、计…

std::condition_variable::wait_for 的几个细节

std::condition_variable::wait_for 的两种重载用法https://blog.csdn.net/smalbig/article/details/130152253 &#xff08;以下简称上篇&#xff09;直观上介绍了 std::condition_variable::wait_for 的使用效果&#xff0c;这篇对没解释清楚的注释、执行结果进行解释。 1.…

大话 HTTP 协议前世今生

HTTP 全称 Hypertext Transfer Protocol&#xff0c;中文是超文本传输协议。网上讲 HTTP 协议的资料可以说是五花八门&#xff0c;但大多数都在罗列 HTTP 协议具体的规定&#xff0c;很少有讲 HTTP 协议这样设计的原因。今天我就尝试从解决问题的角度分析 HTTP 协议主要特性&am…

Android init学习笔记

init大体介绍 init是Android启动的第一个用户空间进程&#xff0c;它fork产生一些关键进程&#xff0c;如zygote、surfaceflinger进程。 init进程有很多功能&#xff1a;加载内核模块、挂载系统分区、加载sepolicy、支持属性服务、启动rc脚本、执行事件触发器和属性改变等等 …

C++之深入解析STL deque容器的底层实现原理

一、deque 容器的存储结构 事实上&#xff0c;STL 中每个容器的特性&#xff0c;和它底层的实现机制密切相关&#xff0c;deque 自然也不例外&#xff0c;deque 容器擅长在序列的头部和尾部添加或删除元素。想搞清楚 deque 容器的实现机制&#xff0c;需要先了解 deque 容器的…

【Python】实战:生成有关联单选问卷 csv《营养不良风险评估表》

目录 一、适用场景 二、业务需求 三、Python 文件 &#xff08;1&#xff09;创建文件 &#xff08;2&#xff09;示例代码 四、csv 文件 &#xff08;1&#xff09;营养不良风险评估表&#xff08;问题 6 不选“不能取得”&#xff09; &#xff08;2&#xff09;营养…

从输入url到页面展现(一)从浏览器解析url开始

前端面试有一道很考验人的问题&#xff0c;那就是&#xff1a;请你说一下从用户从输入url到页面展现的过程是怎样的&#xff1f;在接下来的一段时间呢&#xff0c;狗哥会从这一问题出发&#xff0c;开始剖析这个过程&#xff0c;希望可以让更多的小伙伴掌握到这个过程&#xff…

【加载plist文件展示单组数据 Objective-C语言】

一、接下来,我们要为大家演示如何通过加载plist文件,使用UITableView展示单组数据, 1.最后运行起来的效果,是一个什么效果呢,是这样一个效果: 2.这个里面,这就是一个单元格吧, 这就是一个单元格, 这个单元格里面,包括一个图片框、一个TextLabel、一个DetailLabel、…

JAVA开发(通过网关gateway过滤器进行返回结果加密)

在对C的网站或者APP后端接口中&#xff0c;参数的传输往往需要加密传输。这时我们 可以通过springcloud的网关过滤器进行统一的控制。 网关过滤器的执行顺序&#xff1a; 请求进入网关会碰到三类过滤器&#xff1a;当前路由过滤器、DefaultFilter、GlobalFilter。 请求路由后…

ChatGPT团队中,3个清华学霸,1个北大学霸,共9位华人

众所周知&#xff0c;美国硅谷其实有着众多的华人&#xff0c;哪怕是芯片领域&#xff0c;华为也有着一席之地&#xff0c;比如AMD 的 CEO 苏姿丰、Nvidia 的 CEO 黄仁勋 都是华人。 还有更多的美国著名的科技企业中&#xff0c;都有着华人的身影&#xff0c;这些华人&#xff…

Vue组件化编程【Vue】

2.Vue 组件化编程 2.1 模块与组件、模块化与组件化 2.1.1 模块 理解&#xff1a;向外提供特定功能的js程序&#xff0c;一般就是一个js文件为什么&#xff1a;js文件很多很复杂作用&#xff1a;复用js、简化js的编写、提高js运行效率。 2.1.2 组件 理解&#xff1a;用来实…

Linux搭建Web服务器(二)——Web Server 与 HTTP

目录 0x01 Web Server 静态网络服务器&#xff08;static web server&#xff09; 动态网络服务器&#xff08;dynamic web server&#xff09; 0x02 HTTP协议 HTTP概述 HTTP工作原理 HTTP请求报文格式 HTTP响应报文格式 0x01 Web Server 一个Web Server就是一个服务器…

我们要被淘汰了?从科技变革看"ChatGPT"与"无代码开发"

现在只要一上网&#xff0c;就能看见GPT都在说“好厉害”、“太牛了”、“新技术要诞生了”、“我们人类要被淘汰了”之类的话题。但是这伟大的技术变革到底给我们带来了什么呢&#xff1f;答案好像又比较模糊。现在ChatGPT的代写、问答&#xff0c;以及开始做的搜索、办公是目…

sql查询语句-01

1.单表查询 ◆限制显示结果 使用limit限制显示的行数&#xff0c;分页函数limit m,n,从m1行开始显示n条记录 例&#xff1a;查询选修课程成绩排在前5的学生的学号和成绩。 select sno,score from SCorder by score desc limit 5;limit 1,3 零是第一条 ◆汇总数据(聚集函数&…

coinex06 // 前端数据 -> ringbuffer -> cpu

目录 0. 逻辑树 1 exchange-service 发送消息 1.1 exchange-service 添加依赖 1.2. yml配置文件 1.3. Source 1.4. 配置类 1.5. 发送消息到撮合引擎 service -> impl -> EntrustOrderServiceImpl 1.6. recket-server:8080 2. match-server 接收数据 2.1 数据转…

【SQL 必知必会】- 第十七课 创建和操纵表

目录 17.1 创建表 17.1.1 表创建基础 替换现有的表 17.1.2 使用NULL值 主键和NULL 值 理解NULL 17.1.3 指定默认值 使用DEFAULT 而不是NULL 值 17.2 更新表 小心使用ALTER TABLE 17.3 删除表 使用关系规则防止意外删除 17.4 重命名表 17.5 小结 这一课讲授创建、更改和删除…

【MyBatis Plus】002 -- 通用CRUD(插入、更新、删除、查询)

目录 3、通用CRUD 3.1 插入操作 3.1.1 方法定义 3.1.2 测试用例 3.1.3 测试 3.1.4 TableField 3.2 更新操作 3.2.1 根据id更新 3.2.2 根据条件更新 3.3 删除操作 3.3.1 根据id删除&#xff08;deleteById&#xff09; 3.3.2 根据Map删除数据&#xff08;deleteByMap&#xff09…

程序员必备技巧:Git 和 GitHub 中高效地将单个文件还原为特定提交

Git 和 GitHub 用于存储您的旧代码&#xff0c;允许您在出现问题时回滚并安全地恢复以前的准确代码。 与其他开发人员协作时&#xff0c;了解如何将单个文件恢复为特定提交也变得至关重要。这是因为&#xff0c;在处理某个功能时&#xff0c;您可能需要修改不相关的文件来测试…