第十四讲 JDBC数据库
1. 什么是JDBC
JDBC(Java Database Connectivity,Java数据库连接),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库,并使用SQL语句来完成对数据库中数据的查询、新增、更新和删除等操作。
应用程序使用JDBC访问数据库的方式如图1所示。

图1 应用程序通过JDBC访问数据库方式
2. JDBC常用API
(1)Driver接口
Driver接口是所有JDBC驱动程序必须实现的接口,该接口专门提供给数据库厂商使用。
注意:在编写JDBC程序时,必须要把所使用的数据库驱动程序或类库加载到项目的classpath中(这里指数据库的驱动JAR包)。
(2)DriverManager类
DriverManager类用于加载JDBC驱动并且创建与数据库的连接。其主要方法如表1所示。
表1 DriverManager类常用方法
| 方法声明 | 功能描述 |
| static synchronized void registerDriver(Driver driver) | 该方法用于向DriverManager中注册给定的JDBC驱动程序 |
| static Connection getConnection(String url,String user,String pwd) | 该方法用于建立和数据库的连接,并返回表示连接的Connection对象 |
说明:在实际开发中,通常不使用registerDriver(Driverdriver)注册驱动。因为JDBC驱动类Driver中有一段静态代码块,是向DriverManager注册一个Driver实例,当再次执行registerDriver(newDriver()),相当于实例化了两个Driver对象,因此在加载数据库驱动时通常使用Class类的静态方法forName()来实现。
(3) Connection接口
Connection接口代表Java程序和数据库的连接对象,只有获得该连接对象后,才能访问数据库,并操作数据表。Connection接口常用方法如表2所示。
表2 Connection接口
| 方法声明 | 功能描述 |
| Statement createStatement() | 该方法用于返回一个向数据库发送语句的Statement对象 |
| PreparedStatement prepareStatement(String sql) | 该方法用于返回一个PreparedStatement对象,该对象用于向数据库发送参数化的SQL语句 |
| CallableStatement prepareCall(String sql) | 该方法用于返回一个CallableStatement对象,该对象用于调用数据库中的存储过程 |
(4) Statement接口
Statement是Java执行数据库操作的一个重要接口,它用于执行静态的SQL语句,并返回一个结果对象。
说明:Statement接口对象可以通过Connection实例的createStatement()方法获得,然后返回数据库的处理结果。Statement接口常用方法如表3所示。
表3 Statement常用方法
| 方法声明 | 功能描述 |
| boolean execute(String sql) | 用于执行各种SQL语句,返回一个boolean类型的值,如果为true,表示所执行的SQL语句有查询结果,可通过Statement的getResultSet()方法获得查询结果 |
| int executeUpdate(String sql) | 用于执行SQL中的insert、update和delete语句。该方法返回一个int类型的值,表示数据库中受该SQL语句影响的记录条数 |
| ResultSet executeQuery(String sql) | 用于执行SQL中的select语句,该方法返回一个表示查询结果的ResultSet对象 |
(5)PreparedStatement接口
Statement接口封装了JDBC执行SQL语句的方法,虽然可以完成Java程序执行SQL语句的操作,但是在实际开发过程中往往需要将程序中的变量作为SQL语句的查询条件,而使用Statement接口操作这些SQL语句会过于繁琐,并且存在安全方面的问题。针对这一问题,JDBC API 中提供了扩展的PreparedStatement接口。PreparedStatement是Statement的子接口,用于执行预编译的SQL语句。
说明:PreparedStatement接口扩展了带有参数SQL语句的执行操作,应用接口中的SQL语句可以使用占位符“?”来代替其参数,然后通过setXxx()方法为SQL语句的参数赋值。
PreparedStatement接口常用方法如表4所示。
表4 PreparedStatement接口常用方法
| 方法声明 | 功能描述 |
| int executeUpdate() | 在此PreparedStatement对象中执行 SQL 语句,该语句必须是一个DML语句或者是无返回内容的SQL 语句,如 DDL 语句 |
| ResultSet executeQuery() | 在此PreparedStatement对象中执行 SQL 查询,该方法返回的是ResultSet对象 |
| void setInt(int parameterIndex, int x) | 将指定参数设置为给定的int值 |
| void setFloat(int parameterIndex, float x) | 将指定参数设置为给定的float值 |
| void setString(int parameterIndex, String x) | 将指定参数设置为给定的String值 |
| void setDate(int parameterIndex, Date x) | 将指定参数设置为给定的Date值 |
| void addBatch() | 将一组参数添加到此PreparedStatement对象的批处理命令中 |
| void setCharacterStream(int parameterIndex, java.io.Reader reader, int length) | 将指定的输入流写入数据库的文本字段 |
| void setBinaryStream(int parameterIndex, java.io.InputStream x, int length) | 将二进制的输入流数据写入到二进制字段中 |
为SQL语句参数赋值时,可以通过输入参数与SQL类型相匹配的setXxx()方法。例如字段的数据类型为int或Integer,那么应该使用setInt()方法,也可以通过setObject()方法设置多种类型的输入参数。
// 假设users表中字段id、name、email类型分别是int、varchar、varcharString sql = "INSERT INTO users(id,name,email) VALUES(?,?,?)";PreparedStatement preStmt = conn.prepareStatement(sql);preStmt.setInt(1, 1); //使用参数与SQL类型相匹配的方法preStmt.setString(2, "zhangsan"); //使用参数与SQL类型相匹配的方法preStmt.setObject(3, "zs@sina.com"); //使用setObject()方法设置参数preStmt.executeUpdate();
(6)ResultSet接口
ResultSet接口用于保存JDBC执行查询时返回的结果集,该结果集封装在一个逻辑表格中。在ResultSet接口内部有一个指向表格数据行的游标(或指针),ResultSet对象初始化时,游标在表格的第一行之前,调用next()方法可将游标移动到下一行。如果下一行没有数据,则返回false。在程序中经常使用next()方法作为while循环的条件来迭代ResultSet结果集。ResultSet接口常用方法如表5所示。
表5 ResultSet接口常用方法
| 方法声明 | 功能描述 |
| String getString(int columnIndex) | 用于获取指定字段的String类型的值,参数columnIndex代表字段的索引 |
| String getString(String columnName) | 用于获取指定字段的String类型的值,参数columnName代表字段的名称 |
| int getInt(int columnIndex) | 用于获取指定字段的int类型的值,参数columnIndex代表字段的索引 |
| int getInt(String columnName) | 用于获取指定字段的int类型的值,参数columnName代表字段的名称 |
| Date getDate(int columnIndex) | 用于获取指定字段的Date类型的值,参数columnIndex代表字段的索引 |
| Date getDate(String columnName) | 用于获取指定字段的Date类型的值,参数columnName代表字段的名称 |
| boolean next() | 将游标从当前位置向下移一行 |
| boolean absolute(int row) | 将游标移动到此 ResultSet 对象的指定行 |
| void afterLast() | 将游标移动到此 ResultSet 对象的末尾,即最后一行之后 |
| void beforeFirst() | 将游标移动到此 ResultSet 对象的开头,即第一行之前 |
| boolean previous() | 将游标移动到此 ResultSet 对象的上一行 |
| boolean last() | 将游标移动到此 ResultSet 对象的最后一行 |
ResultSet接口中定义了大量的getXxx()方法,而采用哪种getXxx()方法取决于字段的数据类型。
程序既可以通过字段的名称来获取指定数据,也可以通过字段的索引来获取指定的数据,字段的索引是从1开始编号的。
例如,假设数据表的第1列字段名为id,字段类型为int,那么既可以使用getInt("id")获取该列的值,也可以使用getInt(1)获取该列的值。
3. JDBC编程的基本步骤
通常情况下,JDBC编程可分为如下几个基本步骤。
(1)加载数据库驱动
加载数据库驱动通常使用Class类的静态方法forName()来实现,使用格式:
Class.forName(DriverName);
上述代码中,DriverName代表的是数据库驱动类所对应的字符串。例如,要加载MySQL数据库的驱动可以采用如下代码。
Class.forName("com.mysql.jdbc.Driver");
(2)通过DriverManager获取数据库连接
DriverManager提供了一个getConnection()方法来获取数据库连接,使用格式如下。
Connection conn = DriverManager.getConnection(String url, String user, String pwd);
参数说明:
url:表示连接数据库的URL。
user:表示登录数据库的用户名。
pwd:表示登录数据库的密码。
用户名和密码通常由数据库管理员设置,而连接数据库的URL则有固定格式。如MySQL数据库的URL地址为。
jdbc:mysql://hostname:prot/databasename
上述代码中,jdbc:mysql:是固定写法,mysql指的是MySQL数据库;hostname指的是MySQL数据库所在的主机名或IP地址(例如数据库在本机上,hostname可以是localhost或127.0.0.1);port指的是连接数据库的端口号(默认为3306);databasename指的是要操作的数据库。
(3)通过Connection对象获取Statement对象
Connection创建Statement的方式有3种。
①createStatement():创建基本的Statement对象。
②prepareStatement(String sql):根据传递的SQL语句创建PreparedStatement对象。
③prepareCall(Stringsql):根据传入的SQL语句创建CallableStatement对象。
例创建基本的Statement对象,其代码如下所示。
Statement stmt = conn.createStatement();
(4)使用Statement执行SQL语句
可通过如下3种不同的方式来执行SQL语句。
①execute(String sql):用于执行任意的SQL语句。
②executeQuery(String sql):用于执行查询语句,返回ResultSet结果集对象。
③executeUpdate(String sql):主要用于执行DML(数据操作语言)和DDL(数据定义语言)语句。执行DML语句(INSERT、UPDATE或DELETE)时,会返回受SQL语句影响的行数,执行DDL(CREATE、ALTER)语句返回0。
例执行查询SQL,获取结果集:
// 执行SQL语句,获取结果集ResultSetResultSet rs = stmt.executeQuery(sql);
(5)操作ResultSet结果集
如果执行的SQL语句是查询语句,执行结果将返回一个ResultSet对象,该对象里保存了SQL语句查询的结果。程序可以通过操作该ResultSet对象来取出查询结果。
(6)关闭连接,释放资源
每次操作数据库结束后都要关闭数据库连接,释放资源,以重复利用资源。通常资源的关闭顺序与打开顺序相反,顺序是ResultSet、Statement(或PreparedStatement)和Connection。为了保证在异常情况下也能关闭资源,需要在try...catch的finally代码块中统一关闭资源。
4. JDBC编程示例
(1)添加mysql驱动
①在项目中新建一lib目录,将mysql的驱动程序复制到此目录中。

