MyBatis完整教程IDEA版(2)--ResultMap/注解/一对多/多对一/lombok/log4j - 教程

news/2025/12/3 23:01:54/文章来源:https://www.cnblogs.com/gccbuaa/p/19304273

【狂神说Java】Mybatis最新完整教程IDEA版通俗易懂: P10 - P21

1、解决属性名和字段名不一致的问题

数据库中的字段

在这里插入图片描述
新建一个项目,拷贝之前的,测试实体类字段不一致的情况。

public class User {
private int id;
private String name;
private String password;
}

测试出现问题

在这里插入图片描述

//select * from mybatis.user where id = #{id}
//类型处理器
//select id,name,pwd from mybatis.user where id = #{id}

解决方法:

  • 起别名

    <select id="getUserById" parameterType="int" resultType="com.lingbo.pojo.User">select id,name,pwd as password from mybatis.user where id = #{id}</select>

1.2、ResultMap

结果集映射

id 	name 	pwd
id 	name 	password
<!--结果集映射--><resultMap id="UserMap" type="User"><!--column数据库中的字段,property实体类中的属性--><result column="id" property="id"/><result column="name" property="name"/><result column="pwd" property="password"/></resultMap><select id="getUserById" parameterType="int" resultMap="UserMap">select * from mybatis.user where id = #{id}</select>
  • resultMap 元素是 MyBatis 中最重要最强大的元素。
  • ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
  • 如果这个世界总是这么简单就好了。

2、日志

2.1、日志工厂

如果一个数据库操作出现了异常,我们需要排错。日志就是最好的助手!

曾经:sout、debug

现在:日志工厂!
在这里插入图片描述

在Mybatis中具体使用哪一个日志实现,在设置中设定!

STDOUT_LOGGING标准日志输出

为了学习log4j,将Mybatis版本从3.5.19降回3.5.6

<!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency>

在这里插入图片描述

2.2、LOG4J

什么是log4j?

如何使用log4j?

  1. 先导入log4j的包

    <!-- https://mvnrepository.com/artifact/log4j/log4j --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>
  2. log4j.properties

    #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
    log4j.rootLogger=DEBUG,console,file
    #console 控制台输出的相关配置
    log4j.appender.console=org.apache.log4j.ConsoleAppender
    log4j.appender.console.Target=System.out
    log4j.appender.console.Threshold=DEBUG
    log4j.appender.console.layout=org.apache.log4j.PatternLayout
    log4j.appender.console.layout.conversionPattern=[%c]-%m%n
    #file 文件输出的相关配置
    log4j.appender.file=org.apache.log4j.RollingFileAppender
    log4j.appender.file.File=./log/lingbo.log
    log4j.appender.file.MaxFileSize=10mb
    log4j.appender.file.Threshold=DEBUG
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.conversionPattern=[%p][%d{%yy-MM-dd}][%c]%m%n
    #日志输出级别
    log4j.logger.org.mybatis=DEBUG
    log4j.logger.java.sql=DEBUG
    log4j.logger.java.sql.Statement=DEBUG
    log4j.logger.java.sql.ResultSet=DEBUG
    log4j.logger.java.sql.PreparedStatement=DEBUG
  3. 配置log4j为日志的实现

    <settings><setting name="logImpl" value="LOG4J"/>
    </settings>
  4. Log4j的使用,直接测试运行刚才的查询

在这里插入图片描述
简单使用

  1. 在要使用Log4j的类中,导入包import org.apache.log4j.Logger;

  2. 日志对象,参数为当前类的class

    static Logger logger = Logger.getLogger(UserMapperTest.class);
  3. 日志级别

    logger.info("info:进入了testLog4j");
    logger.debug("debug:进入了testlog4j");
    logger.error("error:进入了testlog4j");

3、分页

思考:为什么要分页?

  • 减少数据的处理量

3.1、使用Limit分页

# 语法
select * from `user` limit startIndex,pageSize;
select * from `user` limit n; #[0,n]

