Mybatis框架的知识点总结

配合此博客 码云仓库地址:https://gitee.com/maoniya/maoni_-mybatis-demo.git

MyBatis官网地址:https://mybatis.org/mybatis-3/zh/configuration.html

maven项目中Mybatis依赖的地址:https://mvnrepository.com/artifact/org.mybatis/mybatis/3.5.4

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.4</version>
</dependency>

什么是mybatis?

  1. 代替jdbc完成对数据库的操作

  2. 简化操作流程,将重复的流程进行封装从而实现对数据库的存储过程及高级映射

  3. 本质:通过简单的xml或注解来配置和映射Java对象到数据库中

核心流程

核⼼流程: https://mybatis.org/mybatis-3/zh/getting-started.html

  1. 每个基于 MyBatis 的应⽤都是以⼀个 SqlSessionFactory 的实例为核⼼

  2. SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得

  3. SqlSessionFactoryBuilder 可以从 XML 配置⽂件或⼀个预先配置的 Confifiguration 实例来构

建出 SqlSessionFactory 实例

  1. ⼯⼚设计模式⾥⾯ 需要获取SqlSession ,⾥⾯提供了在数据库执⾏ SQL 命令所需的所有⽅

流程图:

在这里插入图片描述

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>
<!--    environments环境可以配置多个如开发环境,线上环境-->
    <environments default="development">
        <environment id="development">
<!--        transactionManager    事务管理-->
            <transactionManager type="JDBC"/>
<!--            连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url"
                          value="jdbc:mysql://127.0.0.1:3306/maoni_test2?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
		<!-- 一张表对应一个mapper文件-->
        <mapper resource="mapper/VideoMapper.xml"/>
    </mappers>
    
</configuration>

配置VideoMapper.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:名称空间,保持全局唯一,最好是和dao层的java接口一致,可以自动映射接口里的方法
映射sql语句到对应的方法和参数,返回类型
mybatis 使用接口动态代理,所以namespace需要全路径
-->
<mapper namespace="net.maoni.mavenDemo2.dao.VideoMapper">
    <!--
    statement:sql
    id:mapper接口下的方法名
    resultType:sql查询的结果集,返回接受的类型
    -->
    <select id="selectById" resultType="net.maoni.mavenDemo2.domain.Video">
        select * from video where id = #{video_id}
    </select>
</mapper>

获取参数的值

  • 注意 :取java对象的某个值,属性名⼤⼩写要⼀致

#{value} : 推荐使⽤, 是java的名称

${value} : 不推荐使⽤,存在sql注⼊⻛险

什么是sql注入风险?

编写代码 获取 SqlSession,以xml⽅式读取数据库

public class SqlSessionDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    

        String resouce ="config/mybatis-config.xml";
        //读取配置文件,构建io流
        InputStream inputStream = Resources.getResourceAsStream(resouce);
        //构建sqlsessionfactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取Session
        try(SqlSession sqlSession=sqlSessionFactory.openSession()){
    
    
            VideoMapper videoMapper =sqlSession.getMapper(VideoMapper.class);
            Video video = videoMapper.selectById(44);
//            System.out.println(video.toString());
            List<Video> list = videoMapper.selectList();
            for(Video i:list){
    
    
                System.out.println(i.toString());
            }
        }
    }
}

俩种去读方式 一种是通过xml,一种是通过注解的方式读取

通过注解读取(如果sql简单,没有过多的表关联,则⽤注解相对简单)

public interface VideoMapper {
    
    
    // 根据视频id查找视频对象
    Video selectById(@Param("video_id") int videoId);

    //查询全部视频列表
    @Select("select * from video")
    List<Video> selectList();
}

mybatis的使用流程

  1. 创建mybatis-confifig.xml 全局的配置⽂件

  2. 创建XXXMapper.xml配置⽂件

  3. 创建SqlSessionFactory

  4. ⽤SqlSessionFactory创建SqlSession对象

  5. ⽤SqlSession执⾏增删改查CRUD

