Mybatis和Jpa

news2024/11/14 18:13:19

这里写目录标题

  • 1.Mybatis
    • 1.1 JDBC的缺点
    • 1.2 Mybatis的整体架构
    • 1.3 入门案例
      • 1.3.1 问题:无法连接到数据库服务器
    • 1.4 动态代理实现Mapper
    • 1.5 mybatis-config.xml配置
      • 1.5.1 properties属性读取外部资源
      • 1.5.2 settings设置
      • 1.5.3 typeAliases
      • 1.5.4 typeHandlers(类型处理器)
      • 1.5.5 plugins(插件又称拦截器)
      • 1.5.5.1 自定义拦截器
      • 1.5.6 environments(环境)
      • 1.5.7 Mappers
      • 总结
    • 1.6 Mapper.xml(映射文件)
      • 1.6.1 CRUD操作
    • 1.7 parameterType传入参数
      • 1.7.1 ${}的用法
      • 1.7.2 多个参数
      • 1.7.3 HashMap
      • 1.7.4 面试题(#、$区别)
    • 1.8 resultMap
      • 1.8.1 解决列名和属性名不一致
      • 1.8.2 属性的作用
    • 1.9 sql片段
      • 1.9.1 用法一:内部定义
      • 1.9.1 用法二:外部定义
    • 1.10 动态sql
      • 1.10.1 if
      • 1.10.2 choose、when、otherwise
      • 1.10.3 where
      • 1.10.4 set
      • 1.10.5 foreach
    • 1.11 缓存
      • 1.11.1 一级缓存
        • 1.11.1.1 清除一级缓存 方式一:clearCache
        • 1.11.1.2 清除一级缓存 方式二:执行update、insert、delete的时候,会清空缓存
      • 1.11.2 二级缓存
  • 2.Mybatis的高级查询
    • 2.1 一对一查询
    • 2.2 一对多查询
    • 2.3 多对多查询
    • 2.4 resultMap的继承
    • 2.5 延迟加载
      • 2.5.1 改造一对一查询
      • 2.5.2 开启延迟加载

1.Mybatis

  • MyBatis 是一款优秀的持久层框架,用于简化 JDBC 开发

JavaEE三层架构:表现层、业务层、持久层
持久层:负责将数据到保存到数据库的那一层代码

1.1 JDBC的缺点

在这里插入图片描述

1.2 Mybatis的整体架构

在这里插入图片描述

  • 配置文件

    • 全局配置文件mybatis-config.xml
      作用:配置数据源,引入映射文件
    • 映射文件:XxMapper.xml
      作用:配置sql语句、参数、结果集封装类型等
  • SqlSessionFactory
    作用:获取SqlSession

  • SqlSession
    作用:执行CRUD

  • Executor
    执行器,SqlSession通过调用它来完成具体的CRUD
    它是一个接口,提供了两种实现:缓存的实现、数据库的实现

  • Mapped Statement
    在映射文件里面配置,包含3部分内容:
    具体的sql,sql执行所需的参数类型,sql执行结果的封装类型

1.3 入门案例

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace(命名空间):映射文件的唯一标识 -->
<mapper namespace="UserMapper">

	<!-- 查询的statement,id:在同一个命名空间下的唯一标识,resultType:sql语句的结果集封装类型 -->
	<select id="queryUserById" resultType="cn.itcast.mybatis.pojo.User">
		select * from tb_user where id=#{id}
	</select>
	
</mapper>

Mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- 环境:说明可以配置多个,default:指定生效的环境 -->
	<environments default="development">
		<!-- id:环境的唯一标识 -->
		<environment id="development">
			<!-- 事务管理器,type:类型 -->
			<transactionManager type="JDBC" />
			<!-- 数据源:type-池类型的数据源 -->
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis-49" />
				<property name="username" value="root" />
				<property name="password" value="root" />
			</dataSource>
		</environment>
	</environments>
	<!-- 映射文件 -->
	<mappers>
		<mapper resource="UserMapper.xml" />
	</mappers>
</configuration>

在这里插入图片描述

MybatisTest

public static void main(String[] args) throws IOException {
		
	SqlSession sqlSession = null;
	try {
		// 指定mybatis的全局配置文件
		String resource = "mybatis-config.xml";
		// 读取mybatis-config.xml配置文件
		InputStream inputStream = Resources.getResourceAsStream(resource);
		// 构建sqlSessionFactory
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		// 获取sqlSession回话
		sqlSession = sqlSessionFactory.openSession();
		// 执行查询操作,获取结果集。参数:1-命名空间(namespace)+“.”+statementId,2-sql的占位符参数
		User user = sqlSession.selectOne("UserMapper.queryUserById", 1l);
		System.out.println(user);
	} finally {
		// 关闭连接
		if (sqlSession != null) {
			sqlSession.close();
		}
	}
}

1.3.1 问题:无法连接到数据库服务器

产生这个问题的原因有很多,此处只讲一个情况
在这里插入图片描述
因为当前mysql的版本是8.0.31,而引入的依赖包是5.132所以导致了这个问题,只要引入8.X版本的依赖即可
在这里插入图片描述
同时8.X版本的驱动也要改
在这里插入图片描述

1.4 动态代理实现Mapper

1.XxxMapper接口

public interface UserMapper {
	/**
	 * 根据id获取用户信息
	 * @param id
	 * @return
	 */
	public User queryUserById(Long id);
	
	/**
	 * 查询所有用户
	 * @return
	 */
	public List<User> queryUserAll();
	
	/**
	 * 新增用户
	 * @param user
	 */
	public void insertUser(User user);
	
	/**
	 * 更新用户信息
	 * @param user
	 */
	public void updateUser(User user);
	
	/**
	 * 根据id删除用户信息
	 * @param id
	 */
	public void deleteUserById(Long id);
}

2.XxxMapper.xml

几个要求

  • Mapper接口和SQL映射文件放置在同一目录下
  • 名称空间必须改成XxxMapper接口的全路径
  • StatementId必须和接口方法名一致
  • 结果集的封装类型已经和方法的返回类型一致
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">

</mapper>

测试

public class UserMapperTest {
	
	private UserMapper userMapper;

	@Before
	public void setUp() throws Exception {
		// 读取mybatis的全局配置文件
		InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		// 构建sqlSessionFactory
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		// 获取sqlSession会话
		SqlSession sqlSession = sqlSessionFactory.openSession();

		// 初始化userDao
		this.userMapper = sqlSession.getMapper(UserMapper.class);
	}

	@Test
	public void testQueryUserAll() {
		List<User> userList = this.userMapper.queryUserAll();
		for (User user : userList) {
			System.out.println(user);
		}
	}

}

Mapper代理的底层,依旧是通过SqlSession来操作CRUD

为了实现在maven默认环境下打包时,Mybatis的接口和mapper文件在同一包中,可以通过将接口文件放在src/main/java某个包中,而在src/main/resources目录中建立同样的包,这是一种约定优于配置的方式,这样在maven打包的时候就会将src/main/java和src/main/resources相同包下的文件合并到同一包中。
在这里插入图片描述

1.5 mybatis-config.xml配置

mybatis-config.xml讲究严格的顺序,具体顺序遵循文档的顺序
在这里插入图片描述

1.5.1 properties属性读取外部资源

添加jdbc.properties资源文件:
在这里插入图片描述
jdbc.properties资源文件内容:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis-44
username=root
password=root

在Mybatis-config.xml中引入jdbc.properties资源文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
  
<configuration>
	<!-- 引入外部资源文件,resource:相对路径,url:绝对路径 -->
	<properties resource="jdbc.properties" />
	......
</configuration>

通过properties引入外部资源文件之后,就可以通过${xxx}的方式使用资源文件里的参数了。

1.5.2 settings设置

  • cacheEnabled(可以看mysql缓存章节的说明)
    • 该配置影响的所有映射器中配置的缓存的全局开关。
    • 默认值true
  • lazyLoadingEnabled
    • 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。
    • 默认值false
  • aggressiveLazyLoading
    • 当启用时,带有延迟加载属性的对象的加载与否完全取决于对任意延迟属性的调用;反之,每种属性将会按需加载。
    • 默认值true
  • mapUnderscoreToCamelCase
    • 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。
    • 默认值true
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
  
<configuration>
	<!-- 引入外部资源文件,resource:相对路径,url:绝对路径 -->
	<properties resource="jdbc.properties" />
	<settings>
		<!-- 开启驼峰匹配:经典的数据库列名(多个单词下划线连接)映射到经典的java属性名(多个单词驼峰连接) -->
		<setting name="mapUnderscoreToCamelCase" value="true"/>
	</settings>
</configuration>

1.5.3 typeAliases

在映射文件中用到java类型时,都是使用类的全路径,书写起来非常麻烦

typeAliases的几种方式:

  • 1.typeAlias 为每个pojo提供类型别名
    缺点:每个pojo类都要去配置。
<typeAliases>
	<!-- 引入外部资源文件,resource:相对路径,url:绝对路径 -->
	<properties resource="jdbc.properties" />
	<settings>
		<!-- 开启驼峰匹配:经典的数据库列名(多个单词下划线连接)映射到经典的java属性名(多个单词驼峰连接) -->
		<setting name="mapUnderscoreToCamelCase" value="true"/>
	</settings>
	<!-- 类型别名:type-pojo类的全路径,alias-别名名称(可随便写,推荐和类名一致) -->
	<typeAlias type="cn.itcast.mybatis.pojo.User" alias="user" />
</typeAliases>
  • 2.package 扫描包下所有类,扫描之后别名就是类名,不区分大小写,建议使用时与类名一致
<typeAliases>
	<!-- 类型别名:type-pojo类的全路径,alias-别名名称(可随便写,推荐和类名一致) -->
	<!-- <typeAlias type="cn.itcast.mybatis.pojo.User" alias="user" /> -->
	<!-- 开启别名包扫描,name:包路径,扫描的别名就是类名,并且大小写不敏感 -->
	<package name="cn.itcast.mybatis.pojo"/>
</typeAliases>

内置别名:
已经为普通的 Java 类型内建了许多相应的类型别名。它们都是大小写不敏感的,需要注意的是由于重载原始类型的名称所做的特殊处理。
在这里插入图片描述
在这里插入图片描述

1.5.4 typeHandlers(类型处理器)

  • 在预处理语句(PreparedStatement)中设置参数
    java类型 > 类型处理器 > jdbc类型
  • 从结果集取出一个值
    jdbc类型 > 类型处理器 > java类型

由于Java 类型和数据库的 JDBC 类型不是一一对应的(比如 String 与 varchar), 所以我们把 Java 对象转换为数据库的值,和把数据库的值转换成 Java 对象,需要经过 一定的转换,这两个方向的转换就要用到 TypeHandler

下表描述了一些Mybatis内置的类型处理器。
在这里插入图片描述
Mybatis标签之 typeHandlers 使用及解析

1.5.5 plugins(插件又称拦截器)

Mybatis 定义了四个处理器,用于做 SQL 执行的默认处理;如果我们不添加拦截器,则 Mybatis 会按默认操作进行处理。

  • Executor
  • ParameterHandler
  • StatementHandler
  • ResultSetHandler
    在这里插入图片描述
    执行顺序如下
    在这里插入图片描述

1.5.5.1 自定义拦截器

在这里插入图片描述

package com.itheima.mybatis.interceptor;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

/**
 * Intercepts:拦截器注解
 * 作用:标明此类为mybatis的拦截类
 * 前提:需要手动将此类注册到mybatis的拦截器链InterceptorChain中,才能生效
 * Signature:方法签名注解 (底层是通过反射实现)
 * 作用:表明拦截哪个处理器的哪个方法,即三个属性:
 * type:处理器类
 * method:方法名
 * args:方法参数
 */
@Intercepts({@Signature(type = Executor.class, method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class myExecutor implements Interceptor {
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
        Object obj = (Object) invocation.getArgs()[1];
        RowBounds rb = (RowBounds) invocation.getArgs()[2];
        ResultHandler rh = (ResultHandler) invocation.getArgs()[3];
        return null;
    }
}

配置自定义拦截器(也可以使用spring容器管理的方式来配置)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <plugins>
        <plugin interceptor="com.itheima.mybatis.interceptor.myExecutor"></plugin>
    </plugins>
</configuration>

作用:

  • 分页查询
  • 打印sql日志
  • 对返回结果,过滤掉审计字段,敏感字段
  • 对返回结果中的加密数据进行解密(全局解密)
  • 对新增数据自动添加创建人,创建时间,更新时间,更新人 ,对更新数据自动新增更新时间,更新人

Mybatis拦截器说明和使用
Mybatis之4大插件管理

1.5.6 environments(环境)

  • MyBatis 可以配置成适应多种环境,例如,开发、测试和生产环境需要有不同的配置;
  • 尽管可以配置多个环境,每个 SqlSessionFactory 实例只能选择其一。

几种方式:

  • 方法一:default
    在这里插入图片描述

  • 方法二:build方法
    在这里插入图片描述

1.5.7 Mappers

方式:

  • 方式一:resource
    在这里插入图片描述
    缺点:每次都要在mybatis-config.xml中引入映射文件,麻烦

  • 方式二: file
    在这里插入图片描述
    缺点:
    1.硬盘的位置可能随着项目的部署或迁移,路径发生变化
    2.每新增一个映射文件,就要在全局配置文件中引入

  • 方式三: class
    在这里插入图片描述
    缺点:
    1.java文件和xml映射文件耦合(需要在同一个文件夹下)
    2.每新增一个映射文件,就要在全局配置文件中引入

  • 方式四: package
    在这里插入图片描述
    缺点:
    1、如果包的路径有很多
    2、mapper.xml和mapper.java没有分离。

总结

  • 1.properties:引入外部资源文件,jdbc.properties 两种引入方式:url resource
  • 2.settings:行为参数, mapUnderscoreToCamelCase(驼峰匹配:从经典的数据库列名到经典的java属性名的映射)
  • 3.typeAliases:类型别名,typeAlias(type:类的全路径,alias:别名名称) package(name:包的全路径)
  • 4.typeHandlers:类型处理器
  • 5.plugins:插件、拦截器
  • 6.environments:环境,default:指定采用那个环境, environment:id-唯一标识,子标签:transactionManager:事务管理器 DataSource:数据源

1.6 Mapper.xml(映射文件)

在这里插入图片描述

1.6.1 CRUD操作

  • select标签
  • insert标签
  • update标签
  • delete标签

1.select标签
在这里插入图片描述
2.insert
在这里插入图片描述
3.update
在这里插入图片描述
4.delete
在这里插入图片描述

1.7 parameterType传入参数

CRUD标签都有一个属性parameterType,statement通过它指定接收的参数类型。

接收参数的方式有两种:

  • #{}预编译
  • ${}非预编译(直接的sql拼接,不能防止sql注入)

参数类型有三种:

  • 1、基本数据类型
  • 2、HashMap(使用方式和pojo类似)
  • 3、Pojo自定义包装类型

1.7.1 ${}的用法

使用场景:数据库有两个一模一样的表。历史表,当前表
查询表中的信息,有时候从历史表中去查询数据,有时候需要去新的表去查询数据。希望使用1个方法来完成操作。
![在这里插入图片描述](https://img-blog.csdnimg.cn/7f476f00600c46bca90fca8a4a1daf83.png
在这里插入图片描述

1.7.2 多个参数

在这里插入图片描述

当mapper接口要传递多个参数时,有两种传递参数的方法:

  • 1、默认规则获取参数{0,1…}、{param1,param2…}
    在这里插入图片描述
    在这里插入图片描述

  • 2、使用@Param注解指定参数名
    在这里插入图片描述
    在这里插入图片描述

1.7.3 HashMap

  • 简单类型通过#{key}或者${key}
  • 复杂类型通过${key.属性名}或者#{key.属性名}
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

1.7.4 面试题(#、$区别)

#{}的作用是防止sql注入(没有真实的预编译功能),所以我们每次执行sql,依旧要对sql语法进行检查和编译(可以参照PreparedStatement原理这一章节)
在这里插入图片描述

1.8 resultMap

在这里插入图片描述

1.8.1 解决列名和属性名不一致

查询数据的时候,查不到userName的信息,原因:数据库的字段名是user_name,而POJO中的属性名字是userName,两端不一致,造成mybatis无法填充对应的字段信息。

解决方案

  • 1.在sql语句中使用别名
  • 2.参考驼峰匹配 — mybatis-config.xml 的时候
  • 3.resultMap自定义映射

resultMap的解决方式
在这里插入图片描述

1.8.2 属性的作用

  • id
    此resultMap的唯一标识
  • type
    结果集的封装类型
  • autoMapping
    开启自动匹配,默认为true,没有手动指定映射的字段就会使用自动匹配
    如果开启了驼峰匹配,就会以驼峰匹配的形式进行

1.9 sql片段

在java代码中,为了提高代码的重用性,针对一些出现频率较高的代码,抽离出来一个共同的方法或者类

1.9.1 用法一:内部定义

在这里插入图片描述
在这里插入图片描述

1.9.1 用法二:外部定义

在这里插入图片描述
定义好sql片段的映射文件之后,接下来就该使用它了,首先应该把该映射文件引入到mybatis的全局配置文件中(mybatis-config.xml):
在这里插入图片描述
最后在需要使用该sql片段的地方通过include标签的refId属性引用该sql片段:<include refId=”名称空间.sql片段的id” />
在UserMapper.xml的映射文件中,进一步改造根据用户名查询用户信息
在这里插入图片描述

1.10 动态sql

在这里插入图片描述

1.10.1 if

<select id="queryUserListLikeUserName" resultType="User">
	select * from tb_user where sex=1
	<!-- if:判断
		test:OGNL表达式
	 -->
	<if test="userName!=null and userName.trim()!=''">
		 and user_name like '%' #{userName} '%'
	</if>
</select>

1.10.2 choose、when、otherwise

<select id="queryUserListLikeUserNameOrAge" resultType="User">
	select * from tb_user where sex=1 
	<!-- choose:条件选择
		when:test-判断条件,一旦有一个when成立,后续的when都不再执行
		otherwise:所有的when都不成立时,才会执行
	 -->
	<choose>
		<when test="userName!=null and userName.trim()!=''">and user_name like '%' #{userName} '%'</when>
		<when test="age != null">and age = #{age}</when>
		<otherwise>and user_name = 'zhangsan' </otherwise>
	</choose>
</select>

1.10.3 where

<select id="queryUserListLikeUserNameOrAge" resultType="User">
	select * from tb_user where sex=1 
	<!-- choose:条件选择
		when:test-判断条件,一旦有一个when成立,后续的when都不再执行
		otherwise:所有的when都不成立时,才会执行
	 -->
	<choose>
		<when test="userName!=null and userName.trim()!=''">and user_name like '%' #{userName} '%'</when>
		<when test="age != null">and age = #{age}</when>
		<otherwise>and user_name = 'zhangsan' </otherwise>
	</choose>
</select>

1.10.4 set

<update id="updateUserSelective" >
	UPDATE tb_user
	<!-- 
		set自动添加set关键字
		也有一定的纠错功能:自动去掉sql语句块之后多余的一个逗号
	 -->
	<set>
		<if test="userName!=null and userName.trim()!=''">user_name = #{userName},</if>
		<if test="password!=null and password.trim()!=''">password = #{password},</if>
		<if test="name!=null and name.trim()!=''">name = #{name},</if>
		<if test="age!=null">age = #{age},</if>
		<if test="sex!=null">sex = #{sex}</if>
	</set>
	WHERE
		(id = #{id});
</update>

1.10.5 foreach

/**
* 根据多个id查询用户信息
 * @param ids
 * @return
 */
public List<User> queryUserListByIds(@Param("ids")Long[] ids);
<select id="queryUserListByIds" resultType="User">
	select * from tb_user where id in 
	<!-- 
		foreach:遍历集合
		collection:接收的集合参数
		item:遍历的集合中的一个元素
		separator:分隔符
		open:以什么开始
		close:以什么结束
	 -->
	<foreach collection="ids" item="id" separator="," open="(" close=")">
		#{id}
	</foreach>
</select>

1.11 缓存

执行相同的sql语句参数,mybatis不进行执行sql,而是从缓存中命中返回。

  • 一级缓存的作用域是同一个sqlsession内;
  • 二级缓存作用域是针对mapper进行缓存;

一级缓存是默认使用的,二级缓存需要手动开启。

1.11.1 一级缓存

在mybatis中,一级缓存默认是开启的,并且一直无法关闭,作用域:在同一个sqlSession下
在这里插入图片描述
在这里插入图片描述

前提:

  • 同一个Mapper对象(底层使用sqlSession,本质上要求同一个sqlSession)
  • 执行相同的sql语句,以及参数相同

参数不同,就不会走缓存
在这里插入图片描述

1.11.1.1 清除一级缓存 方式一:clearCache

使用:sqlSession.clearCache();可以强制清除缓存

@Test
public void testCache(){
	User user1 = this.userMapper.queryUserById(1l);
	System.out.println(user1);
	this.sqlSession.clearCache();
	System.out.println("=================第二次查询======================");
	User user2 = this.userMapper.queryUserById(1l);
	System.out.println(user2);
}

1.11.1.2 清除一级缓存 方式二:执行update、insert、delete的时候,会清空缓存

@Test
public void testCache(){
	User user1 = this.userMapper.queryUserById(1l);
	System.out.println(user1);
//		this.sqlSession.clearCache();
	System.out.println("================更新======================");
	User user = new User();
	user.setAge(18);
	user.setName("柳岩");
	user.setPassword("123456");
	user.setUserName("yanyan2");
//		user.setSex(3);
	user.setBirthday(new Date());
	user.setId(12l);
	this.userMapper.updateUser (user);
	System.out.println("=================第二次查询======================");
	User user2 = this.userMapper.queryUserById(1l);
	System.out.println(user2);
}

由于insert、update、delete会清空缓存,所以第二次查询时,依然会输出sql语句,即从数据库中查询。
在这里插入图片描述

1.11.2 二级缓存

mybatis 的二级缓存的作用域:

  • 1、同一个mapper的nameSpace,同一个nameSpace中查询sql可以从缓存中命中
  • 2、跨sqlSession,不同的sqlSession可以从二级缓存命中

怎么开启二级缓存:

  • 1、在映射文件中,添加<cache />标签
    在这里插入图片描述

  • 2、在全局配置文件中,设置cacheEnabled参数,默认已开启。
    在这里插入图片描述

注意:

  • 由于缓存数据是在sqlSession调用close方法时,放入二级缓存的,所以第一个sqlSession必须先关闭
  • 二级缓存的对象必须序列化,例如:User对象必须实现Serializable接口。
    在这里插入图片描述

测试功能

@Test
public void testCache2(){
	User user1 = this.userMapper.queryUserById(1l);
	System.out.println(user1);
	// 注意:关闭sqlSession
	sqlSession.close();
	System.out.println("=================第二次查询======================");
	// 重新打开一个sqlSession会话
	SqlSession sqlSession2 = this.sqlSessionFactory.openSession();
	// 通过sqlSession2重新实例化UserMapper
	this.userMapper = sqlSession2.getMapper(UserMapper.class);
	User user2 = this.userMapper.queryUserById(1l);
	System.out.println(user2);
}

日志
在这里插入图片描述

执行update、insert、delete的时候,会清空缓存


2.Mybatis的高级查询

2.1 一对一查询

基于订单编号查询订单信息,同时获取此订单的下单人
在这里插入图片描述
两种实现方式:

  • 扩展订单(order类)信息
    创建OrderUser继承Order类,同时提供User类的属性
    在这里插入图片描述
    将结果封装成OrderUser对象
    在这里插入图片描述
  • 添加User属性的方式
    就是在Order对象中添加user属性。
    在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.OrderMapper">

	<resultMap type="Order" id="orderUserMap" autoMapping="true">
		<id column="id" property="id"/>
		<!--
			association:一对一的映射
				property:属性名
				javaType:属性对应的java类型
				autoMapping:自动映射
				子标签:参照resultMap
		 -->
		<association property="user" javaType="User" autoMapping="true">
			<id column="user_id" property="id"/>
		</association>
	</resultMap>
	
	<!-- resultType不能完成user信息的映射,必须使用resultMap,resultMap的值对应resultMap标签的id,resultMap和resultType必须二选一 -->
	<select id="queryOrderWithUser" resultMap="orderUserMap">
		SELECT * FROM tb_order a 
		INNER JOIN tb_user b on a.user_id=b.id
		where a.order_number=#{number}
	</select>

</mapper>

2.2 一对多查询

订单 : 订单详情 = 1 : n
在这里插入图片描述

在这里插入图片描述

/**
 * 查询订单,查询出下单人信息并且查询出订单详情。
 * @param number
 * @return
 */
public Order queryOrderWithUserDetail(@Param("number")String number);
<resultMap type="Order" id="orderUserDetailMap" autoMapping="true">
	<id column="id" property="id"/>
	<association property="user" javaType="User" autoMapping="true">
		<id column="user_id" property="id"/>
	</association>
	<!-- 
		collection:一对多的查询
		property:属性名
		javaType:集合类型
		ofType:集合中的元素类型
		autoMapping:开启自动映射
		子标签:参照resultMap
	 -->
	<collection property="detailList" javaType="list" ofType="Orderdetail" autoMapping="true">
		<id column="detail_id" property="id"/>
	</collection>
</resultMap>

<select id="queryOrderWithUserDetail" resultMap="orderUserDetailMap">
	select *,c.id as detail_id from tb_order a
		LEFT JOIN tb_user b on a.user_id=b.id
		LEFT JOIN tb_orderdetail c on a.id=c.order_id
	where a.order_number=#{number}
</select>

2.3 多对多查询

订单:订单详情 = 1 : n
订单详情:商品 = 1 : 1

在这里插入图片描述

<resultMap type="Order" id="orderUserDetailItemMap" autoMapping="true">
	<id column="id" property="id"/>
	<association property="user" javaType="User" autoMapping="true">
		<id column="user_id" property="id"/>
	</association>
	<collection property="detailList" javaType="list" ofType="Orderdetail" autoMapping="true">
		<id column="detail_id" property="id"></id>
		<association property="item" javaType="Item" autoMapping="true">
			<id column="item_id" property="id"/>
		</association>
	</collection>
</resultMap>

<select id="queryOrderWithUserDetailItem" resultMap="orderUserDetailItemMap">
	select *,c.id as detail_id from tb_order a
		LEFT JOIN tb_user b on a.user_id=b.id
		LEFT JOIN tb_orderdetail c on a.id=c.order_id
		LEFT JOIN tb_item d on c.item_id=d.id
	where a.order_number=#{number}
</select>

2.4 resultMap的继承

在这里插入图片描述

2.5 延迟加载

在这里插入图片描述
采用之前的配置方式(参考高级查询),肯定是不能做到延迟加载的,因为咱是通过一个查询sql直接查询出所有的数据。为了测试延迟加载的效果,必须改造高级查询的配置,使Order的查询和User或者OrderDetail的查询分开。只有当我们访问Order对象的User或者OrderDetail属性时,才去执行User或者OrderDetail的查询。

2.5.1 改造一对一查询

在这里插入图片描述
处理组合键时,需要传递多个参数,可以使用column=”{prop1=col1, prop2=col2, prop3=col3…}”,设置多个列名传入到嵌套查询语句,mybatis会把prop1,prop2,prop3设置到目标嵌套的查询语句中的参数对象中。

子查询中,必须通过prop1,prop2,prop3获取对应的参数值,你也可以使用这种方式指定参数名例如:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.5.2 开启延迟加载

在mybatis-config.xml中配置行为参数
在这里插入图片描述
在这里插入图片描述

执行,报错:
在这里插入图片描述
说明延迟加载需要cglib的支持。
在pom.xml中,添加cglib的依赖:

<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>3.1</version>
</dependency>

在这里插入图片描述

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

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

相关文章

【Substance Designer】基础操作和节点学习记录

写在前面 这个记录稍微有点杂&#xff0c;大概是庄懂的技术美术入门课(美术向)-直播录屏-第20课和一些基础操作的记录合集吧&#xff01; 补充 学习发现&#xff0c;基础的节点是需要学习和记录的&#xff0c;但是真正用起来还是要多用多练&#xff01;所以这种简单的记录节点…

YOLOv5/v7 引入 RepVGG 重参数化模块

本篇博文代码出自YOLOv5-lite &#xff0c;YOLOv5-lite的作者在CSDN的账号是 pogg_ &#xff0c;大家可以关注一下&#xff0c;这也是一位在开源项目上做了很多工作的博主。 RepVGG的原理和融合推导过程可以看我的这篇博文&#xff1a;RepVGG&#xff1a;让VGG风格的ConvNets再…

机制设计原理与应用(三)Screening

文章目录3 Screening3.1 为单个不可分割的项目定价3.1.1 对θ\thetaθ的假设3.1.2 问题描述3.1.3 特性3.2 为无限可分的项目定价3.2.1 对θ\thetaθ的假设3.2.3 特性3.2.4 收益最大化3.2.5 最优解决方案3 Screening Screening theory&#xff1a;机制设计理论可以被看作是其多…

Cadence PCB仿真使用Allegro PCB SI生成振铃ringing仿真报告及报告导读图文教程

🏡《Cadence 开发合集目录》   🏡《Cadence PCB 仿真宝典目录》 目录 1,概述2,生成报告3,报告导读4,总结1,概述 本文简单介绍使用Allegro PCB SI生成网络的振铃性能评估的报告的方法,及振铃ringing报告要点导读。 2,生成报告 第1步,选择需要生成报告的网络,然后…

第二章 ArcGIS数据和地理数据库

文章目录第一节 ArcGIS和4D数据基本知识1 4D数据介绍1.1 DLG1.2 DEM1.3 DOM1.4 DRG1.5 4D表现2 ArcGIS的数据和4D数据对应3 栅格数据3.1 查看帮助3.2 空间分辨率3.3 分辨率与比例尺换算3.4 栅格数据介绍——cellsize3.5 栅格数据波段3.6 栅格格式4 栅格数据改变分辨率5 转换栅格…

【 uniapp - 黑马优购 | 登录与支付(2)】如何实现三秒后跳转和微信支付

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大二在校生&#xff0c;讨厌编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;小新爱学习. &#x1f43c;个人WeChat&#xff1a;见文末 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;…

Ubuntu20.04+MAVROS+PX4+Gazebo安装教程

Ubuntu20.04MAVROSPX4Gazebo安装PX4步骤安装MAVROS安装QGCPX4仿真安装PX4步骤 从github上clone源码 git clone https://github.com/PX4/PX4-Autopilot.git --recursive进入PX4-Autopilot文件夹&#xff0c;继续下载未下载完的组件 cd PX4-Autopilot/ git submodule update -…

flowable使用 act_hi_xxx

HistoryService 流程历史信息 act_hi_procinst : 历史流程信息&#xff0c;&#xff0c;如果流程执行完了&#xff0c;end_time_ 和 duration不为null // 没有执行完的List<HistoricProcessInstance> list historyService.createHistoricProcessInstanceQuery().unfi…

uniapp封装并全局挂载request请求

前言 日常开发中,前端项目中需要调用服务端api完成页面渲染,uniapp提供的请求api:uni.request相对繁琐;另外服务端提供的不同api仅子路径不同,api域名以及根路径都是相同的,一旦接口api变更,需要更改地方就会很多.鉴于以上可以将uni.request进行封装,简化开发. 目前uniapp项…

MySQL(四):B+树索引、聚簇索引、二级索引、联合索引

目录一、B树索引1.1 在没有索引时进行查找记录1.2 索引方案1.3 InnoDB中的索引方案二、聚簇索引三、二级索引四、联合索引五、InnoDB中B树索引的注意事项5.1 根页面的位置不会改变5.2 内节点中目录项记录的唯一性5.3 一个页面至少容纳两条记录一、B树索引 数据库中的用来存储数…

MySQL进阶篇之索引1

02、索引 2.1、索引概述 1、介绍 索引&#xff08;index&#xff09;是帮助MySQL高效获取数据的数据结构&#xff08;有序&#xff09;。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&#xff08;指向&#…

Cepstral Analysis 倒谱分析

源过滤器分离 倒谱分析是另一种将声道滤波器响应与激励分开的方法&#xff08;如线性预测&#xff09; 它基于以下观察&#xff1a;语音信号的频谱是激励频谱和声道频率响应的乘积 可以使用log将乘法转换为加法&#xff0c;因此&#xff0c;“对数频谱”可以看作是对数激励频…

十七、Gtk4-Menu and action

Menu 用户经常使用菜单向计算机发出命令。它是这样的: 现在让我们分析一下上面的菜单。对象有两种类型。 “File”, “Edit”, “View”, “Cut”, “Copy”, “Paste” and “Select All”. 它们被称为“菜单项&#xff08;menu item&#xff09;”或简单地称为“item”。当…

字节青训前端笔记 | 前端调试

在程序员的世界中&#xff0c;BUG 一词相信同学们再熟悉不过了&#xff0c;本节课将围绕前端开发中所遇见的 BUG 出发&#xff0c;讲解作为一名合格的前端开发人员&#xff0c;你应该掌握哪些开发调试知识 Chorme DevTools Chorme DevTools 是 chorme内核为大家提供的高效的前…

gdb使用

gdb是一款UNIX及UNIX-like下的调试工具 gdb可用于调试用gcc编译的可执行文件&#xff0c;用gdb调试时gcc编译需要使用参数-g 本文是对于gdb在Linux下使用的基本命令的总结gdb调试视频演示&#xff0c;gdb调试基础指令&#xff0c;gdb调试其他命令&#xff0c;gdb常见错误说明 目…

23种设计模式(二十一)——命令模式【行为变化】

文章目录 意图什么时候使用命令真实世界类比命令模式的实现命令模式的优缺点亦称:动作、事务、Action、Transaction、Command 意图 将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递…

Centos7 Docker安装APISIX

Centos7 Docker安装APISIX1 基础介绍1.1 概念1.2 特性1.3 架构图2 快速安装2.1 前提条件2.2 安装步骤2.2.1 git命令克隆apisix-docker仓库2.2.2 docker-compose启动apisix2.2.3 访问apisix dashboard3 简单使用3.1 准备接口3.2 创建服务3.3 创建路由3.4 测试请求1 基础介绍 1.…

Kubernetes:分享一个很简洁的 k8s 管理工具 Skooner

写在前面 博文内容为 Skooner 简单介绍包括下载安装导入集群基本功能使用Skooner 的 sa 使用的当前命名空间默认的 sa不会显示创建 sa ,当然可以单独创建理解不足小伙伴帮忙指正 我所渴求的&#xff0c;無非是將心中脫穎語出的本性付諸生活&#xff0c;為何竟如此艱難呢 -----…

Spring_FrameWork_10(MyBatisPlus)

lombok mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplTestvoid selectById(){IPage page new Page(2,2);bookDao.selectPage(page,null);System.out.println("当前页码值&#xff1a;"page.getCurrent());System.out.println…

Java---微服务---Nacos集群搭建

Nacos集群搭建1.集群结构图2.搭建集群2.1.初始化数据库2.2.下载nacos2.3.配置Nacos2.4.启动2.5.nginx反向代理2.6.优化1.集群结构图 官方给出的Nacos集群图&#xff1a; 其中包含3个nacos节点&#xff0c;然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。 我们…