使用Mybatis实现分页,核心SQL

  1. 接口

    //分页
    List<User> getUserByLimit(Map<String, Object> map);
  2. Mapper XML

    <!--  分页实现查询  --><select id="getUserByLimit"  parameterType="map" resultMap="UserMap">select * from mybatis.user limit #{startIndex},#{pageSize}</select>
  3. 测试

    @Test
    public void getUserByLimit(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<String, Object> map = new HashMap<>();map.put("startIndex", 1);map.put("pageSize", 2);List<User> userList = mapper.getUserByLimit(map);userList.forEach(System.out::println);sqlSession.close();}

3.2、RowBounds分页

不再使用SQL实现分页

  1. 接口

    //分页2
    List<User> getUserByRowBounds();
  2. mapper.xml

    <!--  RowBounds分页实现查询  --><select id="getUserByRowBounds" resultMap="UserMap">select * from mybatis.user</select>
  3. 测试

    @Test
    public void getUserByRowBounds(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    //RowBounds实现
    RowBounds rowBounds = new RowBounds(1, 2);
    //通过Java代码层面实现分页
    List<User> userList = sqlSession.selectList("com.lingbo.dao.UserMapper.getUserByRowBounds",null,rowBounds);for (User user : userList) {System.out.println(user);}sqlSession.close();}

3.3、分页插件

在这里插入图片描述
了解即可。

官方文档:Mybatis PageHelper

4、使用注解开发

4.1、面向接口编程

关于接口的理解

三个面向区别

4.2、使用注解开发

  1. 注解在接口上实现

    @Select("select * from user")
    List<User> getUsers();
  2. 需要在核心配置文件中绑定接口

    <!--  绑定接口  --><mappers><mapper class="com.lingbo.dao.UserMapper"/></mappers>
  3. 测试

    @Test
    public void testSelectAll() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    //底层主要应用反射
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = mapper.getUsers();for (User user : users) {System.out.println(user);}sqlSession.close();}

本质:反射机制实现

底层:动态代理

在这里插入图片描述

4.3、MyBatis详细的执行流程!

请添加图片描述

4.4、CRUD

我们可以在工具类创建的时候实现自动提交事务!

public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession(true);
}

编写接口,增加注解

public interface UserMapper {
@Select("select * from user")
List<User> getUsers();//方法存在多个参数,所有的参数前面必须加上 @Param注解@Select("select * from user where id = #{id}")User getUserById(@Param("id") int id);@Insert("insert into user(id,name,pwd) values (#{id},#{name},#{password})")int addUser(User user);@Update("UPDATE user set name = #{name} ,pwd = #{password} where id = #{id}")int updateUser(User user);@Delete("delete from user where id = #{id}")int deleteUserById(@Param("id") int id);}

测试

【注意:我们必须要将接口注册绑定到我们的核心配置文件中!】

<!--  绑定接口  --><mappers><mapper class="com.lingbo.dao.UserMapper"/></mappers>

4.5、关于@Param()注解