代码如上图:编写代码 获取 SqlSession,以xml⽅式读取数据库

Mybatis实战参数别名使⽤之查询视频列表

VideoMapper.xml层

<select id="selectPyPointAndTitleLike" resultType="net.maoni.mavenDemo2.domain.Video">
        select * from video where point=#{point} and title like concat('%',#{title},'%')
</select>

模糊查询用 concat(),如上图所示

Mapper层

/**
     * 根据评分和标题模糊查询
     * @param point
     * @param title
     * @return
     */
    List<Video> selectPyPointAndTitleLike(@Param("point") Double point,@Param("title")String title);

实现层

 public static void main(String[] args) throws IOException {
    
    

        String resouce ="config/mybatis-config.xml";
        //读取配置文件,构建io流
        InputStream inputStream = Resources.getResourceAsStream(resouce);
        //构建sqlsessionfactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取Session
        try(SqlSession sqlSession=sqlSessionFactory.openSession()){
    
    
            VideoMapper videoMapper =sqlSession.getMapper(VideoMapper.class);
            /多参数模糊查询
            List<Video> video2 = videoMapper.selectPyPointAndTitleLike(8.7,"HTML");
            for(Video i:video2){
    
    
                System.out.println(i.toString());
            }
        }
    }
}

Mybatis插入语法新增和如何获取自增主键

新增的语法

