资讯中心

基于Java+SpringBoot+SSM的养老院管理系统:从架构到部署全解析

📅 2026/9/24 23:42:22
基于Java+SpringBoot+SSM的养老院管理系统:从架构到部署全解析
“基于JavaSpringBootSSM的养老院管理系统”这个名字我太熟了不管是课程设计、毕业设计还是刚入职的技术练手项目它几乎是Java后端入门绕不开的一个经典整合案例。你拿到手的第一反应可能是SSM 和 SpringBoot 不是两套东西吗怎么标题里写在一起了别急这正是这套项目最有意思的地方——它用 SpringBoot 作为底座骨架把 Spring、SpringMvc、MyBatis 三件套按 SSM 的组织方式串起来既保留了传统 SSM 项目的分层习惯又享受了 SpringBoot 自动配置带来的便利。整套系统围绕养老院日常管理展开涵盖老人档案、入院登记、护理记录、床位分配、费用收缴、家属沟通这些核心业务属于非常典型的管理信息系统MIS项目。如果你正准备拿它做毕设、课程设计或者想通过一个完整项目把 JavaWeb 的知识点串起来这篇文章能让你少走不少弯路从架构思路、数据库设计到代码落地、部署调试一次性讲透。1. 项目整体设计与技术选型1.1 为什么是 SpringBoot SSM而不是二选一很多初学者一看到“SpringBoot SSM”这个组合就犯迷糊觉得这俩是竞争关系。其实 SpringBoot 和 SSM 压根不是一个维度上的东西SSM 是 Spring SpringMVC MyBatis 三套框架的组合方案解决的是“业务代码怎么写、请求怎么分发、数据库怎么访问”的问题而 SpringBoot 是一个快速开发脚手架解决的是“框架之间怎么配置、依赖怎么管理、项目怎么启动”的问题。两者结合等于用 SpringBoot 的自动配置把 SSM 的传统配置全部接管了你不需要再去写 hundreds 行的 XML 配置文件但代码的组织方式依然是经典的 Controller-Service-Mapper 三层结构。我用这个组合的最大感受就是开发效率和代码可读性兼得。以前做 SSM 项目光 spring-mvc.xml、spring-mybatis.xml、web.xml 这些配置文件就能折腾一整天稍不注意版本冲突就给你抛一个 NoSuchMethodError。换成 SpringBoot 之后一个spring-boot-starter-web依赖就把 SpringMVC 和内置 Tomcat 全带进来了spring-boot-starter-jdbc配合mybatis-spring-boot-starter又把 MyBatis 的 SqlSessionFactory、事务管理器自动装配好我只需要在 application.yml 里写清楚数据源连接信息剩下的交给框架。当然做这种项目的时候也要注意SpringBoot 的自动配置虽好但不代表你不理解底层原理就能直接上手。面试官或者答辩老师大概率会追着问“SpringBoot 的自动配置是怎么实现的”、“SpringMVC 的执行流程是怎样的”、“MyBatis 的 #{} 和 ${} 有什么区别”这些问题恰恰是对 SSM 底层理解的考察。所以这套项目其实是一鱼两吃既能拿来当实际系统跑业务又能作为面试八股文的实战载体。1.2 技术栈全景与功能模块规划这套养老院管理系统我建议的技术栈方案如下表所示每一层的选型都有充分的理由。层次技术选型核心职责选型理由前端页面Thymeleaf Bootstrap jQuery页面渲染、表单校验、AJAX 交互前后端不分离学习成本低适合课程设计演示不必额外搭 Node 环境控制层SpringMVCController / RestController接收请求、参数绑定、返回视图或 JSONSSM 标准组成部分注解开发效率高业务层Spring Service业务逻辑处理、事务管理Transactional 声明式事务保证数据一致性持久层MyBatis / MyBatis-Plus数据库 CRUD、动态 SQL、分页灵活可控SQL 自己写答辩能讲清楚数据库MySQL 5.7 / 8.0业务数据存储开源免费、受众最广环境好配项目构建Maven依赖管理、打包Java 项目事实标准比 Gradle 更普及启动与部署SpringBoot 内置 Tomcat项目启动、请求监听打成 jar 包直接运行部署演示极其方便功能模块这块我围绕养老院真实业务场景拆成了七个模块这套划分方法不是凭空设计的而是参考了几家中小型养老机构的信息化需求后浓缩出来的系统管理用户登录、角色权限、操作员管理。一般是管理员、护工、前台三种角色。老人档案管理老人的基本信息、健康状态、入住日期、家属联系方式、紧急联系人。入院/退住管理办理入院登记、分配床位、办理退住并释放床位资源。护理记录管理每天的健康巡检记录、用药提醒、特殊护理事项。床位管理楼栋-楼层-房间-床位四级结构实时查看入住和空余状态。费用管理床位费、护理费、伙食费、医疗费的项目化记录和收缴状态。家属沟通与访客记录来访登记、电话沟通记录。这套模块规划还有一个好处它天然覆盖了增删改查、一对多关联、多条件查询、文件上传、权限拦截、事务处理这些JavaWeb必考核心点。每一个模块拿出来都可以单独扩展成一道面试题比如“老人入住时床位分配怎么保证并发下不冲突”“退住的时候关联的护理记录怎么处理”这些我在后面的章节都会展开讲。1.3 目录结构和工程分层设计我拿到源码之后第一步就是看工程目录结构。如果结构混乱后面加功能简直是一场灾难。这套项目比较规范的目录划分是这样的com.example.eldercare ├── ElderCareApplication.java // SpringBoot 启动类 ├── common/ // 通用返回结果、全局异常处理、工具类 │ ├── Result.java │ ├── GlobalExceptionHandler.java │ └── PageResult.java ├── config/ // 配置类如拦截器、跨域、MyBatis配置 ├── controller/ // 控制层按模块分包 │ ├── AdminController.java │ ├── ElderController.java │ ├── BedController.java │ └── ... ├── service/ // 业务层接口 ├── service/impl/ // 业务层实现 ├── mapper/ // MyBatis Mapper 接口 ├── entity/ // 数据库实体类 ├── dto/ // 数据传输对象承载页面提交的参数 └── resources/ ├── mapper/ // MyBatis XML 映射文件 ├── templates/ // Thymeleaf 模板页面 └── application.yml这里我想强调一点entity和dto一定要分开。很多课设项目图省事直接拿数据库实体类去接收前端表单参数结果页面提交的字段和数据库字段对不上要么报错要么多出一些莫名其妙的字段。我习惯的做法是凡是前端提交的数据一律用 DTO 接收查询返回给页面的数据如果需要关联多张表则自定义 VO。分层清晰之后即使业务复杂度上去了代码也依然好维护。2. 数据库设计是这类系统的灵魂2.1 核心业务表梳理与关系分析养老院管理系统听起来业务不复杂但表与表之间的关联关系比想象中多。我把核心表整理成下面这个清单你对照着看就能理解整个数据模型表名用途关键关联字段核心状态字段sys_user系统用户表无status启用/禁用elder_info老人基本信息表无status在住/退住elder_health_record老人健康档案表elder_id健康等级bed_info床位信息表building/floor/roomstatus空闲/入住/维修check_in_record入院登记表elder_id, bed_idstatus在住/已退住care_record护理记录表elder_id, operator_id护理类型fee_record费用记录表elder_idpay_status未缴/已缴visit_record访客登记表elder_id无family_contact家属联系表elder_id无从表关系上看elder_info是绝对的核心几乎所有业务表都通过elder_id与它关联。在数据库设计阶段我最关心三个问题老人和床位的对应关系怎么保证唯一、退住后的历史数据怎么保留、收费标准变化时费用记录怎么保持历史快照。第一个问题我在check_in_record表上建了唯一索引uk_elder_bed (elder_id, bed_id)并且规定同一时间只能有一条status1在住的入院记录。第二个问题老人退住不是物理删除elder_info的数据而是把状态改成“退住”同时将check_in_record的状态改为失效、床位改回空闲。这样历史的护理记录和费用明细还能完整查询。第三个问题费用表里除了记录金额还要冗余一份“费用项目名称”和“计费周期”避免以后改了收费标准历史账单跟着变动说不清。2.2 三张关键表的结构设计与字段说明我挑三张最具代表性的表展开讲一下字段设计思路这三张表搞明白了其他表举一反三就行。第一张是elder_info老人基本信息表我重点说几个容易忽略的字段。birth_date用 date 类型不要用 datetimehealth_level用 int 表示1-自理2-半自理3-不能自理不要用 varchar 存中文因为后续要根据健康等级统计护理费emergency_contact和emergency_phone虽然看起来和family_contact表重复但这是有意为之的冗余——紧急联系人必须跟着老人主表走哪怕家属变更了紧急联系渠道不能丢。还有一个字段remark很多同学不重视备注字段实际养老场景中非常关键比如“对海鲜过敏”“夜间需要两小时巡查一次”这些只能写在备注里。第二张是bed_info床位表。架构上我采用了楼栋-楼层-房间-床位四级结构building_no、floor_no、room_no、bed_no四个字段组合定位一个具体床位并建立唯一索引。很多简化版设计只有 room 和 bed 两个字段但养老院面积大、楼栋多没有楼栋和楼层标识系统的实用价值就大打折扣了。床位的状态我用一个status字段维护0表示空闲、1表示已入住、2表示维修中页面查询空余床位时直接WHERE status 0简单高效。第三张是care_record护理记录表。这张表算是系统的业务亮点字段包括elder_id关联老人、care_type护理类型、care_content护理内容、care_time护理时间、operator_id执行护工。设计时我刻意把care_time设计成 datetime 而不是 date因为养老院的护理是一天多轮的只有精确到时分才能追溯执行情况。同时care_type我用 int 字典值表示在 Java 枚举中维护映射避免数据库里存中文导致统计时编码问题频发。2.3 建表SQL中的几个细节技巧建表SQL我直接给出一段核心片段方便你直接参考。这里要注意几个细节字符集统一用 utf8mb4别用 utf8emoji 和特殊字符会乱码金额字段用 decimal(10,2) 而不是 float时间字段需要自动更新的用DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP。CREATE TABLE elder_info ( id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, elder_no VARCHAR(32) NOT NULL COMMENT 老人编号, elder_name VARCHAR(32) NOT NULL COMMENT 姓名, gender TINYINT(1) DEFAULT NULL COMMENT 性别 1男 2女, birth_date DATE DEFAULT NULL COMMENT 出生日期, id_card VARCHAR(18) DEFAULT NULL COMMENT 身份证号, health_level TINYINT(1) DEFAULT 1 COMMENT 健康等级 1自理 2半自理 3不能自理, emergency_contact VARCHAR(32) DEFAULT NULL COMMENT 紧急联系人, emergency_phone VARCHAR(20) DEFAULT NULL COMMENT 紧急联系电话, status TINYINT(1) DEFAULT 1 COMMENT 状态 1在住 0已退住, remark VARCHAR(500) DEFAULT NULL COMMENT 备注, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_elder_no (elder_no) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4 COMMENT老人基本信息表;这里的elder_no我特意加上了唯一约束并且建议你生成编号时用“入住日期 序列号”的方式比如EL20250115001这样在人工核验的时候一眼就能看出老人是什么时候入住的。ID 用BIGINT自增主键别用雪花ID课设项目没必要引入分布式ID的复杂度。3. 核心代码实现与业务闭环3.1 从启动类到数据访问层的完整串联代码层面我按“启动类 → 实体类 → Mapper → Service → Controller”的顺序来拆解整个调用链。这套项目用 SpringBoot 整合后启动类非常简单SpringBootApplication MapperScan(com.example.eldercare.mapper) public class ElderCareApplication { public static void main(String[] args) { SpringApplication.run(ElderCareApplication.class, args); } }MapperScan是 MyBatis 和 SpringBoot 整合的关键注解它告诉 Spring 去哪里扫描 Mapper 接口并生成代理对象。如果没有这个注解你就得在每一个 Mapper 接口上单独加Mapper代码会显得非常啰嗦。实体类我基于 MyBatis 的驼峰映射规则设计比如数据库字段elder_name对应实体属性elderName。同时在 application.yml 里必须开启驼峰映射配置mybatis: configuration: map-underscore-to-camel-case: true mapper-locations: classpath:mapper/*.xml不开启这个配置的话查询结果里elder_name是没法自动映射到elderName属性的返回给前端就是 null这是个特别容易踩的坑。3.2 关键业务入住登记与床位分配入住登记是养老院系统最核心的业务闭环之一。流程是前端提交老人基本信息和选择的床位 ID → 后端检查老人状态 → 检查床位是否为空 → 插入elder_info→ 插入check_in_record→ 更新床位状态为已入住。这个过程必须要加事务控制否则可能出现老人信息插入成功、床位状态没更新成功的情况那我就得花大量时间对账。事务控制的实现非常简洁在 Service 方法上标注Transactional即可Transactional(rollbackFor Exception.class) public Result checkIn(ElderCheckInDTO dto) { // 1. 校验老人是否存在以及是否已在住 ElderInfo elder elderMapper.selectById(dto.getElderId()); if (elder null) { return Result.error(老人信息不存在); } if (elder.getStatus() 1) { return Result.error(该老人当前已在住不能重复入住); } // 2. 校验床位状态 BedInfo bed bedMapper.selectById(dto.getBedId()); if (bed null || bed.getStatus() ! 0) { return Result.error(床位不存在或当前不可用); } // 3. 更新老人状态 elder.setStatus(1); elderMapper.updateById(elder); // 4. 创建入院记录 CheckInRecord record new CheckInRecord(); record.setElderId(elder.getId()); record.setBedId(bed.getId()); record.setStatus(1); checkInRecordMapper.insert(record); // 5. 更新床位状态 bed.setStatus(1); bedMapper.updateById(bed); return Result.success(); }这里有个细节Transactional(rollbackFor Exception.class)一定要写rollbackFor因为 Spring 默认只对 RuntimeException 回滚事务如果业务代码里抛的是自定义 Exception不加这个参数事务不会回滚数据就写一半了。3.3 多条件分页查询与模糊搜索养老院里老人多床位多护理记录更多分页查询几乎是每个列表页面都要用到的功能。我使用 MyBatis 官方推荐的 PageHelper 分页插件整合步骤就两行引入pagehelper-spring-boot-starter依赖然后在使用前调用PageHelper.startPage(pageNum, pageSize)。这里我特别想提醒一个 PageHelper 的经典陷阱PageHelper.startPage()只对紧随其后的第一条查询语句生效。也就是说你不能在调用startPage()之后执行其他无关查询或者赋值操作否则分页会作用到错误的 SQL 上。正确写法public PageResultElderVO getElderList(ElderQueryDTO query, int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); ListElderVO list elderMapper.selectElderList(query); PageInfoElderVO pageInfo new PageInfo(list); return new PageResult(pageInfo.getTotal(), pageInfo.getList()); }多条件模糊搜索的处理上我建议把查询条件封装成一个 QueryDTO里面包含elderName、healthLevel、status、startDate、endDate等字段然后在 XML 映射文件里用where加if标签动态拼接 SQLselect idselectElderList resultTypecom.example.eldercare.vo.ElderVO SELECT e.id, e.elder_no, e.elder_name, e.gender, e.birth_date, e.health_level, e.status, b.building_no, b.room_no, b.bed_no FROM elder_info e LEFT JOIN check_in_record cir ON e.id cir.elder_id AND cir.status 1 LEFT JOIN bed_info b ON cir.bed_id b.id where if testelderName ! null and elderName ! AND e.elder_name LIKE CONCAT(%, #{elderName}, %) /if if testhealthLevel ! null AND e.health_level #{healthLevel} /if if teststatus ! null AND e.status #{status} /if /where ORDER BY e.create_time DESC /selectCONCAT(%, #{elderName}, %)是防 SQL 注入的推荐写法千万别直接用%${elderName}%后者属于字符串拼接注入高危区面试被问 MyBatis 安全问题时这就是送分考点。3.4 登录认证与权限拦截养老院系统的用户分管理员、护工、前台等多种角色权限控制我用 SpringMVC 拦截器实现没有引入 Spring Security因为课设项目的权限模型相对简单引入 Security 反而增加了学习和演示负担。登录逻辑是这样的用户提交用户名/密码Controller 调用 Service 校验通过后把用户对象放入 Session。然后写一个LoginInterceptor实现HandlerInterceptor接口在preHandle方法中检查 Session如果为空则重定向到登录页。最后通过WebMvcConfigurer注册拦截器并配置排除路径比如/login、/static/**。public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user request.getSession().getAttribute(loginUser); if (user null) { response.sendRedirect(/login); return false; } return true; } }注册拦截器时静态资源排除是个重灾区。我刚开始做的时候忘记放行静态资源结果登录页的 CSS/JS 全被拦了页面白板一块。排查了半天才发现是拦截器的excludePathPatterns没写/static/**、/templates/**这些路径。4. 部署调试与常见问题排查实录4.1 本地环境准备与注意事项拿到源码之后第一步是在本地把环境跑起来。我建议按下面的顺序准备每完成一步就验证一步不要等全部装好再一次性启动不然出了问题都不知道是哪个环节坏了安装 JDK 1.8 或 11推荐 1.8兼容性最好很多学校的教学环境还是 JDK8。安装 MySQL 5.7 或 8.0本地开发强烈推荐用 8.0字符集和时区支持更好。安装 Maven 3.6并且配置阿里云镜像不然拉取依赖会慢到怀疑人生。用 IDEA 打开项目等待 Maven 自动导入依赖。修改 application.yml 里的数据库连接信息执行项目附带的init.sql初始化数据库。启动ElderCareApplication访问http://localhost:8080。关于数据库连接配置有两点必须提醒MySQL 8.0 的驱动类要从com.mysql.jdbc.Driver改成com.mysql.cj.jdbc.DriverURL 也建议加上serverTimezoneAsia/Shanghai和useSSLfalse参数否则项目启动时大概率会报时区错误或者 SSL 连接警告。spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/eldercare?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse username: root password: 1234564.2 打包部署的两种姿势课设验收的时候老师一般要求你现场演示运行。这里有两种部署方式jar 包方式最简单在 IDEA 终端执行mvn clean package -DskipTests然后去 target 目录下找到生成的 jar 包执行java -jar eldercare-0.0.1-SNAPSHOT.jar就能启动。第二种方式是打 war 包部署到外置 Tomcat这种场景一般出现在学校机房已经装好了 Tomcat 的情况下。这时候你需要做三件事启动类继承SpringBootServletInitializer并重写configure方法pom.xml 里的打包方式改成 warspring-boot-starter-tomcat依赖的 scope 设置为 provided。这三步缺一不可最常见的问题是忘记改打包方式打成 jar 之后硬塞进 Tomcat 的 webapps 目录启动必失败。4.3 高频报错与排查速查表我把实际操作中遇到的高频报错整理成了一个速查表你在开发和部署过程中碰到问题可以对照着排查报错现象根因分析解决方案Access denied for user rootlocalhost数据库用户名或密码错误检查 application.yml 配置注意 MySQL8 默认认证插件的问题Unknown database eldercare数据库没有创建先执行CREATE DATABASE eldercare DEFAULT CHARACTER SET utf8mb4Port 8080 was already in use端口被占用使用netstat -ano | findstr 8080找到进程杀掉或改端口Invalid bound statement (not found)Mapper 接口和 XML 映射不匹配检查 XML 中 namespace 是否和接口全限定名一致id 是否和方法名一致The server time zone value ... is unrecognizedMySQL 时区问题URL 增加serverTimezoneAsia/ShanghaiWhitelabel Error Page且日志无异常静态资源被拦截器拦截或模板路径错误检查拦截器 excludePathPatterns检查 Controller 返回的视图名是否有对应模板中文乱码字符集不统一检查数据库字符集、连接 URL 的characterEncodingutf8、前端页面 meta 标签Invalid bound statement是我见过最多的报错没有之一。绝大多数情况是 XML 文件没有在resources/mapper/目录下被扫描到。解决办法是检查 application.yml 里的mybatis.mapper-locations配置是否正确以及 XML 文件是否打包进了 target 目录。5. 答辩和面试中会被追问的高频问题5.1 技术原理类问题该怎么应答既然这套系统用了 SpringBoot SSM答辩和面试时你的知识储备至少要把这些问题答上来。我挑三个最常被问的展开讲你可以直接拿来做笔记。第一个是“SpringBoot 自动配置的原理是什么”。你要答到SpringBootApplication是一个复合注解核心是EnableAutoConfiguration它通过Import(AutoConfigurationImportSelector.class)去读取META-INF/spring.factories文件中的自动配置类列表再根据ConditionalOnClass、ConditionalOnMissingBean等条件注解做判断最终决定哪些配置要生效。比如DataSourceAutoConfiguration只有在 classpath 下存在javax.sql.DataSource时才会生效。第二个是“SpringMVC 的执行流程”。你要从 DispatcherServlet 开始讲请求先到 DispatcherServlet它通过 HandlerMapping 找到对应的 Controller 方法再由 HandlerAdapter 调用处理方法方法返回 ModelAndView视图解析器解析后渲染视图。回答时如果能带上“核心组件有哪些”这个维度会显得你理解更深。第三个是“MyBatis 的 #{} 和 ${} 的区别”。#{}是预编译处理会生成?占位符能有效防止 SQL 注入${}是字符串直接替换用在表名、列名、排序字段等不能占位符替换的场景。实际开发中能用#{}的地方绝不用${}但如果你要用${}做动态表名必须对输入值做白名单校验。5.2 业务设计类问题怎么答除了技术原理答辩老师还喜欢问业务设计上的考虑。比如“老人退住后之前的数据怎么处理”。这是一个很好的问题考察你对数据生命周期的理解。我当时的回答是退住时不做物理删除而是把老人状态改为退住同时将对应的入院登记记录状态置为失效、床位释放为空闲。老人历史的所有护理记录、费用记录、访客记录都通过elder_id关联保留后续如果需要给老人做健康分析或者统计历史数据都可以直接查出来。再比如“如果两个操作员同时为同一个老人办理入住会不会出问题”。这个问题对应了并发场景下如何保证数据一致性。我的处理思路是通过数据库唯一索引兜底在check_in_record表上对elder_id加一个当前在住状态下的唯一索引同时在代码里对床位状态做条件更新也就是UPDATE bed_info SET status 1 WHERE id ? AND status 0返回受影响行数如果为 0 说明床位已被抢走事务抛出异常回滚。这种乐观锁思路虽然简单但能解决绝大多数并发冲突。5.3 这个项目还可以怎么扩展进阶拿到一套能跑的课设项目不是终点如果想让它在简历上更有分量可以做一些低成本高显示度的扩展。我最推荐的三个方向第一个是引入 Redis 做缓存加速把老人基本信息、床位状态、费用标准这些读多写少的数据放在 Redis 里列表页的响应速度会有肉眼可见的提升。面试聊到这个点还能顺势聊到缓存穿透、缓存击穿、缓存一致性问题这些都是高频考点。第二个是增加 Excel 导入导出功能用 EasyExcel 把老人花名册、每月费用账单导出成 Excel 表格养老院管理人员对这种功能非常认可。技术上就是引入easyexcel依赖前端放一个导出按钮后端查数据然后写文件流返回。第三个是换成前后端分离架构把前端改成 Vue Element UI后端提供纯 JSON 接口。这个扩展的工作量大一些但也是含金量最高的方向做完之后你基本就掌握了当前企业开发的主流形态求职时的竞争力完全不一样。写在最后的一点心得我从拆解源码到重新自己动手实现这套养老院管理系统踩过不少坑最深的体会是不管项目名多大核心永远是把基础的数据流转搞清楚。老人信息怎么存、床位状态怎么维护、费用从生成到核销的状态变化把这几个核心链路打通了其他功能都是在这张网上补节点。这套项目适合两类人一类是急需一个能讲明白、能演示的课程设计或毕业设计项目的学生另一类是准备 Java 后端面试想找一个综合型项目做知识串联的求职者。前者重点看功能模块和部署演示后者一定要把底层原理和业务设计逻辑吃透尤其是自动配置原理、事务传播行为、MyBatis 动态 SQL 这些点。最后再分享一个小提示把项目的init.sql好好读一遍理解每一张表的字段含义比单纯会跑项目有用得多——数据库设计永远是这类管理系统的灵魂。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案