尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
JDBC实战指南:打通Java Web与MySQL的数据访问底层逻辑
做Web开发做到这个阶段你大概率已经能写Servlet、能拼HTML页面、能在浏览器里看到自己输出的内容了。但你会发现一个很明显的问题页面上显示的东西全部是代码里写死的字符串刷新多少次都一样用户一点参与感都没有。真正的动态网站核心是数据——用户注册的信息要存下来商品列表要从库里查出来订单要写进表里。把Java程序和MySQL数据库打通这件事就是JDBC干的事也是今天这篇java_web之路第6篇的主题。这篇东西适合谁看适合那些已经会了一点Java基础语法、知道Servlet和JSP大概怎么回事但一碰到数据存取就发懵的同学。文章会从为什么必须用JDBC讲起然后把MySQL环境准备、JDBC核心API、实际编程时必踩的坑、再到事务和连接池这个概念一条线捋清楚。即便你以后去用MyBatis、Spring Data JPA这类框架今天讲的这些底层逻辑仍然是它们的地基地基不稳上层框架出了错你都不知道去哪查。1. 为什么Web开发离不开JDBC从Servlet到数据库的最后一公里1.1 动态页面的本质数据到底从哪来先说一个很多新手容易忽略的事实。你在浏览器里看到的任何一个动态页面本质上都是服务器端程序根据请求参数从某个地方把数据取出来再拼成HTML返回给浏览器。这个某个地方早期可能是内存里的集合后来是文件但真正规模化之后一定是数据库。举个例子你做一个用户登录功能用户在前端输入用户名和密码点击登录Servlet收到请求之后怎么判断这个用户存不存在总不能在Java代码里写一堆if判断去穷举所有合法用户。合理的做法是把用户输入的账号密码拿到数据库的user表里查一遍有匹配的记录就登录成功没有就是密码错误。再比如你做一个文章列表页文章内容存在哪如果每次发布文章都去改.java文件里的静态数组那这个系统基本没法用。所有博客、电商、后台管理系统的标准答案都是内容进数据库页面展示时通过代码去查询数据库。而Java程序访问数据库最原始、最直接的方式就是JDBC。1.2 JDBC在Java Web技术栈中的定位JDBC的全称是Java Database Connectivity它不是什么第三方框架而是Java标准库提供的一套接口规范位于java.sql和javax.sql这两个包下面。它定义了你连接数据库、执行SQL语句、处理结果集的标准方法具体怎么和某个数据库通信则由对应的数据库驱动jar包去实现。这里有个很重要的理解角度JDBC只是接口真正的实现是各个数据库厂商提供的驱动。MySQL有MySQL的驱动mysql-connector-javaOracle有Oracle的驱动SQL Server有SQL Server的驱动。你的Java代码面向JDBC接口编写只需要在运行时把对应的驱动jar包放进classpath换一个数据库供应商时大部分代码可以保持不变的。有个很生活化的类比JDBC这个接口就是电器上的标准插座。MySQL的驱动就是你买的那个电器上配备的插头。你只需要保证插头符合插座标准电器插上去就能通电。所以JDBC不是一个具体工具它是一个约定是整个Java数据访问世界的通用语言。1.3 JDBC一次完整的工作流程在动手写代码之前脑子里一定要先有这个完整流程不然很容易写一步卡一步加载驱动通知JVM要使用哪个数据库的驱动类让驱动能够被注册到DriverManager中。获取连接通过DriverManager拿到一个Connection对象这个对象代表你和数据库之间的一条物理网络连接。创建语句通过Connection创建Statement或者PreparedStatement用来发送SQL语句。执行SQL如果是查询调用executeQuery()拿到ResultSet结果集如果是增删改调用executeUpdate()拿到受影响的行数。处理结果从ResultSet中逐行取数据封装成Java对象或拼装成前端要用的数据格式。释放资源关闭ResultSet、Statement、Connection。这一步前期容易习惯性省略省略的后果后面会专门讲。注意第6步——释放资源。很多初学者写的JDBC代码查询到的数据是有了但连接一直没关。这在测试环境跑一次两次没什么感觉一旦放到正式环境里高并发请求一来数据库连接池瞬间耗尽整个系统直接卡死。所以你从一开始就要养成用完必关的习惯。2. 环境准备的三个坑MySQL安装、驱动包引入、连接URL配置2.1 本地MySQL环境的搭建与启动先说MySQL的安装。这里我不打算把安装步骤一条条列完整因为图形化安装程序Next、Next就过去了真正让新手花掉半天时间的往往是安装完之后不知道怎么算成功、怎么启动服务。MySQL安装主要有两种方式官方MSI安装包图形化引导和ZIP压缩包解压即用。如果只是本地学习和跑demoMSI安装包最省事。但要注意安装过程中的几个选项端口号默认是3306除非你机器上已经装了别的MySQL实例或MariaDB否则别改改了后面所有连接URL都要跟着变。认证方式新版MySQL 8.x会问你要不要用新的caching_sha2_password认证插件。如果你只是配JDBC新插件没问题但如果你的驱动包比较旧5.x版建议选传统的mysql_native_password否则连接时大概率报认证相关错误。root密码安装时设置的root密码一定要记清楚。密码忘了非常折腾后面所有连接都做不了。安装完成之后去Windows服务管理里找一下有没有一个名字叫MySQL80或类似的服务把它启动起来。你也可以用命令行验证打开cmd输入mysql -u root -p然后输入密码能进入mysql提示符就说明服务正常。这个验证步骤很关键它能帮你区分数据库服务没起和JDBC代码写得有问题。2.2 MySQL 8.x驱动包的选择与引入环境装好MySQL之后又有一个新手常踩的坑驱动jar包版本和数据库版本不匹配。MySQL官方提供的驱动叫mysql-connector-java如果你是MySQL 5.x系列可以用5.1.x版本的驱动如果是MySQL 8.x建议用8.0.x版本的驱动。驱动版本不同连驱动类的类名都不一样5.1.xClass.forName(com.mysql.jdbc.Driver)8.0.xClass.forName(com.mysql.cj.jdbc.Driver)很多人从旧教程里抄了com.mysql.jdbc.Driver这个类名配上MySQL 8.x数据库死活加载不上这就是版本不对应的结果。如果通过Maven引入我推荐直接使用8.0系列坐标如下dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency如果是手工导入jar包的传统方式很多学校课程或公司老项目仍是这样去Maven中央仓库搜索mysql-connector-java下载对应版本的jar文件放到项目的WEB-INF/lib目录或通过IDE添加到构建路径。有一点要注意如果编译能过但运行时报ClassNotFoundException十有八九是jar包没有真正被部署到运行时classpath里而不是代码问题。2.3 连接URL的标准格式与参数含义数据库和驱动都准备好后接下来是让Java程序连接上MySQL。核心就一句话DriverManager.getConnection(url, username, password);关键在于这个url字符串的写法。标准格式是jdbc:mysql://主机地址:端口/数据库名?参数1值1参数2值2比如连接本机的mydb数据库用户名为root密码为123456完整URL可以是jdbc:mysql://localhost:3306/mydb?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8这里逐个说明几个参数理解了才能不瞎抄useSSLfalse本地开发环境建议关掉SSL加密因为MySQL默认支持SSL但本地测试场景用不到加上这个参数能减少握手开销还能避免某些驱动版本因SSL握手问题报错。serverTimezoneAsia/ShanghaiMySQL 8.x要求驱动必须设置时区否则会报Server returns invalid timezone错误。国内开发都设Asia/Shanghai。characterEncodingutf8让客户端和服务器之间使用utf8编码传输数据这是解决中文乱码的最关键参数字符串characterEncodingutf8和characterEncodingUTF-8效果等价注意别把中间的Encoding拼错。useUnicodetrue这个参数在新版驱动里可以省略因为characterEncoding已经隐含了启用Unicode。有些教程还会加一个allowPublicKeyRetrievaltrue这是在用caching_sha2_password认证时可能需要的参数。如果连MySQL 8.x时遇到关于public key retrieval的报错把它加上就行。提示连接URL里的每一个参数都意味着代码和数据库之间的一种约定 。报错时优先检查URL因为数据库名拼错、端口写错、时区没设这三类错误占了JDBC连接失败原因的一大半。3. 手写一个JDBC工具类从DriverManager到PreparedStatement3.1 标准六步流程的完整代码环境准备好之后直接上一段完整的JDBC查询代码。很多教程喜欢把代码拆成片段这对新手不友好我建议先把完整版本看完再去理解每一部分的作用。假设数据库里有张user表字段为id、username、password现在要写一个方法按用户名查询用户信息import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class JdbcDemo { public static void main(String[] args) { String url jdbc:mysql://localhost:3306/mydb?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; String user root; String password 123456; Connection conn null; PreparedStatement ps null; ResultSet rs null; try { // 1. 加载驱动MySQL 8.x使用cj驱动类 Class.forName(com.mysql.cj.jdbc.Driver); // 2. 获取连接 conn DriverManager.getConnection(url, user, password); // 3. 创建PreparedStatement并使用占位符 String sql SELECT id, username, password FROM user WHERE username ?; ps conn.prepareStatement(sql); ps.setString(1, admin); // 4. 执行查询 rs ps.executeQuery(); // 5. 处理结果集 while (rs.next()) { int id rs.getInt(id); String username rs.getString(username); String pwd rs.getString(password); System.out.println(id id , username username , password pwd); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { // 6. 释放资源先关ResultSet再关Statement最后关Connection try { if (rs ! null) rs.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (ps ! null) ps.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (conn ! null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }这段代码分六步走每一步我展开说下要注意的细节。加载驱动用的是Class.forName它会触发驱动类的静态初始化让驱动自行注册到DriverManager。这一步在MySQL 5.x和8.x之间有类名差异上面已经提过。DriverManager.getConnection则是根据URL中的协议头jdbc:mysql去找已注册的驱动然后建立真实连接。3.2 为什么必须用PreparedStatement而不是Statement你会发现我用的不是Statement而是PreparedStatement这是有意为之原因有三点每一点都值得你写进笔记里。第一性能。PreparedStatement创建时会把SQL语句先发送到数据库做预编译之后执行时数据库只需要接收参数值不用重新解析整条SQL。在循环里反复执行同一条SQL时这个性能优势会被明显放大。Statement则每次executeQuery都要完整经历一次SQL解析和编译高并发场景下数据库压力大。第二安全。PreparedStatement使用?占位符绑定参数参数值会被当作纯数据传给数据库而不是被拼进SQL字符串里。这一特性直接杜绝了SQL注入攻击。如果使用Statement拼字符串用户输入的内容可能改变SQL语义非常危险。第三代码可读性。SQL语句和参数分离动态值的位置一目了然后续维护时改条件、加字段都很直观。比如上面代码里setString(1, admin)看到1就明白它对应第一个问号不容易混乱。3.3 资源释放的正确顺序与代码优化上面finally里的释放操作写法很标准但过于冗长。从Java 7开始引入了try-with-resources语法可以在try块结束时自动关闭实现了AutoCloseable接口的资源代码可读性提升了很多推荐你现在就切换到这种写法try (Connection conn DriverManager.getConnection(url, user, password); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { // 处理逻辑 } } catch (SQLException e) { e.printStackTrace(); }这个写法虽然简洁但你心里必须清楚关闭顺序自动关闭顺序和声明顺序相反也就是先关ResultSet再关PreparedStatement最后关Connection。官方推荐先关结果集和语句再关连接这样的顺序能避免内存中堆积垃圾对象尤其是ResultSet内部持有对数据库游标的引用不及时关闭会在数据库端占资源。3.4 把重复代码封装成工具类把上面代码仔细看一遍就能发现加载驱动、获取连接、释放资源这三步在每一个数据访问操作里都是重复的。实际项目里不可能在每个DAO方法里都写一遍DriverManager.getConnection。合理的做法是抽出一个工具类把连接和关闭封装起来import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/mydb?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(ResultSet rs, Statement stmt, Connection conn) { // 依次关闭每个都单独try避免一个关闭失败影响后续 } }静态代码块会在类第一次被加载时执行一次驱动注册不需要每次连接都调用Class.forName。URL、用户名、密码统一放在常量里将来换环境只需要改一处。再进一步把工具类的参数都改成从properties文件读取就可以在不同开发环境之间无缝切换这也是生产项目里的通用做法。到了这一步你已经能感受到封装的意义了。真实项目中数据访问层几乎不会直接写裸的JDBC代码而是会包一层DAOData Access Object把按用户名查用户这样的操作封装成UserDao.findByUsername(String username)方法Servlet层只调用这个方法完全感知不到底层SQL的存在。这样的分层思想在后续学习MyBatis时会反复遇到。4. JDBC实战中必踩的坑乱码、时区、连接泄漏4.1 中文乱码从URL参数到数据库字符集的层层排查JDBC开发中中文乱码是出现频率最高的问题之一而且它不像编译报错那样有明确提示数据写进去读出来就是一堆问号或者奇怪的字符。乱码产生的原因通常不止一处需要按链路逐段排查。第一段链路是连接层面。JDBC客户端和MySQL服务器之间传输数据两端要约定相同的字符编码。客户端这边由连接URL的characterEncodingutf8指定服务器那边由MySQL配置文件里的character_set_server决定。这两者不一致写进去和读出来的数据就可能变形。第二段链路是存储层面。MySQL建表时需要指定字符集。有人建表时不指定继承了库级别的默认字符集如果默认是latin1中文必然乱码。推荐在建库和建表时显式指定utf8mb4这是MySQL里能存完整Unicode字符的字符集比utf8覆盖范围更广CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL, password VARCHAR(50) NOT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;排查乱码时先别急着改Java代码先用MySQL命令行工具直接插入一条中文记录再查询出来看看。如果命令行下中文显示正常那问题基本出在JDBC连接参数的编码设置上如果命令行下就是乱码那优先级最高的是数据库创建时的字符集配置。这个排查顺序能帮你快速缩小问题范围而不是盲目地在代码里加各种转换。4.2 SQL注入用一次攻击演示说明PreparedStatement的必要性我知道很多初学者对SQL注入的理解停留在听说过很危险的层面没有亲眼见过所以总觉得用Statement拼字符串也没什么。这里我用一个最简单的模拟场景演示一下。假设登录方法这样写String sql SELECT * FROM user WHERE username inputUsername AND password inputPassword ; stmt conn.createStatement(); rs stmt.executeQuery(sql);用户在用户名输入框里填入 OR 11此时拼接出来的SQL变成SELECT * FROM user WHERE username OR 11 AND passwordxxx由于OR的优先级低于AND11这个条件强制整个WHERE为真这条查询返回了表中第一行数据。如果你的登录逻辑是查到记录即认为登录成功攻击者不需要知道任何账号密码直接绕过登录。这只是最基础的注入方式真实世界中通过拼接SQL甚至可以删表、拖库。PreparedStatement的占位符方案解决的就是这个问题。参数值被作为字符串字面量传输传入的 OR 11不会参与SQL语句解析数据库只会把它当作一个普通字符串和表中的username字段做比较。安全实现里这套防线一道都不能省。4.3 连接不释放和MySQL的wait_timeout还有一个隐蔽的坑隐藏得特别深连接泄漏。前面我说过finally里要关闭Connection但很多人在写代码时尤其是正常路径能跑通就完事的情况下会把close()这一步随意省掉。测试时一个连接不关数据库也没意见。但生产环境里每次请求都开一个新连接且不关闭连接数会以肉眼可见的速度增长直到数据库max_connections被耗尽新请求全部排队等待系统表现为整体假死。即使你认真写了close()还有一种情况容易忽略程序运行到某个分支时报异常提前return了close()置在return之后根本没执行到。解决这类隐患的关键是把close()放到finally里或者使用try-with-resources。因为finally块无论如何都会执行只有这样才能确保连接能被归还。另外MySQL还有一个默认参数wait_timeout默认值为8小时。如果一条连接超过8小时没有任何操作MySQL服务器会主动断开这条连接。你的程序如果持有连接池里长时间空闲的连接下次使用时就会报Connection has been closed或Communications link failure这类错误。这个问题的经典解法后面会说——用连接池和定期检测机制。5. 往深处走一步事务处理和连接池5.1 手动管理事务转账场景下的commit与rollback单条SQL的增删改查JDBC用起来很直接。但真实业务里经常出现一组SQL必须同时成功或同时失败的情况。最经典的例子是转账A账户扣1000元B账户加1000元。如果第一步执行成功、第二步执行失败钱就从系统中凭空消失了这是绝对不能接受的。JDBC里的Connection默认是自动提交模式autoCommit为true每条SQL执行完立即提交没有回头路可走。要组合多条SQL为一个原子操作你需要手动关掉自动提交自己控制事务边界Connection conn null; PreparedStatement ps1 null; PreparedStatement ps2 null; try { conn DBUtil.getConnection(); // 关闭自动提交开启事务 conn.setAutoCommit(false); String sql1 UPDATE account SET balance balance - 1000 WHERE account_id 1; String sql2 UPDATE account SET balance balance 1000 WHERE account_id 2; ps1 conn.prepareStatement(sql1); ps1.executeUpdate(); ps2 conn.prepareStatement(sql2); ps2.executeUpdate(); // 两条SQL都成功了统一提交 conn.commit(); } catch (SQLException e) { // 任何一条SQL失败回滚全部操作 try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); } finally { // 释放资源并把连接恢复为自动提交模式方便连接池复用 try { if (ps1 ! null) ps1.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (ps2 ! null) ps2.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (conn ! null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } }这段代码里有几个细节需要格外注意。setAutoCommit(false)要放在所有SQL执行之前必须在获取连接之后第一时间调用。commit()代表整个事务成功rollback()代表整个事务作废。finally里关闭连接之前最好把autoCommit恢复为true因为很多连接池在归还连接时不会自动重置提交模式万一连接复用时autoCommit还是false后续执行SQL就不会自动提交数据迟迟写不进库这是个特别容易让人抓狂的坑。5.2 为什么生产环境必须用连接池而非每次新建连接前面反复提到生产环境连接不够用那么正规的解法是什么答案是连接池。核心思想直白得很不要每次访问数据库都创建一个崭新的物理连接用完就丢。而是预先创建一批连接放在池子里程序需要时从池子里取一条用完归还而不是关闭下次请求来了继续复用同一条连接。为什么要这样做因为从零建立一个JDBC连接背后涉及TCP握手、MySQL认证、权限校验等一系列开销在并发量大的时候这部分开销能占掉响应时间的一大部分。用连接池后这部分成本就被摊薄到无数次请求中了。实际项目里主流的连接池有HikariCP、Druid、C3P0等。Spring Boot 2.x之后默认集成的是HikariCP它以极快的速度著称。Druid因为有监控界面和SQL防火墙在国内很多团队也很受欢迎。如果你只想在本地把几个关键参数调明白以Druid为例参数名推荐值含义initialSize5启动时初始化的连接数minIdle5池中最小空闲连接数maxActive20池中最大活动连接数maxWait60000请求连接时最大等待毫秒数超过则抛异常validationQuerySELECT 1检测连接是否有效的SQL合理设置这几个值的依据在于maxActive取决于你的应用并发量和数据库性能设得太小会排队设得太大数据库本身扛不住。initialSize和minIdle设成一致可以避免高峰期频繁创建新连接。maxWait设置等待超时防止系统无休止地阻塞下去。5.3 从JDBC到框架MyBatis到底帮你做了什么文章已经接近尾声我想特别聊一下框架和JDBC的关系。现在培训班和学校上来就教MyBatis、Spring Data JPA很多同学学完框架之后连一条SQL是怎么从Java代码走到数据库的链路都说不清楚。一旦遇到框架报错就完全抓瞎。实际上MyBatis这类ORM或半ORM框架本质上只是在你和JDBC之间加了一层封装。它帮你完成了SQL语句的解析、参数的绑定、结果集到JavaBean的自动映射但底层走的仍然是Class.forName加载驱动、DriverManager获取连接、PreparedStatement执行SQL、ResultSet遍历结果这一整套JDBC流程。你可以做一个自己装一个轻量级的MyBatis替代品核心就是把上面工具类和反射结合起来只不过框架替你把这些细节封装得更优雅。所以我的建议是哪怕你以后的项目全部用框架也不要跳过我上面写的Hand-on JDBC代码环节。亲手写一遍六步流程亲手排查一次乱码亲手感受一次不关连接带来的后果你在框架世界里遇到诡异问题时的排查能力会强很多。框架解决的是效率问题基本功解决的是生存问题。动手建议打开你的IDE建一张学生表写一个DBUtil再写一个StudentDao用JDBC完成增删改查最后加上一个转账事务的案例。这一套流程走完Web开发里的数据访问这一环就算正式过关了。
RELATED