<insert id="add" parameterType="net.maoni.mavenDemo2.domain.Video">        
	INSERT INTO `maoni_test2`.`video`(`title`, `summary`, `cover_img`, `price`, `create_time`, `point`)        
	VALUES 
	(#{title,jdbcType=VARCHAR}, #{summary,jdbcType=VARCHAR},#{coverImg,jdbcType=VARCHAR}, #{price,jdbcType=INTEGER},                
	#{createTime,jdbcType=TIMESTAMP}, #{point,jdbcType=DOUBLE});    
</insert>

注:{coverImg,jdbcType=VARCHAR}和 #{createTime,jdbcType=TIMESTAMP},因为在配置mybatis-config.xml时加了

<settings>       
	<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

所以变量名需和domain或者pojo中的保持一致.在Server层的实现类中实现add方法.

//新增一条记录    
 Video video03=new Video();    
 video03.setTitle("常熟第一人民医院");    
 video03.setCoverImg("http://www.baidu.com");   
 video03.setPoint(9.4);    
 video03.setCreateTime(new Date());    
 video03.setPrice(9900);    
 video03.setSummary("炸u你");    
 videoMapper.add(video03);    
 System.out.println("插入成功");

获取自增主键

mapper.xml里:

<insert id="add" parameterType="net.maoni.mavenDemo2.domain.Video"useGeneratedKeys="true" keyProperty="id" keyColumn="id">
	INSERT INTO `maoni_test2`.`video`(`title`, `summary`, `cover_img`, `price`, `create_time`, `point`)     
	VALUES (#{title,jdbcType=VARCHAR}, #{summary,jdbcType=VARCHAR},#{coverImg,jdbcType=VARCHAR}, #{price,jdbcType=INTEGER},
	#{createTime,jdbcType=TIMESTAMP}, #{point,jdbcType=DOUBLE});
</insert>

注:如上图插入显示, 在 i n s e r t 标 签 最 后 面 加 入 \textcolor{red}{在insert标签最后面加入} insert useGeneratedKeys=“true” keyProperty=“id” keyColumn=“id”,在表video中自增主键为id,将其自主映射到java封装的video类里

执行实现类里的方法:

    //新增一条记录    
    Video video03=new Video();    
    video03.setTitle("常熟第一人民医院");    
    video03.setCoverImg("http://www.baidu.com");    
    video03.setPoint(9.4);    
    video03.setCreateTime(new Date());    
    video03.setPrice(9900);    
    video03.setSummary("炸u你");    
    int rows = videoMapper.add(video03);    
    System.out.println("插入成功:"+rows);    
    System.out.println(video03.toString());

结果显示:

image-20210719093230842

如上图:id=51 ,将其主键映射出来

Mybatis实现foreach批量插入语法

语法及标签介绍

  • 批量插入多条数据

  • foreach:用于循环拼接的内置标签,常用于批量的新增\in查询,如下是foreach标签内的属性

    • collection:必填,值为要迭代循环的集合类型,情况有多种

      • 入参为list类型的时候,collection属性的值为list
      • 入参为map类型的时候,collection属性的值为map的key值
    • item:每⼀个元素进⾏迭代时的别名

    • index:索引的属性名,在集合数组情况下值为当前索引值,当迭代对象是map时,这个值是

      map的key(没有用到)

    • open:整个循环内容的开头字符串(没有用到)

    • close:整个循环内容的结尾字符串(没有用到)

    • separator: 每次循环的分隔符

例子:

在mapper.xml里

<!--    批量插入数据-->
<insert id="addBatch" parameterType="net.maoni.mavenDemo2.domain.Video">    
	INSERT INTO `maoni_test2`.`video`(`title`, `summary`, `cover_img`, `price`, `create_time`, `point`)    
	VALUES <foreach collection="list" item="video" index="index" separator=","> (#{video.title,jdbcType=VARCHAR}, 
	#{video.summary,jdbcType=VARCHAR},#{video.coverImg,jdbcType=VARCHAR}, #{video.price,jdbcType=INTEGER},
	#{video.createTime,jdbcType=TIMESTAMP}, #{video.point,jdbcType=DOUBLE})</foreach>
</insert>

注:

  • 在批量插入数据时,item的别名一定要有,如:#{video.title,jdbcType=VARCHAR}
  • 在插入语句的最后去掉 “;”

在实现类里

/*** 批量插入数据*/
Video video04=new Video();
video04.setTitle("九龙第一人民医院");
video04.setCoverImg("http://www.谷歌.com");
video04.setPoint(8.3);
video04.setCreateTime(new Date());
video04.setPrice(9922);
video04.setSummary("fuck you");

Video video05=new Video();video05.setTitle("广慈第一人民医院");
video05.setCoverImg("http://www.广慈.com");
video05.setPoint(8.7);
video05.setCreateTime(new Date());
video05.setPrice(9933);
video05.setSummary("i love you");
//创建list,将video对象放入list表中开始批量插入'
List<Video> listBatch =new ArrayList<>();
listBatch.add(video04);
listBatch.add(video05);
int rows02 = videoMapper.addBatch(listBatch);
System.out.println(rows02);
System.out.println(listBatch.toString());

结果:

image-20210719105110421

Mybatis实现更新和删除

更新语法

在mapper.xml里

<!--    更新-->    
<update id="updateVideo" parameterType="net.maoni.mavenDemo2.domain.Video">        
	update video set title=#{title,jdbcType=VARCHAR},summary=#{summary,jdbcType=VARCHAR},cover_img=#{coverImg,jdbcType=VARCHAR},            		
	price=#{price,jdbcType=INTEGER},create_time=#{createTime,jdbcType=TIMESTAMP},point=#{point,jdbcType=DOUBLE}  where id =#{id}
</update>
<!--    删除-->    
<delete id="deleteVideo" parameterType="net.maoni.mavenDemo2.domain.Video">        
	delete from video where id=#{id}    
</delete>

实现层里

/*** 更新*/
Video video06 =new Video();
video06.setTitle("上海妇幼医院");
video06.setCoverImg("whwhd.shanghai.com");
video06.setPoint(9.9);
video06.setCreateTime(new Date());
video06.setPrice(963);
video06.setId(165);
int rows03 = videoMapper.updateVideo(video06);
System.out.println(rows03);
/*** 删除*/
Video video07 =new Video();
video07.setId(165);
int rows07 = videoMapper.deleteVideo(video07);
System.out.println(rows07);

动态字段更新(if test标签使用)

  • 可以选择性的更新非空字段

  • if test标签介绍

    • if 标签可以通过判断传⼊的值来确定查询条件,test 指定⼀个OGNL表达式
    • 常⻅写法
    //当前字段符合条件才更新这个字段的值
    <if test='title != null and id == 87 '> title = #{title}, </if><if test="title !=null"> title = #{title},
    

    当前字段不为空且id值为87的才会更新title字段

例子:

在mapper.xml里

<!--    动态字段更新-->
<update id="updateVideoSelective" parameterType="net.maoni.mavenDemo2.domain.Video">    
	update video    
	-- trim标记更新字段的结尾是以","结尾    
	-- test 指定⼀个OGNL表达式,test中的属性值为java封装类中的变量名    
	<trim prefix="set" suffixOverrides=",">        
		<if test="title !=null">title=#{title,jdbcType=VARCHAR},</if>        
		<if test="summary !=null">summary=#{summary,jdbcType=VARCHAR},</if>        
		<if test="coverImg !=null">cover_img=#{coverImg,jdbcType=VARCHAR},</if>        
		<if test="price !=0">price=#{price,jdbcType=INTEGER},</if>        
		<if test="createTime !=null">create_time=#{createTime,jdbcType=TIMESTAMP},</if>        
		<if test="point !=null">point=#{point,jdbcType=DOUBLE},</if>    
	</trim>    
	where    id =#{id}
</update>

实现类里:

/*** 动态字段更新*/
Video video08 =new Video();
video08.setTitle("上海妇幼医院");
video08.setCoverImg("whwhd.shanghai.com");
video08.setPoint(9.9);
video08.setCreateTime(new Date());
video08.setPrice(963);
video08.setId(46);
int rows08=videoMapper.updateVideoSelective(video08);
System.out.println(rows08);

结果:选择性地更新了数据库中字段对应的数据.

Mybatis实现删除语法和转义字符使用

delete删除语法

  • 需求:删除时间大于 and 金额小于
<delete id="deleteByCreateTimeAndPrice" parameterType="java.util.Map">        
	delete from video where create_time  <![CDATA[ >= ]]> #{createTime} and price  <!		[CDATA[ <= ]]> #{price}
</delete>

为什么要转义字符

  • 由于MyBatis的sql写在XML⾥⾯, 有些sql的语法符号和xml⾥⾯的冲突

    如:大于和小于 <> 与xml格式里的<> 冲突

⼤于等于 <![CDATA[ >= ]]>⼩于等于 <![CDATA[ <= ]]>

在mapper.xml里:

<!--    
	<![CDATA[ >= ]]> 转义字符  : > 大于    
	<![CDATA[ <= ]]> 转义字符  : < 小于
-->    
<delete id="deleteByCreateTimeAndPrice" parameterType="java.util.Map">        
	delete from video where create_time  <![CDATA[ >= ]]> #{createTime} and price  <![CDATA[ <= ]]> #{price}    
</delete>

实现类:

/*** 根据创建时间和价格删除
  * 时间>createTime
  * 价格<price
  * 都进行删除
  */
  Map<String,Object> map =new HashMap<>();
  map.put("createTime","2021-01-11 00:00:00");
  map.put("price",10000);
  int rows09 = videoMapper.deleteByCreateTimeAndPrice(map);
  System.out.println(rows09);

MyBatis3.X配置⽂件mybatis-confifig.xml常⻅属性

mybatis-config.xml常⻅配置

注:核⼼配置⽂件(dom节点顺序要求,不然报错)(记住常用的)

官方文档:https://mybatis.org/mybatis-3/zh/confifiguration.html#

configuration(配置)     
	properties(属性)     
	settings(设置)     
	typeAliases(类型别名)     
	typeHandlers(类型处理器)     
	objectFactory(对象⼯⼚)     
	plugins(插件,少⽤)     
	environments(环境配置,不配多环境,基本在Spring⾥⾯配置)     
	environment(环境变量)         
		transactionManager(事务管理器)         
		dataSource(数据源)
databaseIdProvider(数据库⼚商标识)
mappers(映射器)

Mybatis的查询类别名typeAlias的使⽤

给类取别名

在mybatis-config.xml里配置

<!--    给类取个别名,这样在mapper.xml不用输入类的全限定名-->    
<typeAliases>        
	<typeAlias type="net.xdclass.online_class.domain.Video" alias="Video"/>   
</typeAliases>

在mapper.xml里

<select id="selectById" resultType="Video">	
	select * from video where id = #{videoId}
</select>

给包区别名

如果包里存在很多类不需要一个个配置,扫描包即可

在mybatis-config.xml里配置

<typeAliases>
	<!--        <typeAlias type="net.maoni.mavenDemo2.domain.Video" alias="Video"/>-->	
	<package name="net.maoni.mavenDemo2.domain"/>
</typeAliases>

在mapper.xml里

<select id="selectById" resultType="Video">
	select * from video where id = #{videoId}
</select>

注:本身就内置很多别名,⽐如Integer、String、List、Map 等

如:

<delete id="deleteByCreateTimeAndPrice" parameterType="Map">    
	delete from video where create_time  <![CDATA[ >= ]]> #{createTime} and price  <![CDATA[ <= ]]> #{price}
</delete>

Mybatis里sql片段的使用(高性能sql)

在mapper.xml里标签下的最上方加标签

如:

<sql id="base_video_field">   
	id,title,summary,cover_img
</sql>

在mapper.xml里标签下的查询方法里

<select id="selectById" resultType="Video">    
	select <include refid="base_video_field"/> from video where id = #{videoId}
</select>

接下来就是实现类里的事情了

Mybatis下的复杂sql查询

resultMap讲解及简单使用

Mybatis的SQL语句返回结果有两种

  • resultType
    • 查询出的字段在相应的pojo中必须有和它相同的字段对应,或者基本数据类型
    • 适合简单查询
  • resultMap
    • 需要⾃定义字段,或者多表查询,⼀对多等关系,⽐resultType更强⼤
    • 适合复杂查询

resultMap简单使用

在mapper.xml里先配置resultMap的结果集

<resultMap id="VideoResultMap" type="Video">        
<!--  id 指定查询列的唯⼀标示   column 数据库字段的名称     property pojo类的名称-->        
	<id column="id" property="id" jdbcType="INTEGER"/>        
	<result column="video_title" property="title" jdbcType="VARCHAR"/>        
	<result column="summary" property="summary" jdbcType="VARCHAR"/>        
	<result column="cover_img" property="coverImg" jdbcType="VARCHAR"/>
</resultMap>

在配置的下面写上查询方法

 <select id="selectBaseFileByIdWithResultMap" resultMap="VideoResultMap">        
 	select id,title as video_title,summary,cover_img from video where id =#{video_id}
 </select>

注:

select中的resultMap值对应resultMap标签里的id值,

select标签里的id对应接口里的方法名

ResultMap复杂对象⼀对⼀查询结果映射之association

简述:A表与B表有关联,且B表中有且只有一条数据与A表有关联,在进行B关联A查询时,将A中的数据查询出来的同时也将B表中的数据查询出来

首先在mapper.xml里配置resultMap,然后在resultMap的标签里association映射到需要查询的表中,具体步骤如下

<resultMap id="VideoOrderResultMap" type="VideoOrder">        
	<id column="id" property="id"/>        
	<result column="user_id" property="userId" />        
	<result column="out_trade_no" property="outTradeNo" />        
	<result column="create_time" property="createTime" />        
	<result column="state" property="state"/>        
	<result column="total_fee" property="totalFee"/>        
	<result column="video_id" property="videoId"/>        
	<result column="video_title" property="videoTitle"/>        
	<result column="video_img" property="videoImg"/>
	<!--        关联的是哪个对象 ,对象的类型是什么 -->
	<!--        association 配置属性一对一 property 对应videoOrder里面的user属性名 javatype 对应user属性的类型-->        
	<association property="user" javaType="User">            
		<id column="user_id" property="id" />            
		<result column="name" property="name" />            
		<result column="head_img" property="headImg" />           
		<result column="create_time" property="createTime" />            
		<result column="phone" property="phone" />        
	</association>
</resultMap>

查询的语句

<select id="queryVideoOrderList" resultMap="VideoOrderResultMap">        
	select            
		o.id id,            
		o.user_id ,            
		o.out_trade_no,            
		o.create_time,            
		o.state,            
		o.total_fee,            
		o.video_id,            
		o.video_title,            
		o.video_img,            
		u.name,            
		u.head_img,            
		u.create_time,            
		u.phone        
	from video_order o left join user u on o.user_id =u.id;
</select>

完善接口和实现类

List<VideoOrder> queryVideoOrderList();
List<VideoOrder> videoOrderList =videoOrderMapper.queryVideoOrderList();System.out.println(videoOrderList.toString());

调试debug:image-20210720105809209

结果集显示查询结果6个,每个结果集里都会包含一个user对象及其查询的数据

ResultMap复杂对象⼀对多查询结果映射之collection

简述:A表与B表有关联,且A表中的某一个字段关联着B表中的多条数据,查询A表的数据时将与其B表中的数据全部查询出

首先在mapper.xml里配置resultMap,然后在resultMap的标签里collection映射到需要查询的表中,具体步骤如下

<resultMap id="UserOrderResultMap" type="User">        
	<id column="id" property="id" />        
	<result column="name" property="name" />        
	<result column="head_img" property="headImg" />        
	<result column="create_time" property="createTime" />        
	<result column="phone" property="phone" />
	<!--        如上图所示一样关联的是哪个对象,对象的类型是什么-->        
	<!--        collection 配置属性一对多   property pojo类中类属性的名称 ofType集合里面的pojo对象 -->        	
	<collection property="videoOrderList" ofType="VideoOrder">
	<!--            配置主键,管理order的唯一标识-->            
		<id column="order_id" property="id"/>            
		<result column="user_id" property="userId" />            
		<result column="out_trade_no" property="outTradeNo" />            
		<result column="create_time" property="createTime" />            
		<result column="state" property="state"/>            
		<result column="total_fee" property="totalFee"/>           
		<result column="video_id" property="videoId"/>            
		<result column="video_title" property="videoTitle"/>            
		<result column="video_img" property="videoImg"/>        
	</collection>
</resultMap>

查询的语句

<select id="queryUserOrder" resultMap="UserOrderResultMap">        
	select        
		u.id,        
		u.name,        
		u.head_img,        
		u.create_time,        
		u.phone,        
		o.id order_id,        
		o.out_trade_no,        
		o.create_time,        
		o.state,        
		o.total_fee,        
		o.video_id,        
		o.video_title,        
		o.video_img        
	from user u left join video_order o on u.id =o.user_id
</select>

接口和实现类

/**    * 查询全部用户的全部订单    */	
List<User> queryUserOrder();
/** * resultMap 和 collection测试 * 查询全部用户的全部订单 */
List<User> userList=videoOrderMapper.queryUserOrder();
System.out.println(userList.toString());

查询结果

image-20210720161833395

总结ResultMap的复杂对象查询

  • association 映射的是⼀个pojo类,处理⼀对⼀的关联关系。

  • collection 映射的⼀个集合列表,处理的是⼀对多的关联关系。

  • 模板

    <!-- column不做限制,可以为任意表的字段,⽽property须为type 定义的pojo属性-->
    <resultMap id="唯⼀的标识" type="映射的pojo对象">     
         <id column="表的主键字段,或查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" />    
         <result column="表的⼀个字段" jdbcType="字段类型" property="映射到pojo对象的⼀个属性"/>         
         
         <association property="pojo的⼀个对象属性" javaType="pojo关联的pojo对象">     
         <id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的属性"/>     
         <result column="表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/>     
         </association>         
         
         <!-- 集合中的property 需要为oftype定义的pojo对象的属性-->     
         <collection property="pojo的集合属性名称" ofType="集合中单个的pojo对象类型">     
         <id column="集合中pojo对象对应在表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />     
         <result column="任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属    性" />      
         </collection>    
         
    </resultMap>
    

Mybatis3.x 中的多级缓存和懒加载

Mybatis3.X ⼀级缓存简述

  • 什么是缓存

    • 程序经常要调⽤的对象存在内存中,⽅便其使⽤时可以快速调⽤,不必去数据库或者其他持久化

      设备中查询,主要就是提⾼性能

  • Mybatis⼀级缓存

    • 简介:⼀级缓存的作⽤域是SQLSession,同⼀个SqlSession中执⾏相同的SQL查询(相同的

      SQL和参数),第⼀次会去查询数据库并写在缓存中,第⼆次会直接从缓存中取

    • 基于PerpetualCache 的 HashMap本地缓存

    • 默认开启⼀级缓存

  • 失效策略:当执⾏SQL时候两次查询中间发⽣了增删改的操作,即insert、update、delete等操作

    commit后会清空该SQLSession缓存; ⽐如sqlsession关闭,或者清空等

Mybatis3.X ⼆级缓存怎么使用

Mybatis⼆级缓存和配置

Mybatis⼆级缓存

  • 简介:Mybatis 二级端口是namespace级别的,多个SqlSession去操作同⼀个namespace下的

    Mapper的sql语句,多个SqlSession可以共⽤⼆级缓存,如果两个mapper的namespace相

    同,(即使是两个mapper,那么这两个mapper中执⾏sql查询到的数据也将存在相同的⼆级

    缓存区域中,但是最后是每个Mapper单独的名称空间)

  • 基于PerpetualCache 的 HashMap本地缓存,可⾃定义存储源,如 Ehcache/Redis等

  • 默认是没有开启⼆级缓存

  • 操作流程:第⼀次调⽤某个namespace下的SQL去查询信息,查询到的信息会存放该

    mapper对应的⼆级缓存区域。 第⼆次调⽤同个namespace下的mapper映射⽂件中,相同

    的sql去查询信息,会去对应的⼆级缓存内取结果

失效策略

  • 执⾏同个namespace下的mapepr映射⽂件中增删改sql,并执⾏了commit操作,会清

    空该⼆级缓存

注意:实现⼆级缓存的时候,MyBatis建议返回的POJO是可序列化的, 也就是建议实现

Serializable接⼝

缓存淘汰策略:会使⽤默认的 LRU 算法来收回(最近最少使⽤的)

如何开启某个⼆级缓存 mapper.xml里面配置

eviction:代表的是缓存回收策略,常⻅下⾯两种。

(1) LRU,最近最少使⽤的,⼀处最⻓时间不⽤的对象

(2) FIFO,先进先出,按对象进⼊缓存的顺序来移除他们

flushInterval:刷新间隔时间,单位为毫秒,这⾥配置的是100秒刷新,如果不配置

它,当SQL被执⾏的时候才会去刷新缓存。

size:引⽤数⽬,代表缓存最多可以存储多少个对象,设置过⼤会导致内存溢出

readOnly:只读,缓存数据只能读取⽽不能修改,默认值是false

在mapper.xml里,放在mapper下面

<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>

在mybatis-config.xml里配置全局总开关

<!--这个配置使全局的映射器(⼆级缓存)启⽤或禁⽤缓存,全局总开关,这⾥关闭,mapper中开启了也没⽤-->
<setting name="cacheEnabled" value="true" />

Mybatis⼆级缓存实操

配置好图上显示的俩个二级缓存配置后

String resouce ="config/mybatis-config.xml";        
//读取配置文件,构建io流        
InputStream inputStream = Resources.getResourceAsStream(resouce);        
//构建sqlsessionfactory        
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);        
//获取Session        
try {
    
                
	SqlSession sqlSession1 =sqlSessionFactory.openSession();            
	VideoMapper videoMapper1=sqlSession1.getMapper(VideoMapper.class);            
	Video video1=videoMapper1.selectById(44);            
	System.out.println(video1.toString());            
	sqlSession1.commit();            
	SqlSession sqlSession2 =sqlSessionFactory.openSession();            
	VideoMapper videoMapper2=sqlSession1.getMapper(VideoMapper.class);            
	Video video2=videoMapper2.selectById(44);            
	System.out.println(video2.toString());            
	sqlSession1.commit();        
}catch (Exception e){
    
                
	e.printStackTrace();        
}    

结果显示如下图:

结果显示,在执行时,只执行了一次sql语句,显示2个结果,说明在执行第二次sql语句时直接在namespace二级缓存空间里查询结果了

image-20210721095541798

如何实现在mapper里某个查询方法不使用二级缓存的功能?

在配置好上诉的俩个配置后在mapper.xml里namespace的标签下select查询的标签里添加useCache标签useCache=“false”

<!-- statement:sql id:mapper接口下的方法名  resultType:sql查询的结果集,返回接受的类型 useCache:规定selectById查询不走二级缓存-->
<select id="selectById" resultType="Video"  useCache="false">   
	select <include refid="base_video_field"/> from video where id = #{videoId}
</select>

执行实现类里的查询方法后结果显示如下图:

image-20210721100840671

出现俩个sql语句,说明该查询方法并未执行二级缓存

⼀级缓存和⼆级缓存使⽤顺序

优先查询⼆级缓存 > 查询⼀级缓存 > 数据库

⾯试题-Mysql的Innodb和MyISAM引擎的区别

mysql常⻅的两种存储引擎的区别

image-20210721112906186

MyISAM不⽀持事务,如果需要事务则改为innodb引擎 更改数据库的表⾥⾯的引擎

我这里使用的是Navicat数据库连接工具,修改表中的引擎

第一步:

image-20210721113113647

第二步:

image-20210721113147297

public static void main(String[] args) throws IOException {
    
    

        String resouce ="config/mybatis-config.xml";
        //读取配置文件,构建io流
        InputStream inputStream = Resources.getResourceAsStream(resouce);
        //构建sqlsessionfactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取Session
        // false:为非自动提交  TRUE:自动提交
        SqlSession sqlSession=sqlSessionFactory.openSession(false);
        try{
    
    
            VideoMapper videoMapper = sqlSession.getMapper(VideoMapper.class);
            Video video1 =new Video();
            video1.setTitle("微服务架构");
            videoMapper.add(video1);
            int i =1/0;
            sqlSession.commit();   // 手动提交

        }catch (Exception e){
    
    
            e.printStackTrace();
            sqlSession.rollback();      //事务回滚
        }
  }

在使用mybatis框架时会遇见的问题

  1. 在domain层封装数据时与数据库中的字段名出现不匹配的现象如 数据库中字段名带下划线,封装的数据都是驼峰命名,如何将俩个进行映射?

​ 在mybatis-config.xml配置中在标签里添加,且位置必须放在里靠上的位置(原因:在mybatis配置xml里遵循一定的顺序)

<!--    下划线自动映射驼峰字段-->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
  1. 使用mybatis时在插入的时候,标签使用:parameterType

    <insert id="add" parameterType="net.maoni.mavenDemo2.domain.Video">
    '''
    </insert>
    
  2. 在执行插入语句时容易发生的问题?

    • 在批量插入数据时,item的别名一定要有,如:#{video.title,jdbcType=VARCHAR}

    • 在插入语句的最后去掉 “;”

  3. 在执行删除or添加用到大于小于时>< ,需要用到转义字符

    ⼤于等于 <![CDATA[ >= ]]>
    ⼩于等于 <![CDATA[ <= ]]>
    

猜你喜欢

转载自blog.csdn.net/m0_49969111/article/details/118962867