Bouncy Castle实战:5分钟搞定Java自签名证书生成(附常见错误排查)
2026/4/1 17:40:20
摘要:本文将带你深入了解 Java 持久层框架 MyBatis。从环境搭建到核心配置,再到动态 SQL 和高级映射,结合实际项目代码(学生选课/图书管理系统),手把手教你掌握 MyBatis。文末附带高频面试题,助你从容应对面试!
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
在 Maven 项目中,我们需要引入 MyBatis 和 MySQL 驱动的依赖。
pom.xml)<dependencies><!-- MyBatis 核心包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.13</version></dependency><!-- MySQL 驱动包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!-- Lombok (可选,用于简化实体类) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version><scope>provided</scope></dependency><!-- 日志框架 (推荐使用,方便查看 SQL) --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.36</version></dependency></dependencies>SqlMapConfig.xml)这是 MyBatis 的全局配置文件,包含了数据库连接池、事务管理器、映射器文件路径等核心信息。
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 1. Settings: 全局设置 --><settings><!-- 开启驼峰命名自动映射:将数据库的 user_name 自动映射为 Java 的 userName --><settingname="mapUnderscoreToCamelCase"value="true"/><!-- 打印 SQL 日志到控制台 (开发环境推荐) --><settingname="logImpl"value="STDOUT_LOGGING"/></settings><!-- 2. Environments: 环境配置 (开发、测试、生产) --><environmentsdefault="development"><environmentid="development"><!-- 事务管理器: JDBC (使用 Connection 的 commit/rollback) --><transactionManagertype="JDBC"/><!-- 数据源: POOLED (使用连接池,复用连接,提高性能) --><dataSourcetype="POOLED"><propertyname="driver"value="com.mysql.cj.jdbc.Driver"/><propertyname="url"value="jdbc:mysql://localhost:3306/library_system?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8"/><propertyname="username"value="root"/><propertyname="password"value="your_password"/></dataSource></environment></environments><!-- 3. Mappers: 注册 Mapper XML 文件 --><mappers><!-- 使用 resource 属性指定类路径下的 XML 文件 --><mapperresource="mapper/BookMapper.xml"/><mapperresource="mapper/BorrowRecordMapper.xml"/></mappers></configuration>💡 知识点解析:
mapUnderscoreToCamelCase:非常重要!数据库字段通常是下划线命名(create_time),而 Java 属性是驼峰命名(createTime)。开启此配置后,MyBatis 会自动帮我们完成映射,不再需要手动写resultMap。POOLED:MyBatis 自带的连接池。生产环境通常会整合 Druid 或 HikariCP。
在代码中,我们通常这样使用 MyBatis:
// 1. 读取配置文件InputStreaminputStream=Resources.getResourceAsStream("SqlMapConfig.xml");// 2. 创建 SqlSessionFactory (工厂模式)SqlSessionFactorysqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream);// 3. 获取 SqlSession (会话)SqlSessionsqlSession=sqlSessionFactory.openSession(true);// true 表示自动提交事务// 4. 获取 Mapper 接口代理对象 (动态代理)BookMapperbookMapper=sqlSession.getMapper(BookMapper.class);// 5. 执行方法List<Book>books=bookMapper.findAll();close())。它相当于 JDBC 的Connection。Book.java)@Data// Lombok 注解,自动生成 Getter/Setter/ToStringpublicclassBook{privateIntegerid;privateStringtitle;privateStringauthor;privateDoubleprice;privateIntegercategoryId;}BookMapper.java)publicinterfaceBookMapper{// 查询所有List<Book>findAll();// 根据 ID 查询BookfindById(Integerid);// 新增intinsertBook(Bookbook);// 更新intupdateBook(Bookbook);// 删除intdeleteBook(Integerid);}BookMapper.xml)<mappernamespace="com.qcby.dao.BookMapper"><!-- id: 对应接口中的方法名 resultType: 返回结果的全限定类名 (如果开启了驼峰映射,会自动匹配字段) --><selectid="findAll"resultType="com.qcby.entity.Book">SELECT * FROM book</select><!-- parameterType: 参数类型 (可选,MyBatis 能自动推断) --><selectid="findById"parameterType="int"resultType="com.qcby.entity.Book">SELECT * FROM book WHERE id = #{id}</select><!-- useGeneratedKeys="true": 使用数据库自增主键 keyProperty="id": 将生成的主键值回填到 book 对象的 id 属性中 --><insertid="insertBook"useGeneratedKeys="true"keyProperty="id">INSERT INTO book (title, author, price, category_id) VALUES (#{title}, #{author}, #{price}, #{categoryId})</insert></mapper>MyBatis 最强大的功能之一就是动态 SQL。它摆脱了 JDBC 中拼接 SQL 字符串的痛苦。
<if>和<where>:多条件查询场景:用户可能只输入了书名,也可能同时输入了书名和作者,或者什么都没输。
<!-- 动态查询书籍信息 --><selectid="findBooksByCondition"resultType="com.qcby.entity.Book">SELECT * FROM book<where><!-- if test="条件表达式": 如果为 true,则拼接标签内的 SQL --><iftest="book.title != null and book.title !=''">AND title LIKE concat('%', #{book.title}, '%')</if><iftest="book.author != null and book.author !=''">AND author = #{book.author}</if><!-- 处理日期范围 --><iftest="startDate != null">AND publish_date >= #{startDate}</if></where></select>💡 知识点:
<where>标签:非常智能。如果标签内部有内容,它会自动插入WHERE关键字。如果内容以AND或OR开头,它会自动剔除掉第一个AND/OR,防止 SQL 语法错误。
<set>:动态更新场景:只更新用户修改了的字段,没修改的字段保持原样。
<updateid="updateBook">UPDATE book<set><iftest="title != null">title = #{title},</if><iftest="author != null">author = #{author},</if><iftest="price != null">price = #{price},</if></set>WHERE id = #{id}</update>💡 知识点:
<set>标签:会自动插入SET关键字,并且会自动剔除最后多余的逗号,。
<foreach>:批量插入/查询场景:一次性插入 100 本书,或者查询 ID 在 [1, 3, 5] 中的书。
<!-- 批量插入 --><insertid="batchInsertBooks">INSERT INTO book (title, author, category_id, publish_date) VALUES<!-- collection: 集合参数的名称 (list, array 或 @Param 指定的名) item: 当前遍历元素的别名 separator: 分隔符 --><foreachcollection="books"item="book"separator=",">(#{book.title}, #{book.author}, #{book.categoryId}, #{book.publishDate})</foreach></insert>当数据库表结构比较复杂(如一对多、多对一)时,简单的resultType可能无法满足需求,这时需要使用resultMap。
association)场景:查询借阅记录 (BorrowRecord) 时,同时查出对应的用户 (User) 和书籍 (Book) 信息。
<!-- 定义 ResultMap --><resultMapid="BorrowRecordMap"type="com.qcby.entity.BorrowRecord"><idproperty="id"column="id"/><resultproperty="borrowDate"column="borrow_date"/><!-- 关联 User 对象 --><associationproperty="user"javaType="com.qcby.entity.User"><idproperty="id"column="user_id"/><resultproperty="name"column="user_name"/></association><!-- 关联 Book 对象 --><associationproperty="book"javaType="com.qcby.entity.Book"><idproperty="id"column="book_id"/><resultproperty="title"column="book_title"/></association></resultMap><selectid="findUserBorrowRecords"resultMap="BorrowRecordMap">SELECT br.*, u.id as user_id, u.name as user_name, b.id as book_id, b.title as book_title FROM borrow_record br LEFT JOIN user u ON br.user_id = u.id LEFT JOIN book b ON br.book_id = b.id</select>#{}和${}的区别是什么?(必问)#{}:是预编译处理(PreparedStatement)。MyBatis 会将其替换为?,然后调用 JDBC 的set方法赋值。${}:是字符串替换。MyBatis 会直接将变量的值拼接到 SQL 语句中。ORDER BY ${columnName})。commit、close或update/insert/delete操作会清空一级缓存。<cache/>开启。Serializable接口。<insert>标签中使用useGeneratedKeys="true"和keyProperty="id"。id属性中。总结:MyBatis 是 Java 开发中必不可少的技能。掌握好动态 SQL 和 ResultMap,能让你在处理复杂业务时游刃有余。希望这篇教程能帮你建立起完整的 MyBatis 知识体系!🚀