Java EE 企业应用 17:连接池与数据库连接预算
请求越来越多,数据库却只收到少数连接 采购高峰时有三十个 HTTP 请求同时进入用例,如果只给数据库开很少的连接名额,一部分请求要等待,有些可能超时。继续增加 HTTP 线程不会凭空增加数据库处理能力;把池上限调大则可能耗尽 PostgreSQL 接受连接的预算。这个问题关乎队列、持有时间和失败恢复,不是“服务器开了 jdbc-4.3 功能”就能推断的性能结论。本篇在 Open Liberty 26.0.0.5、Java 21、PostgreSQL 16.15 的版本范围内提出可测条件,不把任何未采集的延迟或吞吐说成实测。 本篇源码、迁移、脚本与测试可从固定版本完整归档取得;版本 20261005-local(基于 1b08ada),SHA-256 见源码清单。 借用、使用与归还是三段不同时间 真实配置 examples/javaee-enterprise/deploy/server.xml 有一个 jndiName="jdbc/Procurement" 数据源及驱动库,绑定本机 127.0.0.1 的教学实例,没有显式设置 connectionManager...
Java EE 企业应用 16:Schema 迁移与应用版本窗口
新 WAR 启动正常,旧申请为什么仍读不了 采购系统部署新版本时,代码可能开始读取旧库没有的列;也可能先删掉某列,正在处理请求的旧 WAR 随即失败。两种错误都无法通过空库上一条建表脚本验证。当前工程确有 examples/javaee-enterprise/db/migrations/001-initial.sql,但没有迁移执行器、版本表或从旧 schema 升级的脚本。说清这点之后才能讨论升级合同:从空库建立初始表是一种实验;保持旧应用在扩展期间可工作、最终删除旧结构,是另一种实验。 本篇源码、迁移、脚本与测试可从固定版本完整归档取得;版本 20261005-local(基于 1b08ada),SHA-256 见源码清单。 初始脚本保护了哪些数据 001-initial.sql 建三张表:purchase_request 保存租户、版本、状态及 numeric(18,2) 总额;purchase_line 用外键关联申请,规定 SKU、价格、数量;purchase_order.request_id 设唯一且引用申请。申请的状态枚举值受 CHECK 限制,总额与单价不为负、数...
Java EE 企业应用 15:稳定排序、索引与分页怎样配合
第一页有二十条,第二页为什么又出现同一张申请 采购审批列表按租户和状态筛选,用户在浏览第一页时,另一位申请人又提交一张申请。如果查询只写 LIMIT 20 OFFSET 20 而没有确定的排序,第二页可能重复或漏掉行;即使加了排序,数据在两次请求之间变动也可能改变偏移边界。这是查询的契约问题,不是把页面大小调大就能解决。例子仍以 PostgreSQL 16.15、Java 21 与现有 JDBC 采购工程为背景。本章设计一个尚不存在的列表入口;仓库的 JdbcRequestStore 只有按 ID 和租户读取申请及明细的方法,没有分页接口或可归档的列表请求结果。 本篇源码、迁移、脚本与测试可从固定版本完整归档取得;版本 20261005-local(基于 1b08ada),SHA-256 见源码清单。 列表的单位是申请,不是 JOIN 后的明细行 当前 db/migrations/001-initial.sql 为 purchase_request 建立 (tenant_id, status, id) 索引;purchase_line 按 request_id 外键关联。若业务页...
Java EE 企业应用 14:DAO 接口不能替事务做决定
一张订单插入成功,申请仍停在已批准怎么办 采购用例从 APPROVED 到 ORDERED 要做两件事:写订单、更新申请状态。如果第一条 SQL 成功、第二条因版本冲突失败,最终可能留下订单和申请状态不一致。为每个 SQL 都写一个 DAO 方法,不能自动把两个方法合为一次数据库事务。第 13 篇说明参数和结果如何映射;本章关注 DAO 负责哪一段、调用者负责哪一段,以及在受管 Jakarta EE 11 环境下怎样追踪。先修是能区分请求返回、JDBC 连接关闭和事务提交。 本篇源码、迁移、脚本与测试可从固定版本完整归档取得;版本 20261005-local(基于 1b08ada),SHA-256 见源码清单。 端口描述用例所需的动作,适配器承受 SQL 细节 examples/javaee-enterprise/application/src/main/java/blog/javaee/application/RequestStore.java 是业务侧使用的存储接口;同模块的 ProcurementUseCases.java 从 store.find(id, tenantI...
Java EE 企业应用 13:SQL 参数、类型与行映射的边界
订单编号返回了,申请明细真的写对了吗 两份纸品和三支笔应该合计 13.75。采购 HTTP 入口若只返回一个申请 ID,仍有几种可能:金额在数据库被截断、明细没入库、租户值写错,或者状态更新找不到原行。检查这些问题不能只读插入方法的返回值。第 12 篇处理连接和语句的归还;这一篇沿着 examples/javaee-enterprise/adapters-jdbc/src/main/java/blog/javaee/jdbc/JdbcRequestStore.java 检查参数、返回行和对象重建。冻结环境为 Java 21、pgJDBC 42.7.7、PostgreSQL 16.15 与通过 jdbc/Procurement 提供连接的 Jakarta EE 11 服务器。 本篇源码、迁移、脚本与测试可从固定版本完整归档取得;版本 20261005-local(基于 1b08ada),SHA-256 见源码清单。 SQL 结构固定,数据从参数槽进入 JdbcRequestStore.insert 的申请 SQL 把 tenant_id、status、total 放入 ? 槽,通过...
Java EE 企业应用 12:JDBC 资源从借用到归还
查询已经返回,连接为什么仍可能占着池 采购申请读取一份申请时,会先查申请行,再查商品明细。响应正常并不能说明两次查询使用的语句、结果集和连接都已归还;一旦读取明细中途出错,资源释放路径尤其容易遗漏。读者可以先检查一个具体问题:如果 ResultSet.next() 抛出异常,关闭的是哪个对象,关闭失败会不会掩盖查询失败?这里讨论的是 JDBC 借用和关闭,不是审批状态正确性。示例采用 Java 21、Jakarta EE 11、Open Liberty 26.0.0.5、pgJDBC 42.7.7 与专用 PostgreSQL 16.15 javaee_lab。JDBC 的 java.sql 和 javax.sql 属于 Java SE;不要将 javax.sql.DataSource 改成 jakarta.sql。 本篇源码、迁移、脚本与测试可从固定版本完整归档取得;版本 20261005-local(基于 1b08ada),SHA-256 见源码清单。 DataSource 是入口,Connection 是一次借用 服务器配置 examples/javaee-enterpri...
Java EE 企业应用 05:服务器资源与受管调用契约
WAR 能启动,不等于资源能用 采购用例通过存储端口访问数据库。开发机上能用 DriverManager 建立连接,不表示部署后的 WAR 已经使用服务器管理的数据源;健康端点能返回 ready,也不表示每个采购调用都拿到了连接。如果数据库口令、驱动 JAR 和连接池配置各自散落在业务类里,重启、更换配置以及追踪失败会变得困难。应用服务器提供组件环境、资源引用和受管调用路径,代价是必须区分:声明了什么、服务器映射了什么、实际调用经过了什么。 本篇源码、迁移、脚本与测试可从固定版本完整归档取得;版本 20261005-local(基于 1b08ada),SHA-256 见源码清单。 累计工程中,examples/javaee-enterprise/deploy/server.xml 是 Open Liberty 26.0.0.5 的实验配置,开启 jakartaee-11.0 和 jdbc-4.3,注册 pgJDBC 42.7.7 驱动库,并把名为 jdbc/Procurement 的服务器数据源指向独立的 javaee_lab 库。examples/javaee-enterpri...
Java EE 企业应用 04:CDI 如何创建、选择与销毁对象
一个请求要用哪一份对象 采购系统的用例服务要取得价格目录与存储端口。创建一个 ProcurementUseCases 并传入两个实现,看起来已经解决装配问题;但在 Web 应用中,还要回答目录由谁选、服务活多久、每个请求是否拿到同一份可变数据,以及结束时谁关闭它持有的资源。仅从构造函数的参数类型,回答不了这些问题。尤其不能把“类上有注解”当成“容器已经创建过对象”的证据。 本篇源码、迁移、脚本与测试可从固定版本完整归档取得;版本 20261005-local(基于 1b08ada),SHA-256 见源码清单。 累计工程的真实入口位于 GitLab 仓库路径 examples/javaee-enterprise/application/src/main/java/blog/javaee/application/ProcurementUseCases.java。目前该类使用 @ApplicationScoped、@Inject 构造函数与 @Transactional;FixedPriceCatalog 是唯一的 PriceCatalog 实现。另一个真实装配点是 examples...
JPA 持久化 08:Schema 迁移与集成测试的证据边界
新实体能启动,旧订单未必安全 假设申请实体新增 @Version。新库按映射生成表,插入、查询全部通过;生产旧库却没有 version 列。另一个风险更隐蔽:表和列都在,但 purchase_order.request_id 上没有唯一约束,双重建单在并发时才暴露。两种故障分别属于映射与库结构不匹配、业务约束缺失。把“Provider 启动成功”当成“迁移完成”,会同时漏掉数据搬迁、约束和上线顺序。采购审批里的金额、租户与订单唯一性,不能只交给 Java 注解;它们要在现存行、DDL 和事务测试之间取得一致。 本篇源码、迁移、脚本与测试可从固定版本完整归档取得;版本 1b08ada,SHA-256 见源码清单。 本章以 Jakarta Persistence 3.2、Hibernate ORM 7.1.36.Final、PostgreSQL 16、Java 21 的 examples/jpa/ 为入口。实体映射与测试源码已存在;仅有 db/migrations/01-init.sql 一份初始化脚本,没有旧库升级链,也没有“08 专属迁移测试套件”。PostgreSQL 16.1...
Java EE 企业应用 08:会话怎样保存登录态并处理并发请求
看到 active 就是已经登录了吗 采购审批页在两次 HTTP 请求之间要识别用户。浏览器带回一枚会话 Cookie,服务器据此查找 HttpSession,页面显示“仍在会话中”。可是当前工程的演示端点只往 Session 写一个随机 labNonce:没有核验用户名、口令、角色,也没有把身份关联到租户。把 active 当作“能批准该租户的采购申请”,等于让一段随机状态替代认证与对象权限。第 24–26 篇完成认证之前,Session 在本篇只是一种 Web 生命周期实验,不是安全机制已经上线的证据。 本篇源码、迁移、脚本与测试可从固定版本完整归档取得;版本 20261005-local(基于 1b08ada),SHA-256 见源码清单。 工程的 LabSessionServlet.java 映射 /servlet/lab-session,代码试图用 JAVAEE_DEMO_MODE=true 和回环地址限制入口;部署的 server.xml 只监听 127.0.0.1。Servlet 在拒绝路径调用 sendError 后又依赖 response.isCommitted...