②选择菜单【file】-【project structure】,左侧选择“modules”,右侧中间选择“Dependencies”,然后点击右上角的“+”号,选择“1 jars or directories…”,如下图所示。

③在弹出的对话框中选择项目中lib目录下的mysql驱动,然后点击”ok”返回。

④此时在Dependencies中会多了刚才选中的mysql驱动,然后点击“ok”即可。

(2)数据库操作
假设要操作的MySQL数据库名为db_student,db_student数据库中有一个表为tb_stud,表中内容如下所示。

【例10-1】读取表中内容并显示
import java.sql.*;public class JDBCShow {public static void main(String[] args) throws SQLException {Connection conn = null;Statement stmt = null;ResultSet rs = null;try{Class.forName("com.mysql.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/db_student?characterEncoding=utf8";String username="root";String password = "";conn = DriverManager.getConnection(url,username,password);stmt = conn.createStatement();rs = stmt.executeQuery("select * from tb_stud");System.out.println("no\t\tname\tmath\tchinese\tenglish");while(rs.next()){String no = rs.getString("no");String name = rs.getString("name");int math = rs.getInt("math");int chinese = rs.getInt("chinese");int english = rs.getInt("english");System.out.println(no + "\t" +name + "\t" + math + "\t\t" + chinese+"\t\t"+ english);}}catch(Exception e){e.printStackTrace();}finally{if(rs!=null) {rs.close();}if(stmt!=null){stmt.close();}if (conn!=null){conn.close();}}}}
运行结果如下图所示。

【例10-2】先往表中插入记录,然后读取表中记录显示
import java.sql.*;public class JDBCInsertShow {public static void main(String[] args) throws SQLException {Connection conn = null;Statement stmt = null;ResultSet rs = null;try{Class.forName("com.mysql.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/db_student?characterEncoding=utf8";String username="root";String password = "";conn = DriverManager.getConnection(url,username,password);stmt = conn.createStatement();String sql = "insert into tb_stud(no,name,math,chinese,english) values(?,?,?,?,?)";PreparedStatement preStmt =conn.prepareStatement(sql);preStmt.setString(1,"1005");preStmt.setString(2,"张小");preStmt.setInt(3,80);preStmt.setInt(4,99);preStmt.setInt(5,90);preStmt.executeUpdate();rs = stmt.executeQuery("select * from tb_stud");System.out.println("no\t\tname\tmath\tchinese\tenglish");while(rs.next()){String no = rs.getString("no");String name = rs.getString("name");int math = rs.getInt("math");int chinese = rs.getInt("chinese");int english = rs.getInt("english");System.out.println(no + "\t" +name + "\t" + math + "\t\t" + chinese+"\t\t"+ english);}}catch(Exception e){e.printStackTrace();}finally{if(rs!=null) {rs.close();}if(stmt!=null){stmt.close();}if (conn!=null){conn.close();}}}}
运行结果如下图所示。

此时数据库表中内容如下所示。

【例10-3】记录的增、删、改、显示操作
import java.sql.*;public class JDBCOperator {public static void main(String[] args) throws SQLException {Connection conn = null;Statement stmt = null;ResultSet rs = null;try{Class.forName("com.mysql.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/db_student?characterEncoding=utf8";String username = "root";String pw = "";conn = DriverManager.getConnection(url,username,pw);stmt = conn.createStatement();String sql = "update tb_stud set name='王明' where id=1"; //记录的修改stmt.executeUpdate(sql);sql = "insert into tb_stud values(null,'1004','张朋',70,70,70)"; //记录的添加stmt.executeUpdate(sql);sql = "delete from tb_stud where name='李军'"; //记录的删除stmt.executeUpdate(sql);rs = stmt.executeQuery("select * from tb_stud");System.out.println("no\t\tname\tmath\tchinese\tenglish");while(rs.next()){String no = rs.getString("no");String name = rs.getString("name");int math = rs.getInt("math");int chinese = rs.getInt("chinese");int english = rs.getInt("english");System.out.println(no + "\t" +name + "\t" + math + "\t\t" + chinese+"\t\t"+ english);}}catch(Exception e){e.printStackTrace();} }finally{if (rs!=null){rs.close();}if (stmt!=null) {stmt.close();}if (conn!=null) {conn.close();}}}
运行结果如下图所示。

此时表中内容如下所示。

相关文章:
第十四讲 JDBC数据库
1. 什么是JDBC JDBC(Java Database Connectivity,Java数据库连接),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库,并使用SQL语句来完成对数据库中数据的查询、新增、更新和删除等操作…...
“AI教学实训系统:打造未来教育的超级引擎
嘿,各位教育界的伙伴们,今天我要跟你们聊聊一个绝对能让你们眼前一亮的教学神器——AI教学实训系统。作为资深产品经理,我可是亲眼见证了这款系统如何颠覆传统教学,成为未来教育的超级引擎。 一、什么是AI教学实训系统?…...
java读取设置pdf属性信息
pom <dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.24</version> </dependency>读取属性 import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmod…...
C语言内存管理详解
C语言不像其他高级语言那样提供自动内存管理,它要求程序员手动进行内存的分配和释放。在C语言中,动态内存的管理主要依赖于 malloc、calloc、realloc 和 free 等函数。理解这些函数的用法、内存泄漏的原因及其防止方法,对于编写高效、可靠的C…...
mysql从全备文件中提取单库或单表进行恢复——筑梦之路
前提条件 与业务确认涉及业务、数据库IP、数据误删除时间点、数据删除涉及的SCHEMA、数据表,确认该数据库为MySQLdump备份方式,备份策略为每日凌晨1点进行数据库全备份,备份保留7天,业务误删除数据时间点为当日10点左右࿰…...
HTML-新浪新闻-实现标题-排版
标题排版 图片标签:<img> src:指定图片的url(绝对路径/相对路径) width:图片的宽度(像素/相对于父元素的百分比) heigth:图片的高度(像素/相对于父元素的百分比&a…...
【前沿聚焦】机器学习的未来版图:从自动化到隐私保护的技术突破
网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…...
二叉树的最大深度(C语言详解版)
一、摘要 嗨喽呀大家,leetcode每日一题又和大家见面啦,今天要讲的是104.二叉树的最大深度,思路互相学习,有什么不足的地方欢迎指正!好啦让我们开始吧!!! 二、题目简介 给定一个二…...
基于dlib/face recognition人脸识别推拉流实现
目录 一.环境搭建 二.推拉流代码 三.人脸检测推拉流 一.环境搭建 1.下载RTSP服务器MediaMTX与FFmpeg FFmpeg是一款功能强大的开源多媒体处理工具,而MediaMTX则是一个轻量级的流媒体服务器。两者结合,可以实现将本地视频或者实时摄像头画面推送到RTSP流,从而实现视频…...
【kong gateway】5分钟快速上手kong gateway
kong gateway的请求响应示意图 安装 下载对应的docker 镜像 可以直接使用docker pull命令拉取,也可以从以下地址下载:kong gateway 3.9.0.0 docker 镜像 https://download.csdn.net/download/zhangshenglu1/90307400, postgres-13.tar http…...
webrtc入门系列(五)amazon-kinesis-video-streams-webrtc-sdk-c编译
《webrtc入门系列(一)easy_webrtc_server 入门环境搭建》 《webrtc入门系列(二)easy_webrtc_server 入门example测试》 《webrtc入门系列(三)云服务器coturn环境搭建》 《webrtc入门系列(四&…...
通过亚马逊云科技Bedrock打造自定义AI智能体Agent(上)
大家对于智能体代理Agent一定已经非常熟悉,自主代理(Autonomous Agents) 目前在AI行业极其热门并具有巨大的潜力,能够显著提升开发者日常的工作效率、自动化日常琐碎、重复性任务,并生成全新的内容。Agent可以理解用户…...
【Nacos】负载均衡
目录 前言 一、服务下线二、权重配置三、同一个集群优先访问四、环境隔离 前言 我们的生产环境相对是比较恶劣的,我们需要对服务的流量进行更加精细的控制.Nacos支持多种负载均衡策略,包括配置权重,同机房,同地域,同环…...
小智 AI 聊天机器人
小智 AI 聊天机器人 (XiaoZhi AI Chatbot) 👉参考源项目复现 👉 ESP32SenseVoiceQwen72B打造你的AI聊天伴侣!【bilibili】 👉 手工打造你的 AI 女友,新手入门教程【bilibili】 项目目的 本…...
HTML一般标签和自闭合标签介绍
在HTML中,标签用于定义网页内容的结构和样式。标签通常分为两类:一般标签(也称为成对标签或开放闭合标签)和自闭合标签(也称为空标签或自结束标签)。 以下是这两类标签的详细说明: 一、一般标…...
怎么用u盘怎么重装系统_用u盘重装系统详细图文教程【新手教程】
怎么用u盘怎么重装系统?如果需要重装操作系统的话,以往采用光盘使用的比较多,随着技术的进步,用u盘制作一个启动盘安装系统比较方便,只需要用u盘制作好pe启动盘就可以帮助别人安装系统了,那么用u盘怎么重装…...
记录一次k8s起不来的排查过程
我在k8s集群,重启了一个node宿主机,竟然发现kubelet起不来了!报错如下 这个报错很模糊,怎么排查呢。这样,开两个界面,一个重启kubelet,一个看系统日志(/var/log/message:centos,/va…...
代码练习2
求数组中的第二大值 #include <stdio.h> #include <stdlib.h> int main() {int arr[10]{1,9,2,8,7,3,4,6,5,10};int first, second,i;if (arr[0] > arr[1]) {first arr[0];second arr[1];} else {first arr[1];second arr[0];}for(i 2; i < 10; i) {if…...
2.1.3 第一个工程,点灯!
新建工程 点击菜单栏左上角,新建工程或者选择“文件”-“新建工程”,选择工程类型“标准工程”选择设备类型和编程语言,并指定工程文件名及保存路径,如下图所示: 选择工程类型为“标准工程” 选择主模块机型&#x…...
Qt Designer and Python: Build Your GUI
1.install pyside6 2.pyside6-designer.exe 发送到桌面快捷方式 在Python安装的所在 Scripts 文件夹下找到此文件。如C:\Program Files\Python312\Scripts 3. 打开pyside6-designer 设计UI 4.保存为simple.ui 文件,再转成py文件 用代码执行 pyside6-uic.exe simpl…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
