Mybatis扩展
1 pageHelper
1.1 介绍
- Mybatis中常用的一个插件,其作用是更加方便的进行分页查询
- 如果查询的数据量很大,此时我们会选择使用分页查询,减缓服务器压力
SELECT *
FROM tb_user
LIMIT index, pageNum;
# index 表示当前页中第一条数据的编号(编号从0开始) 也叫作偏移量
# pageNum 表示一页显示的记录数
1.2 依赖
<!-- pageHelper 插件 -->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.3.0</version>
</dependency>
1.3 引入
①UserMapper.xml
<select id="getUserByPage" resultType="User">SELECT id,username,nickname,password,mobile,status,created_time,modified_timeFROM tb_usersLIMIT #{index},#{size};
</select>
②UserDao
/*** 分页查询tb_users表中记录** @param index 每页中的第一条记录的编号(编号从0开始)* @param size 每页显示的记录数* @return*/
public List<User> getUserByPage(Integer index, Integer size);
③TestUser
@Test
public void getUserByPage() {List<User> userList = userDao.getUserByPage(5, 5);for (User user : userList) {System.out.println(user);}
}
1.4 TO类型封装
- 如果传入的多个参数时,这些参数都不属于业务模型中的数据(不属于POJO中的数据),没有对应的实体类,但是这些数据还是经常被使用的,所以可以也封装为一个类,并用属性描述这些参数,这样的类成为TO类
- TO(Transfer Object) 数据传输对象
- 可以封装分页参数
①Page
package cn.tedu.to;public class Page {/*** 每页中的第一条记录的编号(编号从0开始)*/private Integer index;/*** 每页显示的记录数*/private Integer size;public Integer getIndex() {return index;}public void setIndex(Integer index) {this.index = index;}public Integer getSize() {return size;}public void setSize(Integer size) {this.size = size;}
}
②UserMapper.xml
<select id="getUserByPage" resultType="User">SELECT id,username,nickname,password,mobile,status,created_time,modified_timeFROM tb_usersLIMIT #{index},#{size};
</select>
③UserMapper接口
/*** 分页查询tb_users表中记录** @param page 分页数据* @return 指定页的记录*/
public List<User> getUserByPage(Page page);
④TestUser
@Test
public void getUserByPage() {Page page = new Page();page.setIndex(0);page.setSize(5);List<User> userList = userDao.getUserByPage(page);for (User user : userList) {System.out.println(user);}
}
1.5 使用pageHelper
①pom.xml
<!--pageHelper插件-->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.3.0</version>
</dependency>
②PageHelperConfig
- 如果对插件有其余的设置时,可以设置配置类,否则不添加也可以
@Configuration
public class PageHelperConfig {/*** 当SpringBoot启动时,会自动加载配置类,自动执行配置方法,* 将方法的返回值交给Spring容器管理** @return*/@Beanpublic PageHelper pageHelperInit() {PageHelper pageHelper = new PageHelper();//指定分页时的一些设置Properties p = new Properties();p.setProperty("reasonable", "true"); // 分页合理化return pageHelper;}
}
- 也可以在配置文件进行设置
pagehelper:reasonable: true
③UserMapper接口
/*** 查询所有用户信息** @return 所有用户信息*/
public List<User> getUser();
④UserMapper.xml
<select id="getUser" resultType="User">SELECT id,username,nickname,password,mobile,status,created_time,modified_timeFROM tb_users
</select>
⑤TestUser
@Test
public void getUser() {//startPage(a,b) 设置分页为第a页,每页有b条记录PageHelper.startPage(5, 5);List<User> userList = userDao.getUser();for (User user : userList) {System.out.println(user);}
}
2 逆向工程
2.1 概念
- 正向工程: 根据数据库中的表,创建对应的JAVA实体类,然后再创建接口,xml文件等内容
- 逆向工程: 先创建数据库的表,由框架负责读取数据库表,反向生成如下资源:
- JAVA实体类
- Mapper接口
- Mapper.xml文件
2.2 配置POM
①创建SpringBoot项目,名为MyBatisGeneratorDemo
,并将版本改为2.5.4
②在项目的POM中,添加如下依赖
<!--添加MySQL数据库驱动依赖-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>
<!--添加mybatis启动依赖-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version>
</dependency>
③在项目的POM中的build/plugins
组件中,添加如下插件
<!-- 控制Maven在构建过程中的相关配置 -->
<build><!-- 构建过程中要使用的插件 --><plugins><!-- 一个具体的插件 --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!-- 逆向工程的操作的相关插件 --><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.0</version><!-- 插件的依赖 --><dependencies><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency></dependencies></plugin></plugins>
</build>
2.3 配置文件
①在项目的resources目录下,添加一个配置文件,文件名必须是: generatorConfig.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration><!--targetRuntime: 表示进行逆向工程时的版本是什么MyBatis3Simple: 生成最基本的增删改查的SQL语句MyBatis3: 会根据实体表的情况,动态的生成带条件的增删改查的SQL语句--><context id="DB2Tables" targetRuntime="MyBatis3Simple"><!-- 数据库的连接信息 --><jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/sblog?characterEncoding=utf8&serverTimezone=Asia/Shanghai"userId="root"password="root"></jdbcConnection><!--JAVA实体类的生成策略targetPackage: 表示实体类存在的包路径是哪里targetProject: 表示实体类所在的包存储到哪个主目录中(基本不会改动)--><javaModelGenerator targetPackage="cn.tedu.pojo" targetProject=".\src\main\java"><property name="enableSubPackages" value="true"/><property name="trimStrings" value="true"/></javaModelGenerator><!--SQL映射文件的生成策略targetPackage: 表示SQL映射文件存在的路径是哪里targetProject: 表示SQL映射文件所在的包存储到哪个主目录中(基本不会改动)--><sqlMapGenerator targetPackage="mapper" targetProject=".\src\main\resources"><property name="enableSubPackages" value="true"/></sqlMapGenerator><!--MAPPER接口的生成策略targetPackage: 表示MAPPER接口存在的路径是哪里targetProject: 表示MAPPER接口所在的包存储到哪个主目录中(基本不会改动)--><javaClientGenerator type="XMLMAPPER" targetPackage="cn.tedu.mapper" targetProject=".\src\main\java"><property name="enableSubPackages" value="true"/></javaClientGenerator><!--逆向分析的表tableName: 表示要读取的数据库中的表名domainObjectName: 表示根据对应的表生成的基础的名字比如: 基础名为Users实体类名: UsersSQL文件名: UsersMapperMAPPER接口: UsersMapper--><table tableName="tb_users" domainObjectName="Users"/></context>
</generatorConfiguration>
②执行插件
- 如果没有显示,则表示插件引入有问题,检查POM文件是否设置正确
2.4 测试
①将生成的接口上,添加@Mapper
注解
@Mapper
public interface UsersMapper {...
}
②然后在项目中添加配置文件application.yml
- 检查用户密码是否输入有误
- 检查
MAPPER.xml
文件的包路径和配置文件的路径是否匹配 - 检查
实体类路径
和配置文件设置的路径是否匹配
spring:datasource:url: jdbc:mysql://localhost:3306/sblog?serverTimezone=Asia/Shanghai&characterEncoding=utf8username: rootpassword: rootmybatis:configuration:map-underscore-to-camel-case: truemapper-locations: classpath:/mapper/*.xmltype-aliases-package: cn.tedu.pojologging:level:cn:tedu: debug
③创建测试类,生成测试方法
@SpringBootTest
class TestUser {@Autowiredprivate UsersMapper usersMapper;@Testpublic void selectByPrimaryKey() {Users users = usersMapper.selectByPrimaryKey(1);System.out.println(users);}}
3 延迟加载
3.1 什么是延迟加载
- 假设要查询指定id为1的文章的信息以及文章所属的用户信息
SELECT a.id,a.title,u.username
FROM tb_articles a LEFT JOIN tb_users u
ON a.user_id = u.id
WHERE a.id = 1;
- 假设id为100的文章信息,在数据库中该文章不存在,但是由于SQL已经执行了,导致内存中已经将关联的信息存储起来,所以希望实现如果文章不存在,就不去查询用户表的记录了,以此节省资源
- 所以使用分部查询的方式来解决这个问题
①首先查询文章表,是否存在记录,如果没查询到记录,则终止查询
SELECT *
FROM tb_articles
WHERE id = 1;
②如果查询到了记录,则使用查询的记录中的user_id,作为SQL的id值
SELECT *
FROM tb_users
WHERE id = #{id}
3.2 一对一查询
3.2.1 目标
根据文章ID,查询出文章信息,并且查询出文章所属的用户信息,将查询的结果封装到Articles对象中
3.2.2 生成Articles相关逆向工程
- 使用逆向工程生成tb_articles相关的实体类,SQL映射和接口
- 并在
Articles
类中添加用户表的属性
private Users users;public Users getUsers() {return users;
}public void setUsers(Users users) {this.users = users;
}
3.3.3 映射文件
<resultMap id="BaseResultMap" type="cn.tedu.pojo.Articles"><id column="id" property="id" jdbcType="BIGINT"/><result column="title" property="title" jdbcType="VARCHAR"/><result column="TYPE" property="type" jdbcType="CHAR"/><result column="content" property="content" jdbcType="VARCHAR"/><result column="STATUS" property="status" jdbcType="CHAR"/><result column="user_id" property="userId" jdbcType="BIGINT"/><result column="created_time" property="createdTime" jdbcType="TIMESTAMP"/><result column="modified_time" property="modifiedTime" jdbcType="TIMESTAMP"/><!--①通过select属性,调用第二步要执行的SQL--><!--②通过column属性,来制定第二步要传入的参数是那个属性值--><!--③通过property属性,封装第二条SQL传入的结果--><!--④通过fetchType属性,表示本次的延迟加载是懒加载模式--><association property="users"javaType="Users"select="cn.tedu.mapper.UsersMapper.selectByPrimaryKey"column="user_id"fetchType="lazy"></association>
</resultMap>
3.3.4 测试类
①查询文章信息,不获取用户信息,执行查询文章表的SQL
@Test
public void selectArticleByPrimaryKey() {Articles articles = articlesMapper.selectByPrimaryKey(1L);System.out.println(articles.getTitle());
}
②获取用户信息,会自动查询用户表的SQL
@Test
public void selectArticleByPrimaryKey() {Articles articles = articlesMapper.selectByPrimaryKey(1L);System.out.println(articles.getUsers());
}
3.3 一对多查询
3.2.1 目标
根据用户ID查询用户信息,并且查询出该用户的所有的文章信息,将查询的结果封装到User对象中
3.2.2 添加Articles属性
- 在
Users
类中,添加属性封装关联的文章信息
private List<Articles> articles;public List<Articles> getArticles() {return articles;
}public void setArticles(List<Articles> articles) {this.articles = articles;
}
3.3.3 映射文件
①在ArticlesMapper.xml
中定义根据user_id
查询文章信息的SQL
<select id="selectByUserId" resultMap="BaseResultMap">SELECT id, title, TYPE, content, STATUS, user_id, created_time, modified_timeFROM tb_articlesWHERE user_id = #{userId}
</select>
②在ArticlesMapper接口
中定义接口
List<Articles> selectByUserId(Long userId);
③在User
类中,定义一对多的延迟加载的映射
同学们!!!这个案例映射失败的原因是因为我在collection标签中,写错了属性,不能写javaType属性,要写出ofType属性才可以!!!不要像我一样马虎哦!!!!
<resultMap id="BaseResultMap" type="cn.tedu.pojo.Users"><!--WARNING - @mbggeneratedThis element is automatically generated by MyBatis Generator, do not modify.This element was generated on Fri Jun 09 20:34:40 CST 2023.--><id column="id" property="id" jdbcType="INTEGER"/><result column="username" property="username" jdbcType="VARCHAR"/><result column="nickname" property="nickname" jdbcType="VARCHAR"/><result column="password" property="password" jdbcType="VARCHAR"/><result column="mobile" property="mobile" jdbcType="VARCHAR"/><result column="status" property="status" jdbcType="TINYINT"/><result column="created_time" property="createdTime" jdbcType="TIMESTAMP"/><result column="modified_time" property="modifiedTime" jdbcType="TIMESTAMP"/><collection property="articles"ofType="Articles"select="cn.tedu.pojo.Articles.selectByUserId"column="id"fetchType="lazy"></collection>
</resultMap>
3.3.4 测试类
①查询用户信息,不获取文章信息,执行查询用户表的SQL
@Test
public void selectByPrimaryKey() {Users users = usersMapper.selectByPrimaryKey(1);System.out.println(users.getUserName());
}
②获取文章信息,会自动查询文章表的SQL
@Test
public void selectByPrimaryKey() {Users users = usersMapper.selectByPrimaryKey(1);System.out.println(users.getArticles());
}
4 Maven中的scope
maven坐标中的scope表示依赖的作用范围
通常有以下几个作用范围:
- compile: 这是默认的作用范围,表示依赖会被编译到项目中,并且会在运行时对项目产生影响
- provided: 表示依赖会在编译时使用,但是在运行时需要额外的提供
- runtime: 表示依赖不会被编译到项目中,但是运行时会使用到
- test: 表示此以来使用在测试中
5 Maven的version
maven坐标中的version表示的是依赖的版本号
通常有以下的值:
- SNAPSHOT: 表示此版本是开发中的版本,可能会存在频繁的更新和变动
- RELEASE: 表示稳定的、成熟的版本,不会经常的变动版本号
- GA: 表示正式版本,以正式发布,不会经过重大更大
上一篇文章:Java综合项目(day38)-CSDN博客https://blog.csdn.net/Z0412_J0103/article/details/142972779下一篇文章: