简介:《Java Web数据库系统应用开发与实例》配套包面向希望系统掌握Java Web与数据库开发的学习者,内容覆盖Servlet、JSP、JDBC、MVC设计模式、Tomcat部署以及SQL增删改查等核心知识,适合高校课程设计、毕业设计入门和自学者补齐项目经验。压缩包共884个文件,约222.5MB,以java与class源文件、jsp页面、js脚本、sql脚本、jar依赖、xml配置和avi操作视频为主,既保留可运行的工程素材,也提供便于理解开发流程的演示录屏。已有470人学习,说明其在Java Web入门与数据库应用方向具有一定参考价值。读者可借助源码梳理分层结构、数据库访问逻辑与页面交互关系,通过视频观察系统演示、Servlet作用及JSP应用部署过程,并围绕报表打印、用户认证、并发访问和SQL优化等问题进行排错与扩展练习,把零散知识点落实到可运行的Web系统上。整体目录按功能模块组织,便于对照学习与二次开发。
1. 一个 Java Web 数据库系统应用开发项目里,列表接口在测试环境 50ms,上线后偶发 3 秒超时,代码翻了三遍没发现问题,最后是连接池只有 5 个连接、事务里又套了一次远程调用。Java Web 数据库系统应用开发要解决的,就是这类从浏览器请求到 Controller、Service、Mapper,再到 SQL 执行和连接归还的完整链路问题。标题里的源码与视频只是学习材料,真正值钱的是把一条增删改查链路跑通,知道连接池、事务、索引、分页各自在哪一层发力。刚接触 Java Web 的开发者可以照着搭骨架,已经写过课程设计的人更适合拿它补齐参数、排查和上线边界。
2. 选型先定骨架:Servlet+JDBC、Spring Boot+MyBatis 还是 JPA
很多示例代码一上来就是一堆注解:@RestController、@Service、@Mapper,跑起来能查库,换一个环境就卡在驱动、连接池或者事务上。Java Web 数据库系统应用开发的骨架,先要定三件事:请求怎么进、SQL 怎么发、连接怎么还。Servlet+JDBC 是最原始也最透明的组合,适合看清 HTTP 到ResultSet的全过程;Spring Boot+MyBatis 把 SQL 留在 XML 或注解里,适合需要手写复杂查询的业务系统;Spring Boot+JPA 把单表 CRUD 压到 Repository,适合实体关系清晰、查询不绕的管理后台。选型不是比谁新,而是看团队能不能维护 SQL、能不能接受 ORM 的隐式行为。
2.1 三种常见组合的边界与适用场景
| 组合 | 适合的团队/场景 | 明显优势 | 容易翻车的点 |
|---|---|---|---|
| Servlet+JDBC | 课程设计、需要理解底层、SQL 量不大 | 依赖少,每一步可见 | 手写连接关闭、事务和分页,代码重复多 |
| Spring Boot+MyBatis | 中小业务系统、复杂查询多、需要调 SQL | SQL 可控,动态条件和分页好写 | XML 与接口容易错位,N+1 和慢 SQL 要自己盯 |
| Spring Boot+JPA | 管理后台、单表为主、实体关系清晰 | 开发快,移植性好 | 懒加载、级联、隐式更新容易出问题 |
我的建议是:标题里带“数据库系统应用开发与实例”,优先选 Spring Boot+MyBatis。它既能让你看到 SQL,又不会把连接管理、参数绑定、事务切面全部摊在手写代码里。下面的最小工程按这个组合搭,数据库用 MySQL,连接池用 Spring Boot 默认的 HikariCP。版本号按你本地仓库可用的版本替换,不要为了追新把依赖树搅乱。
2.2 用依赖表定下最小工程
先把依赖压到最少。Web 入口、MyBatis、MySQL 驱动、测试四个就够,日志和连接池由 starter 带进来。不要一开始加分页插件、代码生成器、多数据源,这些会掩盖字段映射和 SQL 本身的问题。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.5</version> </parent> <groupId>com.example</groupId> <artifactId>demo-db</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>17</java.version> </properties> <dependencies> <!-- Web 入口,提供内嵌 Tomcat 和 MVC --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis 与 Spring Boot 的整合,版本按本地仓库替换 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> <!-- MySQL 驱动只在运行期需要 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- 测试用,后面 MockMvc 会用到 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>spring-boot-starter-parent负责统一依赖版本,mybatis-spring-boot-starter把SqlSessionFactory、Mapper 扫描和事务整合到一起,mysql-connector-j的runtime作用域表示编译期不直接依赖驱动类。不要把mybatis-spring-boot-starter和单独的mybatis混着加,容易出现版本冲突;也不要在 Web 层直接引DataSource,连接池应该由 Spring 容器管理。
2.3 建一个能启动的 Spring Boot + MyBatis 工程
配置文件里先把数据源、连接池和 MyBatis 的映射规则写清楚。连接串中的useUnicode、characterEncoding、serverTimezone三个参数不要省,尤其是跨时区部署时,时间字段差 8 小时往往就是这里漏了。
server: port: 8080 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/demo_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: demo password: demo driver-class-name: com.mysql.cj.jdbc.Driver hikari: maximum-pool-size: 10 minimum-idle: 2 connection-timeout: 3000 idle-timeout: 600000 max-lifetime: 1800000 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.demo.domain configuration: map-underscore-to-camel-case: truemaximum-pool-size不是越大越好,数据库连接数、应用实例数、慢查询时长要一起算。假设数据库max_connections=200,应用有 4 个实例,每个实例 30 个连接,就接近上限;再留出运维连接,通常每个实例 10 到 20 个更安全。connection-timeout设 3000ms,让拿不到连接的请求快速失败,而不是堆在 Tomcat 线程里。max-lifetime要小于数据库的wait_timeout,常见做法是设 1800000ms,避免连接被数据库单方面断开。map-underscore-to-camel-case把order_no映射到orderNo,省掉大量resultMap。
@SpringBootApplication @MapperScan("com.example.demo.mapper") public class DemoDbApplication { public static void main(String[] args) { SpringApplication.run(DemoDbApplication.class, args); } }@MapperScan指定 Mapper 接口所在包,避免每个接口都写@Mapper。启动命令用:
mvn spring-boot:run启动失败时先看三处:驱动类是否加载、URL 是否连到正确库、用户名密码是否有权限。Communications link failure多半是地址或端口不对,Access denied是账号权限问题,Unknown database是库还没建。不要急着改连接池参数,先把这三类错误排掉。
3. 把表建对:从 ER 图到建表 SQL 的四个约束
表结构是数据库应用的黑匣子:接口慢、事务不回滚、金额对不上,最后往往回到字段类型和索引。下面用客户、订单、订单明细三张表做最小模型,够跑通主从表写入和分页查询。四个约束分别是:主键与自增、金额用定点数、时间保留毫秒、索引和唯一约束按查询路径建。
3.1 用户-订单-订单明细三张表的最小 ER 设计
关系很简单:一个客户多个订单,一个订单多条明细。客户表放id、name、phone、created_at;订单表放id、order_no、customer_id、status、amount、created_at;明细表放id、order_id、product_name、price、quantity。金额一律用DECIMAL(18,2),不要用FLOAT或DOUBLE,否则对账时会出现0.30000000000000004这种尾差。时间用DATETIME(3),保留毫秒,方便排查同一秒内的并发写入。主键用BIGINT UNSIGNED AUTO_INCREMENT,订单号另加唯一索引,手机号也加唯一索引。
3.2 建表 SQL:主键、唯一索引、金额类型、时间字段
CREATE DATABASE IF NOT EXISTS demo_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; USE demo_db; CREATE TABLE customer ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', name VARCHAR(64) NOT NULL COMMENT '客户名', phone VARCHAR(32) NOT NULL COMMENT '手机号', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (id), UNIQUE KEY uk_customer_phone (phone) ) ENGINE=InnoDB; CREATE TABLE orders ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', order_no VARCHAR(32) NOT NULL COMMENT '业务订单号', customer_id BIGINT UNSIGNED NOT NULL COMMENT '客户主键', status TINYINT NOT NULL DEFAULT 0 COMMENT '0待支付 1已支付 2已取消', amount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '订单金额', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (id), UNIQUE KEY uk_orders_order_no (order_no), KEY idx_orders_customer_created (customer_id, created_at), CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customer(id) ) ENGINE=InnoDB; CREATE TABLE order_item ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', order_id BIGINT UNSIGNED NOT NULL COMMENT '订单主键', product_name VARCHAR(128) NOT NULL COMMENT '商品名', price DECIMAL(18,2) NOT NULL COMMENT '单价', quantity INT NOT NULL DEFAULT 1 COMMENT '数量', PRIMARY KEY (id), KEY idx_order_item_order (order_id), CONSTRAINT fk_order_item_order FOREIGN KEY (order_id) REFERENCES orders(id) ) ENGINE=InnoDB;utf8mb4能存 emoji 和生僻字,utf8mb4_0900_ai_ci是 MySQL 8 常见排序规则,MySQL 5.7 换成utf8mb4_general_ci。订单表的(customer_id, created_at)联合索引是按“查某个客户的订单,按时间排序”设计的,最左前缀是customer_id,不要把它拆成两个单列索引。外键在演示项目里能帮你发现脏数据,但在高并发写入场景常被去掉,改由应用层校验;不要一边用外键一边在代码里假设数据库不会报错。明细表的order_id索引必须有,否则按订单查明细会走全表扫描。
3.3 连接池与事务参数:HikariCP 与 @Transactional 的常用配置
事务不要写在 Controller 里,也不要包住远程调用。下面是一个创建订单的 Service,主表插入后拿到自增主键,再批量插入明细,两步在同一个事务里。
@Service public class OrderService { private final <p> <a href="https://download.csdn.net/download/xmt1139057136/10766985" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>