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

Posted 宇宙磅礴而冷漠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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</artifactId>
    <version>5.1.2</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();

以上是关于Mybatis-plus流程图解和使用,一级和二级缓存禁用启用详解,map的k-v入库,自增id,分页查询等各种骚操作的主要内容,如果未能解决你的问题,请参考以下文章

湖仓一体电商项目(十五):实时统计商品及一级种类二级种类访问排行业务需求和分层设计及流程图

图解 Spring 解决循环依赖,学不会接着砍!

mybatis-plus和mybatis的区别

MyBatis框架原理3:缓存

Hibernate中一级缓存和二级缓存使用详解

mybaties的缓存(转)