  • 基本类型的参数或者String类型,需要加上。
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上!
  • 我们在SQL中引用的(#{uid}),就是我们这里的@Param()中设定的属性名!

#{}和${}的区别

${}会有SQL注入的风险,不安全!

5、Lombok

使用步骤:

  1. 在IDEA中安装lombok插件

  2. 在项目中导入lombok的jar包

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency>
  3. 在实体类上加注解即可

@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Jacksonized
@Data:无参构造,getter,setter,toString,hashcode,equals
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString

6、多对一处理

多对一:

在这里插入图片描述

  • 多个学生,对应一个老师
  • 对于学生这边而言,关联… 多个学生,关联一个老师 【多对一】
  • 对于老师而言,集合,一个老师,有很多学生 【一对多】

在这里插入图片描述

数据准备:

CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

6.1、测试环境搭建

  1. 导入lombok
  2. 新建实体类Teacher,Student
  3. 建立Mapper接口
  4. 建立Mapper.xml文件
  5. 在核心配置文件中绑定注册Mapper接口或者文件!
  6. 测试查询是否能够成功!

6.2、按照查询嵌套处理

<!--
思路:
1.查询所有的学生信息
2.根据查询出来的学生的tid,寻找对应的老师!  子查询
--><select id="getStudents" resultMap="StudentTeacher"><!--        select s.id,s.name,t.name from student s, teacher t where s.tid = t.id;-->select * from student;</select><resultMap id="StudentTeacher" type="Student"><result property="id" column="id"/><result property="name" column="name"/><!--    复杂的属性,我们需要单独处理 对象:association 集合: collection   --><association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/></resultMap><select id="getTeacher" resultType="Teacher">select * from teacher where id = #{id};</select>

6.3、按照结果嵌套处理

<!--按照结果嵌套处理--><select id="getStudents2" resultMap="StudentTeacher2">select s.id sid,s.name sname,t.name tname from student s, teacher t where s.tid = t.id;</select><resultMap id="StudentTeacher2" type="Student"><result property="id" column="sid"/><result property="name" column="sname"/><!--    复杂的属性,我们需要单独处理 对象:association 集合: collection   --><association property="teacher" javaType="Teacher"><result property="name" column="tname"/></association></resultMap>

回顾MySQL多对一查询的方式:

  • 子查询
  • 联表查询

7、一对多处理

比如:一个老师拥有多个学生!

对于老师而言,就是一对多的关系!

7.1、环境搭建,和多对一一样

实体类

@Data
public class Teacher {
private int id;
private String name;
//一个老师拥有多个学生
private List<Student> students;}
@Data
public class Student {
private int id;
private String name;
private int tid;
}

7.2、按照结果嵌套处理

<!--按结果嵌套查询--><select id="getTeacherById" resultMap="TeacherStudent">select s.id sid, s.name sname, t.name tname, t.id tidfrom student s, teacher twhere s.tid=t.id and t.id = #{tid}</select><resultMap id="TeacherStudent" type="Teacher"><result property="id" column="tid"/><result property="name" column="tname"/><!--    复杂的属性,我们需要单独处理 对象:association 集合: collectionjavaType="" 指定属性的类型集合中的泛型信息,我们使用ofType获取--><collection property="students" ofType="Student"><result property="id" column="sid"/><result property="name" column="sname"/><result property="tid" column="tid"/></collection></resultMap>

7.3、按照查询嵌套处理

<select id="getTeacherById2" resultMap="TeacherStudent2">select *from teacherwhere id = #{tid}
</select><resultMap id="TeacherStudent2" type="Teacher"><collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap><select id="getStudentByTeacherId" resultType="Student">select * from student where tid = #{tid}
</select>

7.4、小结

  1. 关联 - association 【多对一】
  2. 集合 - collection 【一对多】
  3. javaType & ofType
    1. JavaType 用来指定实体类中属性的类型
    2. ofType 用来指定映射到List或者集合中的 POJO类型,泛型中的约束类型!

注意点:

  • 保证SQL的可读性,尽量通俗易懂
  • 注意一对多和多对一种,属性名和字段的问题!
  • 如果问题不好排查错误,可以使用日志,建议使用log4j

慢SQL 1s 1000s

面试高频

  • MySQL引擎
  • InnoDB底层原理
  • 索引
  • 索引优化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/986126.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

以 Core i9-13900HX 实例讲解CPU概念:物理CPU,内核,逻辑CPU

缘起 # 完整代码见:https://github.com/luminousmen/grokking_concurrency/blob/master/Chapter%205/password_cracking_parallel.pydef crack_password_parallel(crypto_hash: str, length: int) -> None:"&…

图书馆管理系统团队作业4-项目冲刺

图书馆管理系统团队作业4-项目冲刺这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScien…

C语言之折中查找

题目描述有 n个数(n≤1000000),这 n个数已按从大到小顺序存放在一个数组中,然后有 T次查询,每次输入一个数,要求用折半查找法找出该数在数组中第一次出现的位置。如果不在数组中输出 0。 输入第一行数组元素的个…

【第七章:时间序列模型】3.时间序列实战:使用时序模型进行股票预测实战 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

罗克韦尔Micro850 PLC和欧姆龙NJ互通离不开Modbus工业物联网技术支撑

一、项目背景:人工关节精密加工生产线的通讯困境 在医疗器械人工关节精密加工生产线中,某企业用欧姆龙 NJ 系列 PLC(Modbus RTU 协议)负责钛合金关节切削打磨(尺寸精度 0.005mm),罗克韦尔 Micro850 PLC(Modbus…

一条不太寻常的路 —— AFO 退役记 -

我不是一个很爱煽情的人,但总会在看到别人退役记时,因别人的故事而伤心。这次轮到我的。 序言 这是一次悄悄的退役,无人知晓。这篇文章,只是介绍一个无名的人的莽撞与无能。 OIer 其实是一个很温暖的群体,但我好像…

Go 语言:类型别名 vs 新类型详解 - 若

📚 前言 在 Go 语言中,类型系统是非常严格的。我们经常需要基于现有类型创建新的类型,Go 提供了两种方式:类型别名(Type Alias) 和 新类型定义(Type Definition)。虽然它们看起来很相似,但本质上有着巨大的区…

pytest高级用法之mark

mark给用例标记不同标签,实现用例筛选 ①注册标记:项目根目录下新建pytest.ini文件,添加配置[pytest]markers =bvtP0P1P2 ②打上标记 ③筛选标记: 运行单个标记 :pytest -m bvt 运行多个标记 :pytest -m &q…

20232320 2025-2026-1 《网络与系统攻防技术》实验八实验报告

1.实验内容 (1)Web前端HTML 能正常安装、启停Apache。理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML。 (2)Web前端javascipt 理解JavaScript的基本功能,理解DOM。 在(1)的基础上,编写JavaScript…

第一篇Scrum冲刺

第一篇Scrum冲刺认领任务成员 任务郭涛 商城交易系统以及分数统计系统设计区泽明 碰撞检测以及生命系统设计袁智燊 战斗机制的设计,包括飞机控制,敌机移动与攻击逻辑梁法恩 游戏UI界面设计以及主菜单(包括商店系统)…

Vibe Coding - 深度解读规范驱动制作(SDD):对 Kiro、spec-kit、Tessl 三大设备的剖析与实践

Vibe Coding - 深度解读规范驱动制作(SDD):对 Kiro、spec-kit、Tessl 三大设备的剖析与实践2025-12-03 22:39 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !impo…

第六篇SCrum冲刺

每日Scrum报告 日期: 2025-12-01 会议时间: 09:00 1. 当日站立式会议记录 会议照片成员同步内容 成员:齐思贤昨天已完成的工作:实现收藏接口(POST /api/v1/collections),校验商户是否存在; 实现取消收藏接口(…

Hudi 文件格式分析

Hudi 文件格式分析 请关注微信公众号:阿呆-bot 主题说明 Hudi 支持多种文件格式来存储数据,不同的格式有不同的特点和适用场景。理解文件格式的选择和使用,有助于优化存储和查询性能。 Hudi 主要使用两种文件格式:…

ai故事生成报告 - f

软件构造实验作业 实验名称:儿童故事管理平台的开发 实验一:AI故事生成平台 一、实验要求 实验名称: AI故事生成平台 - 核心数据模型与文本生成 核心任务: 构建平台的后端核心,实现基于关键词的自动故事生成。 任…

落山基唬人队-冲刺总结

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/202501SoftwareEngineering这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/202501SoftwareEngineering/homework/13559这个作业的目标 冲刺计划与冲…

深入解析:微信小程序通过关联公众号发送待办消息:实战指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

团队作业4

作业基本信息项目 内容这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/homework…

生命是一树花开

生命是一树花开 余秋雨生命,是一树花开,或安静或热烈,或寂寞或璀璨。日子,在岁月的年轮中依次厚重,那些天真的、跃动的、抑或沉思的灵魂,在繁华与喧嚣中,被刻上深深浅浅的印痕。很欣赏这样一句话:生命,是一场…

深入解析:【5】理解GUID和Handle:解锁UEFI驱动和应用程序的钥匙

深入解析:【5】理解GUID和Handle:解锁UEFI驱动和应用程序的钥匙pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "…

JavaSE--面向对象

JavaSE--面向对象JavaSE--面向对象 1. 面向过程 & 面向对象 面向过程思维面向过程思维--步骤清晰,第一步,第二部...适合处理一些简单的问题。顺序结构面向对象思维物以类聚,分类思维模式。解决问题把总的分类分…