相关推荐

Spring Boot预约系统实战:数据模型、并发防超卖与权限设计

Spring Boot预约系统实战:数据模型、并发防超卖与权限设计

上个月帮当地一家旅行社把导游预约管理从Excel表格搬到线上系统,从需求沟通到部署上线大概花了两周。整个项目基于Spring Boot框架,做的就是在线导游预约系统,数据层用MyBatis加MySQL,热点数据放了Redis,权限用的是Spr…

📅 2026/10/9 3:27:19
SpringBoot与微信小程序:个性化服装搭配推荐系统部署实战

SpringBoot与微信小程序:个性化服装搭配推荐系统部署实战

如果你正在做一个Spring Boot 微信小程序的毕设项目,或者想快速上手“小程序 后端接口”这套组合拳,那么这个标题里提到的“个性化服装搭配推荐”项目,基本能把一条完整的技术链路给你串起来。它不是单纯教你写几个CRUD接口,而是…

📅 2026/10/9 3:22:19
SSM+Vue教学日志管理系统毕设:从环境配置到答辩全攻略

SSM+Vue教学日志管理系统毕设:从环境配置到答辩全攻略

开题季刚过,又是一年中最热闹的毕设周期。今年问得最多的题目里,“SSMVue教学日志管理系统”至少出现了十几次。说句实话,这个题目能在“Spring Boot Vue”大行其道的今天依然坚挺,靠的不是噱头,而是实实在在的稳妥—…

