Mybatis-06 动态Sql

Mybatis-06 动态Sql

Mybatis系列文章已经完成上传:
一、什么是Mybatis
二、CRUD
三、配置解析
四、日志、分页
五、注解开发
六、动态Sql

多对一处理

多个学生,对应一个老师

对于学生这边而言,关联多个学生,关联一个老师 【多对一】

对于老师而言,集合,一个老师又很多学生 【一对多】

1.创建数据库

1

2

2.创建实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class teacher {

    private int id;
    private String name;

}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class student {
    
    private int id;
    private String name;
    private teacher teacher;

}

3.接口类

public interface StudentMapper {

    public List<student> getStudent();

}

4.Mapper.xml文件

思路:

  1. 查询出所有学生
  2. 根据tid查询其对应老师

复杂的对象就用associationcollection

对象:association 集合:collection

4.1 按照查询嵌套处理

<mapper namespace="com.Dao.StudentMapper">
    <resultMap id="stutea" type="pojo.student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="teacher" column="tid" javaType="pojo.teacher" select="getTeacher"/>
    </resultMap>
     <select id="getStudent" resultMap="stutea">
         select * from mybatistest.stu
     </select>
    <select id="getTeacher" resultType="pojo.teacher">
         select * from mybatistest.teacher where id = #{id}
    </select>
</mapper>

4.2 按照结果嵌套处理

<mapper namespace="com.Dao.StudentMapper">
    <select id="getStudent" resultMap="studentTeacher2">
            select s.id,s.name,t.name
            from mybatistest.stu s,mybatistest.teacher t
            where s.tid=t.id
    </select>
    <resultMap id="studentTeacher2" type="pojo.student">
            <result property="id" column="id"/>
            <result property="name" column="name"/>
            <association property="teacher" javaType="pojo.teacher">
                <result property="name" column="name"/>
            </association>
    </resultMap>
</mapper>    

5.测试

 @Test
    public void getStudent(){
        SqlSession sqlSession = mybatis_util.getSqlSession1();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<student> student = mapper.getStudent();
        for (pojo.student student1 : student) {
            System.out.println(student1);
        }
        sqlSession.close();
    }

3

4

一对多处理

数据库不变

1.创建实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class teacher {

    private int id;
    private String name;
    private List<student> students;

}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class student {

    private int id;
    private String name;
   // private teacher teacher;
    private int tid;

}

2.接口类

public interface TeacherMapper {

     public teacher getTeacher(@Param("tid") int id);

}

3.Mapper.xml文件

3.1 按照查询嵌套处理

<mapper namespace="com.Dao.TeacherMapper">
    
    <select id="getTeacher" resultMap="geTeacher" >
        select * from mybatistest.teacher where id = #{tid}
    </select>
    <resultMap id="geTeacher" type="pojo.teacher">
        <collection property="students" javaType="ArrayList" ofType="pojo.student" select="getStudent" column="id"></collection>
    </resultMap>
    <select id="getStudent" resultType="pojo.student">
        select * from mybatistest.stu where tid = #{tid}
    </select>
    
</mapper>

3.2 按照结果嵌套处理

<mapper namespace="com.Dao.TeacherMapper">

    <select id="getTeacher" resultMap="teacherStudent">
        select t.id tid,t.name tname,s.id sid,s.name sname
        from mybatistest.stu s,mybatistest.teacher t
        where s.tid=t.id and t.id=#{tid}
    </select>
    <resultMap id="teacherStudent" type="pojo.teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <collection property="students" ofType="pojo.student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

</mapper>

4.测试

 @Test
public void getTeacher(){
      SqlSession sqlSession = mybatis_util.getSqlSession1();
      TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
      teacher teacher = mapper.getTeacher(1);
      System.out.println(teacher);
      sqlSession.close();
}

5

6

ofType & javaType

  1. javaType用来指定实体类中属性
  2. ofTyoe用来指定映射到List或者集合中pojo类型,泛型中的约束类型

注意点:注意一对多和多对一中,属性名和字段的问题

动态sql

动态SQL就是指根据不同的条件生成不同的SQL语句

  • If
  • choose (when,otherwise)
  • trim (where,set)
  • foreach

1.基础准备

1.1 创建数据库

CREATE TABLE `blog`(
`id` INT(10) NOT NULL COMMENT '博客id',`title` VARCHAR(20) NOT NULL COMMENT '博客标题',`author` VARCHAR(10) NOT NULL COMMENT '作者',`create_time` DATETIME NOT NULL COMMENT '创建时间',`views` INT(20) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB CHARSET=utf8;

7

1.2 创建实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}

