web-第7次课后作业-2

web-第7次课后作业-2
初步了解MybatisMyBatis 入门项目文档一、项目概述这是一个Spring Boot 3 MyBatis 3的入门学习项目演示如何用最简单的方式操作 SQL Server 数据库。具体包括MyBatis 是什么、怎么连接数据库、怎么做增删改查CRUD、MyBatis 帮你省掉了什么工作。二、技术栈介绍技术版本它的作用新手友好解释Spring Boot3.2.0Java 项目的管家帮你管理依赖、启动应用、注入对象MyBatis3.0.3一个持久层框架让你用声明接口的方式操作数据库不用手写 JDBCSQL Server—微软的关系型数据库Maven—包管理工具自动下载依赖的 jar 包Java21编程语言JUnit 5—单元测试框架随 spring-boot-starter-test 引入三、项目文件结构pj4/ ├── pom.xml # Maven 配置声明依赖 ├── init.sql # 数据库初始化脚本 ├── mvnw / mvnw.cmd # Maven Wrapper无需本地装 Maven ├── src/ │ ├── main/ │ │ ├── java/com/example/pj4/ │ │ │ ├── Pj4Application.java # Spring Boot 启动入口 │ │ │ ├── pojo/ │ │ │ │ └── User.java # 实体类POJO一张表对应一个类 │ │ │ └── mapper/ │ │ │ └── UserMapper.java # MyBatis Mapper 接口定义数据库操作 │ │ └── resources/ │ │ └── application.properties # 数据库连接配置 │ └── test/java/com/example/pj4/ │ └── Pj4ApplicationTests.java # 单元测试 └── target/ # 编译输出目录自动生成不用管四、各文件详解4.1 pom.xmlMaven 依赖配置dependencies!-- MyBatis 起步依赖引入后就能用 MyBatis 的全部功能 --dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion3.0.3/version/dependency!-- SQL Server 驱动Java 连接 SQL Server 必须的驱动包 --dependencygroupIdcom.microsoft.sqlserver/groupIdartifactIdmssql-jdbc/artifactIdscoperuntime/scope/dependency!-- Spring Boot 测试依赖提供 JUnit、Spring Test 等 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies说明mybatis-spring-boot-starter是核心——它内部已经包含了 MyBatis 核心包和 MyBatis-Spring 整合包引入这一个依赖就能用 MyBatis。4.2 init.sql数据库初始化脚本在 SQL Server 中执行这个脚本它会自动创建数据库和测试数据-- 创建数据库 mybatisCREATEDATABASE[mybatis];-- 切换到该数据库USE[mybatis];-- 创建 user 表ID 自增CREATETABLE[user](idINTIDENTITY(1,1)PRIMARYKEY,-- 自增主键从 1 开始每次 1name NVARCHAR(100)NULL,-- 支持中文的字符串ageTINYINTNULL,genderTINYINTNULL,-- 1男, 2女phone NVARCHAR(11)NULL);-- 插入 6 条测试数据《倚天屠龙记》角色INSERTINTO[user](name,age,gender,phone)VALUES(N白眉鹰王,55,1,18800000000);INSERTINTO[user](name,age,gender,phone)VALUES(N金毛狮王,45,1,18800000001);INSERTINTO[user](name,age,gender,phone)VALUES(N青翼蝠王,38,1,18800000002);INSERTINTO[user](name,age,gender,phone)VALUES(N紫衫龙王,42,2,18800000003);INSERTINTO[user](name,age,gender,phone)VALUES(N光明左使,37,1,18800000004);INSERTINTO[user](name,age,gender,phone)VALUES(N光明右使,48,1,18800000005);4.3 application.properties数据库连接配置spring.datasource.driver-class-namecom.microsoft.sqlserver.jdbc.SQLServerDriver spring.datasource.urljdbc:sqlserver://localhost:1433;databaseNamemybatis;encryptfalse;trustServerCertificatetrue spring.datasource.usernamesa spring.datasource.password你猜每一行的含义配置项含义driver-class-name告诉 Java 用哪个数据库驱动这里是 SQL Server 驱动url数据库地址localhost:1433是本机 1433 端口databaseNamemybatis是数据库名。encryptfalse和trustServerCertificatetrue是开发环境关闭 SSL 加密生产环境不能这样写username/password数据库登录账号密码你不需要写任何获取连接的代码。Spring Boot 读到这些配置后会自动创建数据库连接池默认 HikariCPMyBatis 会从这个池里拿连接。4.4 Pj4Application.java启动类SpringBootApplication// 标记这是 Spring Boot 应用publicclassPj4Application{publicstaticvoidmain(String[]args){SpringApplication.run(Pj4Application.class,args);// 启动应用}}SpringBootApplication是干什么的它是三个注解的快捷方式Configuration允许定义 BeanSpring 管理的对象EnableAutoConfiguration自动配置——Spring Boot 读到 pom.xml 里引入了 MyBatis就自动帮你配好 MyBatisComponentScan自动扫描当前包及子包下的所有组件包括你的Mapper接口4.5 User.java实体类 / POJOpublicclassUser{privateIntegerid;// 数据库 int → Java IntegerprivateStringname;// 数据库 nvarchar → Java StringprivateShortage;// 数据库 tinyint → Java ShortprivateShortgender;privateStringphone;// 无参构造方法MyBatis 反射创建对象时需要// getter / setterMyBatis 通过它们读写属性值// toString()打印输出用}重要概念数据库的一行对应 Java 的一个 User 对象数据库的列对应 User 对象的属性。这个类就叫POJOPlain Old Java Object也叫实体类Entity。4.6 UserMapper.javaMyBatis Mapper 接口—— 核心重点Mapper// ① 告诉 MyBatis这个接口我来接管publicinterfaceUserMapper{Select(SELECT id, name, age, gender, phone FROM [user])ListUserlist();// ② 查询全部Select(SELECT id, name, age, gender, phone FROM [user] WHERE id #{id})UsergetById(Integerid);// ③ 按 ID 查询Insert(INSERT INTO [user] (name, age, gender, phone) VALUES (#{name}, #{age}, #{gender}, #{phone}))Options(useGeneratedKeystrue,keyPropertyid)voidinsert(Useruser);// ④ 新增Update(UPDATE [user] SET name#{name}, age#{age}, gender#{gender}, phone#{phone} WHERE id#{id})voidupdate(Useruser);// ⑤ 更新Delete(DELETE FROM [user] WHERE id#{id})voiddelete(Integerid);// ⑥ 删除}逐行详解①Mapper告诉 Spring MyBatis“别看我只有一个接口声明我会在运行时自动生成一个实现类来代理你。”② 查询全部Select里面写 SQL 语句返回类型ListUserMyBatis 自动把查出来的多行数据映射成User对象的列表因为数据库的列名id,name,age,gender,phone和User类的属性名完全一致所以 MyBatis 会自动映射不需要额外配置③ 按 ID 查询#{id}这是 MyBatis 的参数占位符相当于 JDBC 的?。MyBatis 会把方法参数Integer id的值填到这里安全#{ }使用的是PreparedStatement参数绑定不会有 SQL 注入风险④ 新增#{name},#{age}等参数是一个User对象MyBatis 会自动从对象里取getName()、getAge()等Options(useGeneratedKeys true, keyProperty id)因为[user]表的id是自增列插入时不需要提供 id。插入成功后数据库生成的 id 值会自动回填到传入的User对象的id属性上⑤ 更新根据User对象的id找到对应行把其他字段更新为对象中的值⑥ 删除根据id删除对应行MyBatis 注解速查表注解用途对应 SQLSelect查询SELECT ...Insert插入INSERT INTO ...Update更新UPDATE ...Delete删除DELETE FROM ...Options附加选项如主键回填—#{}vs${}重要写法底层原理安全性使用场景#{xxx}用PreparedStatement的?占位符安全防 SQL 注入始终优先使用${xxx}直接拼字符串到 SQL 里不安全可能被注入只在需要动态表名/列名时用MyBatis 是怎么帮你的对比 JDBC你写的代码 MyBatis 帮你做的 ─────────────────────────────────────────────────── import org.apache.ibatis. → 不需要 import JDBC 任何东西 annotations.*; Mapper → 不需要 Class.forName 加载驱动 public interface UserMapper { → 不需要 DriverManager.getConnection → 不需要 try-finally 关闭连接 Select(SELECT ...) → 不需要 PreparedStatement ListUser list(); → 不需要 ResultSet → 不需要 while(rs.next()) } → 不需要 rs.getInt(id) ... → MyBatis 通过反射调用 setId/getName 自动完成列→属性的映射一句话你只需定义一个接口、写一个 SQL 注解MyBatis 自动生成实现类帮你完成从接口调用到返回 Java 对象的全过程。4.7 Pj4ApplicationTests.java单元测试SpringBootTest// 启动完整的 Spring 上下文会连接真实数据库Transactional// 每个测试方法执行后自动回滚数据库不留痕迹publicclassPj4ApplicationTests{AutowiredprivateUserMapperuserMapper;// Spring 自动注入 MyBatis 生成的代理对象TestpublicvoidtestList(){...}// 测试查询全部TestpublicvoidtestGetById(){...}// 测试按 ID 查询TestpublicvoidtestInsert(){...}// 测试新增看 id 是否回填TestpublicvoidtestUpdate(){...}// 测试更新看修改是否生效TestpublicvoidtestDelete(){...}// 测试删除看总数是否减少}Autowired干了什么UserMapper明明是个接口没有实现类但 MyBatis 在启动时用**动态代理JDK Proxy**生成了一个代理对象代理对象里封装了 “根据注解拿 SQL → 获取连接 → 执行 → 映射结果” 的全套逻辑Spring 把这个代理对象注入到userMapper变量里你调用userMapper.list()实际调用的是代理对象Transactional的作用每个测试方法执行时会开启一个数据库事务方法结束后自动回滚。所以测试中的新增/更新/删除不会真正修改数据库数据。五、运行结果执行./mvnw test后的输出 查询全部 User{id1, name白眉鹰王, age55, gender1, phone18800000000} User{id2, name金毛狮王, age45, gender1, phone18800000001} User{id3, name青翼蝠王, age38, gender1, phone18800000002} User{id4, name紫衫龙王, age42, gender2, phone18800000003} User{id5, name光明左使, age37, gender1, phone18800000004} User{id6, name光明右使, age48, gender1, phone18800000005} 按ID查询 User{id1, name白眉鹰王, age55, gender1, phone18800000000} 新增用户 插入后返回的ID: 8 ← 注意ID 被自动回填了 User{id8, name张无忌, age22, gender1, phone19900000000} 更新前 User{id1, name白眉鹰王, age55, gender1, phone18800000000} 更新后 User{id1, name殷天正, age60, gender1, phone18800000000} ← 名字和年龄均已更新 删除前总数: 7 删除后总数: 6 Tests run: 5, Failures: 0, Errors: 0, Skipped: 0 BUILD SUCCESS六、数据流转全景图┌──────────────────────────────────────────────────────────────────┐ │ 测试代码 │ │ userMapper.list() ← 你只写了一行方法调用 │ └─────────────────────┬────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────┐ │ MyBatis 动态代理对象框架自动生成 │ │ 1. 从 Select 拿到 SQL: SELECT id,name,age,gender,phone FROM │ │ [user] │ │ 2. 从连接池拿一个 ConnectionHikariCP 管理 │ │ 3. 创建 PreparedStatement填入 #{参数} 的值 │ │ 4. 执行 executeQuery() │ │ 5. 遍历 ResultSet每行创建一个 User 对象 │ │ 6. 列名 id → 调用 user.setId()列名 name → user.setName()... │ │ 7. 归还 Connection 到连接池 │ │ 8. 返回 ListUser │ └─────────────────────┬────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────┐ │ SQL Server 数据库 │ │ [user] 表 → 6行数据 → 通过网络返回给 Java │ └──────────────────────────────────────────────────────────────────┘你只需关心写 SQL 注解和调用方法两个动作中间所有 JDBC 的脏活累活 MyBatis 全部代劳。七、常见问题Q1Mapper和Repository有什么区别Mapper是 MyBatis 专属注解告诉 MyBatis 为这个接口生成代理实现。Repository是 Spring 的通用注解MyBatis 不识别它。Q2如果数据库列名和 Java 属性名不一致怎么办比如数据库叫user_nameJava 叫userName。两种解决方式在application.properties中设置mybatis.configuration.map-underscore-to-camel-casetrue自动下划线转驼峰在 SQL 中取别名SELECT user_name AS userName FROM [user]Q3注解方式和 XML 方式用哪个注解适合简单 SQL代码紧凑本项目用的就是这种方式XML适合复杂 SQL多表联合、动态条件SQL 与 Java 代码分离两种方式可以混用Q4我怎么知道 MyBatis 真的执行了哪些 SQL在application.properties中加一行mybatis.configuration.log-implorg.apache.ibatis.logging.stdout.StdOutImpl这样 MyBatis 执行的每条 SQL 和参数都会打印在控制台。