Mybatis-plus流程图解和使用,一级和二级缓存禁用启用详解,map的k-v入库,自增id,分页查询等各种骚操作

介绍

官网地址

官网地址:https://mybatis.plus/guide/page.html

基本工作流程

图示:
在这里插入图片描述
(1)mybatis-config.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂

(2)基于SqlSessionFactory可以生成SqlSession对象

(3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。

(4)Executor是SqlSession底层的对象,用于执行SQL语句

(5)MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)

缓存机制

springboot里默认都启用两种缓存&禁用启用

mybatis源码显示一级缓存和二级缓存都开启了

 public Configuration() {
		//...
        this.cacheEnabled = true;//二级
        this.localCacheScope = LocalCacheScope.SESSION;//一级
        //..
 }

要使用二级缓存只需要配置cache标签,实体类实现序列化,在mapper文件中开启,二级缓存是以一个mapper为单位,该mapper下的所有操作都关系二级缓存

<mapper namespace="com.xx.mapper.XxxMapper" >
<cache/>
<!--xxx-->
</mapper>

如何关闭二级缓存?
1.普通去除->去掉mapper.xml里的cache标签就行了
2.根本去除->执行1,再配置yml

mybatis-plus.configuration.cache-enabled=false//源码配置默认true

如何关闭一级缓存?
1.普通去除->使用随机数生成不同sql

(int)Math.random()*1000  (int)Math.random()*10000 
where #{random}=#{random}

2.根本去除->yml配置

mybatis.configuration.local-cache-scope=statement

代码验证一二级缓存

一级缓存验证:
配置详情:
采用默认配置,不做修改任何缓存配置。
代码:

@Autowired
private StudentDao studentDao;
@Test
public void c1(){
        for (int i=0;i<3;i++){
            List<Student> list=studentDao.findStudents();
            System.out.println(list.hashCode());
        }
    }

查看日志:
在这里插入图片描述
结论:可以看到sql语句被执行三次,三次访问了数据库.
原因:一次访问数据库相当于一次service里的操作,虽然默认开启过了一级缓存,操作完一次会关闭,但是每次操作都是新的sqlsession,而一级缓存是session级别的。当调用SqlSession的修改,添加,删除,commit(),close()等方法时就会清空一级缓存.
修改代码加上@Transactional开启事物:

@Autowired
private StudentDao studentDao;
@Test
@Transactional
public void c1(){
        for (int i=0;i<3;i++){
            List<Student> list=studentDao.findStudents();
            System.out.println(list.hashCode());
        }
    }

查看日志:
在这里插入图片描述
结论:只访问了一次数据库。
原因:同一个事物里的操作都属于一个sqlsession,因为默认开启过了一级缓存,数据会尝试从hashmap结构的缓存查找数据,当然会有数据的了。

如果再次修改代码,使用自己创建的sqlSession:

@Autowired
private SqlSessionFactory sqlSessionFactory;
@Test
public void c2(){
	SqlSession sqlSession=sqlSessionFactory.openSession();
    for (int i=0;i<3;i++){
    List<Student> list=sqlSession.getMapper(StudentDao.class).findStudents();
    System.out.println(list.hashCode());
   }
 }    

查看日志:
在这里插入图片描述
结论:只执行一次数据库查询。

二级缓存验证:
首先mapper.xml不添加cache标签
代码:

@Test
public void c3(){
     for (int i=0;i<3;i++){
            List<Dept> list=StudentDao.findDept();
            System.out.println(list.hashCode());
     }
}

查看日志:
在这里插入图片描述
结论:没有进入一级缓存和二级缓存,访问了三次数据库。

在mapper.xml加入cache标签
代码不变
查看日志:
在这里插入图片描述
结论:只访问了一次数据库,进入了二级缓存.

一级缓存解释

  SqlSession级别的缓存,实现在同一个会话中数据的共享
  一级缓存的生命周期和SqlSession一致
  当有多个SqlSession或者分布式环境下,数据库写操作会引起脏数据。

二级缓存解释

  SqlSessionFactory级别的缓存,实现不同会话中数据的共享,是一个全局变量
  可自定义存储源,如Ehcache
  当开启缓存后,数据查询的执行的流程是:二级缓存>一级缓存>数据库
  不同于一级缓存,二级缓存可设置是否允许刷新和刷新频率实现

plus复杂语句嵌套单表操作

1.pojo实体类与数据库表关联
实体类要求示例:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain=true)//实现链式加载
@TableName("user")//1.关联表名
public class User {
    //对象与数据表完美映射,对象名称与表名,对象的属性与表字段
    @TableId(type = IdType.AUTO)//主键自增,value = "id"可不写
    private Integer id;
    //@TableField(value = "name")//可以省略,但是名称必须相同
    private String name;
    private Integer age;
    private String sex;
    @TableField(exist = false)//入库丢弃,不属于数据库表字段
    private String dept;
}

mapper接口示例:通常plus包含单表操作,自己可以不需要写方法

@Mapper
public interface UserMapper extends BaseMapper<User> {
    List<User> findAll();
}