📅 2026/10/9 3:22:19
MORE NEWS

更多资讯

📰

Agent-Reach 实战:CLI 驱动的 AI Agent 执行框架与工具调用

1. 从零认识 Agent-Reach:它到底解决什么问题第一次看到 Agent-Reach 这个名字,很多人会以为又是一个套壳的聊天机器人。实际用下来你会发现,它更像是一套给 AI Agent 装上“手脚”的中间层工具。简单说,Agent-Reach 是一个基于 C…

📰

Agent-Reach:AI Agent生产可用的关键触达能力,你了解吗?

这两年只要聊到 AI Agent,大家习惯性先比模型参数和推理能力,仿佛 prompt 调得越花,Agent 就越接近“智能”。但真正把 Agent 推上线、跑业务的人心里都清楚:模型只是大脑,Agent 能不能干活,还得看它能不能…

📰

万字长论文批量降AI:从全篇扫描到分章精修的完整流程

长文档的降AI处理,听起来像是应该放在论文写完以后再做的事,但我的实操经验正好相反:如果你写的是几万字、十几章的长论文,等到全文拼起来才发现“AI味”过重,那工作量几乎是灾难级的。我之前处理一篇五万多字的硕士论…

📰

单词拆分LeetCode 139:从动态规划到面试追问的完整拆解

LeetCode热题100刷到第82题,单词拆分(Word Break),这道题我太有印象了——去年面一家独角兽的时候被原题面过,当时只要求判断能否拆分,答完后面试官轻描淡写补了一句"那如果要求输出所有拆分方案呢&qu…

📰

栈算法核心:单调栈、表达式求值与回溯递归的实战指南

1. 先把栈的本质聊透:不只是“先进后出”栈这个数据结构,几乎所有写代码的人第一天就见过,但真正到算法题里能把它用明白的,其实不多。很多朋友问我“栈怎么刷题”,我的回答永远是:先把三个场景啃透&#x…

📰

JCache接口键不存在时get与put行为详解及避坑指南

后台总有读者在准备Java面试,问得比较多的一道"基础篇"题目就是今天要聊的:JCache(JSR-107)中 Cache 接口的 put 和 get 方法,在键不存在时到底是什么行为。题目确实只有一句话,但这句话背后牵出…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