1.3 创建接口类

public interface BlogMapper {

    public int addBlog(Blog blog);

}

1.4 创建Mapper.xml文件

<mapper namespace="com.Dao.BlogMapper">
    <insert id="addBlog" parameterType="pojo.Blog">
        insert into mybatistest.blog(id,title,author,create_time,views)
        values (#{id},#{title},#{author},#{createTime},#{views})
    </insert>
</mapper>

1.5 测试代码

  @Test
    public void Test(){
        SqlSession sqlSession = mybatis_util.getSqlSession1();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        Blog blog = new Blog(1,"title","张",new Date(),11);
        int i = mapper.addBlog(blog);
        System.out.println(i);
    }

2.IF

接口

public interface BlogMapper {

   public List<Blog> queryBlogIF(Map map);

}

映射文件

<mapper namespace="com.Dao.BlogMapper">
    
    <select id="queryBlogIF" parameterType="map" resultType="pojo.Blog">
        select * from mybatistest.blog where 1=1
        <if test="views != null">
            and views > #{views}
        </if>
        <if test="author != null">
            and author=#{author}
        </if>
        <if test="title != null">
            and title like #{title}
        </if>
    </select>

</mapper>

测试

   @Test
    public void queryBlogIF(){
        SqlSession sqlSession = mybatis_util.getSqlSession1();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap<String,Object> map = new HashMap<String,Object>();
        map.put("views",10);
        List<Blog> blogs = mapper.queryBlogIF(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
    }

8

注意:

  • 未绑定mapper

在配置文件中绑定:

<mappers>
   <mapper class="com.Dao.BlogMapper"/>
</mappers>
  • createTime数据为null

这是因为在实体类中,数据库中定义时间属性为:create_time,有_

可以开启驼峰命名法映射,在配置文件中加入:

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

在数据库字段命名规范中常常用下划线 "_" 对单词进行连接,如:"create_time",而开发中实体属性通常会采用驼峰命名法命名为 createTime

3.choose (when,otherwise)

接口

public interface BlogMapper {

   public List<Blog> queryBlogChoose(Map map);

}

映射文件

<select id="queryBlogChoose" parameterType="map" resultType="pojo.Blog">
      select * from mybatistest.blog
      <where>
         <choose>
              <when test="title != null">
                 and title like #{title}
             </when>
             <when test="author != null">
                 and author = #{author}
             </when>
             <otherwise>
                 and views > #{views}
             </otherwise>
        </choose>
     </where>
</select>

测试

    @Test
    public void queryBlogChoose(){
        SqlSession sqlSession = mybatis_util.getSqlSession1();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap<String,Object>();
        map.put("title","%啦%");
        List<Blog> blogs = mapper.queryBlogChoose(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
    }

9

4.trim (where,set)

where元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 ANDORwhere 元素也会将它们去除。

<where>
    <if test="views != null">
        views > #{views}
    </if>
    <if test="author != null">
        and author=#{author}
    </if>
    <if test="title != null">
        and title like #{title}
    </if>
</where>

set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。

接口

 public int updateBlogSet(Map map);

映射文件

<update id="updateBlogSet" parameterType="map">
    update mybatistest.blog
    <set>
        <if test="title != null">title=#{title},</if>
        <if test="author != null">author=#{author},</if>
        <if test="views != null">views=#{views},</if>
    </set>
    where id=#{id}
</update>

测试

    @Test
    public void updateBlogSet(){
        SqlSession sqlSession = mybatis_util.getSqlSession1();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap<String,Object>();
        map.put("id",1);
        map.put("title","t-test");
        map.put("author","a-test");
        map.put("views",100);
        int i = mapper.updateBlogSet(map);
        System.out.println(i);
        HashMap map1 = new HashMap();
        List<Blog> blogs = mapper.queryBlogIF(map1);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
    }

10

5.Foreach

接口

public List<Blog> queryBlogForeach(Map map);

映射文件

<select id="queryBlogForeach" parameterType="map">
    select * from mybatistest.blog
    <where>
        /*此处的collection是一个list,所以map需要传入一个list来进行遍历*/
        <foreach collection="ids" item="id" open="and (" close=")" separator="or">
            id=#{id}
        </foreach>
        <if test="views != null">
            and views > #{views}
        </if>
        <if test="author != null">
            and author=#{author}
        </if>
    </where>
</select>

测试

    @Test
    public void queryBlogForeach(){
        SqlSession sqlSession = mybatis_util.getSqlSession1();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap<String,Object>();
        List<Integer> ids = new ArrayList<Integer>();
        ids.add(2);
        ids.add(3);
        map.put("ids",ids);
        List<Blog> blogs = mapper.queryBlogForeach(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
    }

11

6.Sql片段

我们可以将一些公共的部分用<sql>抽取出来,方便复用!

<sql id="id-test">
    <choose>
        <when test="title != null">
            and title like #{title}
        </when>
        <when test="author != null">
            and author = #{author}
        </when>
        <otherwise>
            and views > #{views}
        </otherwise>
    </choose>
</sql>
<select id="queryBlogChoose" parameterType="map" resultType="pojo.Blog">
   select * from mybatistest.blog
   <where>
       <include refid="id-test"></include>
   </where>
</select>

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

我们可以先在Mysql中写出完整的SQL,在对应的去修改称为我们的动态SQL

缓存

1.简介

查询:连接数据库,耗资源!

一次查询的结果,给他暂存在一个可以直接取到的地方——内存:缓存

那么我们再次查询的时候就可以不用走数据库了

  1. 缓存【Cache】?
    • 存在内存中的临时数据
    • 将用户经常查询的数据放在缓存中,用户查询的时候就不用从磁盘上查询了,而从缓存中查询,提高查询效率
  2. 为什么使用缓存?
    • 减少和数据库的交互次数,减少系统开销
  3. 什么样的数据能使用缓存?
    • 经常查询并且不经常改变的数据

2.Mybatis缓存

Mybatis系统中默认顶一个两级缓存:一级缓存和二级缓存

  • 默认情况下,只有一级缓存开启。这是sqlSession级别的,随着Session开启而开启,关闭而关闭,也称其为本地缓存
  • 二级缓存是namespace级别的,需要手动开启和配置
  • Mybatis有一个配置缓存的接口Cache,可以定义二级缓存

注意事项:

  • 映射语句文件中的所有 select 语句的结果将会被缓存。
  • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
  • 缓存会使用最近最少使用算法(LRU,Least Recently Used)算法来清除不需要的缓存。
  • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
  • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

3.一级缓存

一级缓存也叫本地缓存:

  • 在域数据库交互的同一个会话中,会将查过的数据放在缓存中
  • 以后再查询相同的数据时,直接从缓存中取数据

测试

  1. 开启日志
  2. 测试两次查询同一条数据
    @Test
    public void cache(){
        SqlSession sqlSession = mybatis_util.getSqlSession1();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        user user = mapper.getUserById(1);
        System.out.println(user);
        System.out.println("===============================");
        user user1 = mapper.getUserById(1);
        System.out.println(user1);
        System.out.println(user==user1);
        sqlSession.close();
    }

12

从图中可以看出,数据在一级缓存,只查询一次,这两者相同,为true

手动清理缓存

    @Test
    public void cache(){
        SqlSession sqlSession = mybatis_util.getSqlSession1();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        user user = mapper.getUserById(1);
        System.out.println(user);
        sqlSession.clearCache();    //手动清理缓存
        System.out.println("===============================");
        user user1 = mapper.getUserById(1);
        System.out.println(user1);
        System.out.println(user==user1);
        sqlSession.close();
    }

13

从图中可以看出,数据在一级缓存,手动清理缓存后,查询了两次,这两者不同,为false

4.二级缓存

二级缓存是基于namespace的缓存,它的作用域比一级大

  • 我们希望当会话关闭的时候,存储在一级缓存的数据可以进入二级缓存
  • 用户进行第二次会话的时候,就可以直接从二级缓存拿数据

4.1 开启缓存

在配置文件开启二级缓存

<setting name="cacheEnabled" value="true"/>

在对应的mapper.xml中选择开启二级缓存

<cache/>

也可以自定义cache

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

4.2测试

      @Test
      public void SecondCache(){
          SqlSession sqlSession = mybatis_util.getSqlSession();
          UserDao mapper = sqlSession.getMapper(UserDao.class);
          user user = mapper.getUserByID(1);
          System.out.println(user);
          sqlSession.close();
          System.out.println("===============================");
          SqlSession sqlSession1 = mybatis_util.getSqlSession();
          UserDao mapper1 = sqlSession1.getMapper(UserDao.class);
          user user1 = mapper1.getUserByID(1);
          System.out.println(user1);
          System.out.println(user==user1);
          sqlSession.close();
      }

14

从图中可以看出,开启二级缓存后,sqlSession关闭时,数据存入二级缓存,直接在二级缓存调出数据,只用查询了一次 ,这两者不同,为false

注意:可能会出现的错误:Error serializing object. Cause:java.io.NotSerializableException: pojo.user,这个错误只需要在实体类继承Serializable,即:class user implements Serializable

5.缓存原理

15

6.自定义缓存-encache

Ehcache是一种广泛使用的开源Java分布式缓存。EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。

6.1 导入依赖

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

6.2 导入配置文件

创建ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">

    <diskStore path="./tmpdir/Tmp_EhCache"/>

    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
</ehcache>

6.3 开启二级缓存

 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

其实没什么大的区别,想用可以用

个人博客为:
MoYu's Github Blog
MoYu's Gitee Blog

原文地址:https://www.cnblogs.com/MoYu-zc

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


1.pom.xml引入依赖 &lt;dependency&gt; &lt;groupId&gt;com.github.pagehelper&lt;/groupId&gt; &lt;artifactId&gt;pagehelper&lt;/artifactId&gt; &lt;version&gt;5
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt; &lt;!DOCTYPE configuration PUBLIC &quot;-//mybatis.org//DTD Config 3.0//EN&quot; &qu
准备工作 ① 创建数据库&amp;数据表 ## 创建数据库 CREATE DATABASE `dbtest1`; ## 创建数据表 CREATE TABLE `t_user` ( `id` INT NOT NULL AUTO_INCREMENT, `username` VARCHAR(20) DEF
MyBatis逆向工程是指根据数据库表结构自动生成对应的实体类、Mapper接口以及SQL映射文件的过程。这个过程可以通过MyBatis提供的逆向工程工具来完成,极大地方便了开发人员,避免了重复的代码编写,提高了开发效率。 创建逆向工程的步骤 1、添加依赖&amp;插件 &lt;!-- 控制Mave
MyBatis获取参数值的两种方式:${}和#{} ${}的本质就是字符串拼接,#{}的本质就是占位符赋值。 ${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自
resultMap作用是处理数据表中字段与java实体类中属性的映射关系。 准备工作 ① 创建数据库&amp;数据表 CREATE DATABASE `dbtest1`; CREATE TABLE `t_emp` ( `emp_id` int NOT NULL AUTO_INCREMENT, `em
EHCache缓存针对于MyBatis的二级缓存。 MyBatis默认二级缓存是SqlSessionFactory级别的。 添加依赖 &lt;!-- MyBatis-EHCache整合包 --&gt; &lt;dependency&gt; &lt;groupId&gt;org.mybatis.cac
MyBatis 提供了一级缓存和二级缓存的支持,用于提高数据库查询的性能,减少不必要的数据库访问。 一级缓存(SqlSession 级别的缓存) 一级缓存是 MyBatis 中最细粒度的缓存,也称为本地缓存。它存在于每个 SqlSession 的生命周期中,当 SqlSession 被关闭或清空时,
动态SQL是 MyBatis 中非常强大且灵活的功能,允许你根据不同的条件构建SQL查询。 这主要通过 &lt;if&gt;、&lt;choose&gt;、&lt;when&gt;、&lt;otherwise&gt;、&lt;foreach&gt;等标签实现。 查询场景 /** * 根据条件查询员工
本教程操作系统:windows10系统、DELL G3电脑。 MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。在 MyBatis 中,配置数据库连接是非常重要的第一步。下面将详细介绍如何配置 MyBatis 的
今天小编给大家分享的是MyBatis批量查询、插入、更新、删除如何实现,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。
今天小编给大家分享的是Mybatis操作多数据源实现的方法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
本篇文章和大家了解一下mybatis集成到spring的方式有哪些。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。1 前言1.1 集成spring前使用mybat...
今天小编给大家分享的是mybatis-plus分页查询的3种方法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
本篇内容主要讲解“mybatis之BaseTypeHandler怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mybatis...
这篇文章主要介绍了mybatisforeach怎么传两个参数的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇mybatisforeach怎...
这篇“MyBatis映射文件中parameterType与resultType怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的...
这篇文章主要介绍“MyBatis怎么获取自动生成的键值”,在日常操作中,相信很多人在MyBatis怎么获取自动生成的键值问题上存在疑惑,小编查阅了各式资料,整理出
这篇文章主要讲解了“怎么去掉IntelliJIDEA中mybatis对应的xml文件警告”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入...
这篇文章主要介绍“MybatisPlus使用@TableId主键id自增长无效如何解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这...