语句举例:delete from user where id=? and creatorId=? and (valid=? or startTime>?)
//and()语句相当于一个独立条件用()括起来。

UserMapper.delete(new QueryWrapper<FSTest>()
                .eq("id",testId)
                .eq("creatorId",creatorId)
                .and(qw->qw.eq("valid", 0).or().gt("startTime", new Date())));

获取自增id

非plus版本:
1.插入pojo实体类,执行成功,该pojo会被赋值自增的id值

<insert id="insertAuto" parameterType="com.xx.pojo.Teacher" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
      insert into teacher (name,dept,password) values (#{name},#{dept},#{password})
</insert>

2.map类型,自增id会封装到map里

<insert id="insertAuto" parameterType="map">
      insert into teacher (name,dept,password) values (#{name},#{dept},#{password})
      <selectKey keyProperty="id" order="AFTER" keyColumn="id" resultType="java.lang.Integer">
          SELECT LAST_INSERT_ID() AS id
      </selectKey>
</insert>

plus版本:
如果是使用自带封装的plus插入方法,成功执行会把id封装到pojo
如果是mapper.xml自定义方式则和非plus版本相同

sql联表优化查询

 <!-- 方案 1
        select c.*,p.name parentName
        from sys_menus c left join sys_menus p
        on c.parentId=p.id
        -->
<!-- 方案 2 -->
        select c.*,(
        select p.name
        from sys_menus p
        where c.parentId=p.id
        ) parentName
        from sys_menus c

PageHelper和Page分页

非plus版本->PageHaper
依赖:

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.2.13</version>
</dependency>

代码:

PageHelper.startPage(pageCurrent, 15);
//firstTestMapper.doGetFirstTest(valid, notEnd,creatorId)返回一个list
PageInfo<FSTest> info=new PageInfo<>(firstTestMapper.doGetFirstTest(valid, notEnd,creatorId));
return new PageObject<>((int)info.getTotal(),info.getPages() ,15 ,info.getList() ,pageCurrent);

plus版本->Page
配置类:

@Configuration
@MapperScan("com.baomidou.cloud.service.*.mapper*")
public class MybatisPlusConfig {

    // 旧版
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        // paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        // paginationInterceptor.setLimit(500);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }
    
    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }
    
}

操作:

Page<Item> pageItem=new Page<>(pageCurrent,rowsNumber,true);//定义页
QueryWrapper<Item> queryWrapper=new QueryWrapper<>();
queryWrapper.orderByDesc("updated");
IPage<Item> iPage=itemMapper.selectPage(pageItem,queryWrapper );//返回页数据
return new EasyUITable(iPage.getTotal(),iPage.getRecords());

各种常用标签

foreach
foreach元素的属性主要有item,index,collection,open,separator,close。

item:集合中元素迭代时的别名
index:集合中元素迭代时的索引
open:常用语where语句中,表示以什么开始,比如以’('开始
separator:表示在每次进行迭代时的分隔符
close 常用语where语句中,表示以什么结束

传入list或array:

<select id="queryById" resultMap="BaseReslutMap" >
      select * from user
      where id in 
      <foreach collection="ids" item="id" index="index" open="(" separator="," close=")">
              #{id}
      </foreach>
</select>

if

 <if test="ids!=null and ids.length!=0">
         id in <!--(1,3,32,2)-->
         <foreach collection="ids" open="(" close=")" separator="," item="id">
              #{id}
         </foreach>
</if>

choose

 <choose>
     <when test="notEnd==null">
          and second_test.id=#{testId}
     </when>
     <otherwise>
     	   <--再嵌套-->
           <choose>
               <when test="notEnd==true">
                   and second_test.endTime &gt; NOW()
                </when>
           		<otherwise>
                   and second_test.endTime &lt; NOW()
           		</otherwise>
           </choose>
           
     </otherwise>
</choose>

resultMap
property为pojo属性,column为数据库字段

<resultMap id="studentMap" type="Student">
        <result property="className" column="class"/>
</resultMap>

模糊查询:

select * from user where name like concat('%',concat(#{name},'%'))

map-kv操作

把map的不确定的key和value全部作为值插入固定字段(list[map1,map2,map3,…])
例如: key=100,value=“hello” 分别插入id和world字段,最终传list到mapper.

List<Map> getMapList(Map<String, String> map){
        Set<String> set=map.keySet();
        List<Map> list=new ArrayList<>();
        Iterator<String> iterator=set.iterator();
        while (iterator.hasNext()){
            Map map1=new HashMap();
            String id=iterator.next();
            String world=map.get(id);
            map1.put("id",id );
            map1.put("world", world);
            list.add(map1);
        }
        return list;
}

mapper.xml配置:

<insert id="subTest">
     insert into tableOne(id,world,isDone) values
     <foreach collection="list" item="map" index="index" separator=",">
         (#{map.id},#{map.world},#{isDone})
     </foreach>
</insert>

以map形式出库

<select id="getMapList" resultType="java.util.Map">
       select * from teacher
</select>
List<Map> getMapList();
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可——叹——落叶飘零

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值