Mybatis-06 動態Sql

Mybatis-06 動態Sql

多對一處理

多個學生,對應一個老師java

對於學生這邊而言,關聯多個學生,關聯一個老師 【多對一】git

對於老師而言,集合,一個老師又不少學生 【一對多】github

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查詢其對應老師

複雜的對象就用associationcollectionsql

對象: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類型,泛型中的約束類型

注意點:注意一對多和多對一中,屬性名和字段的問題mybatis

動態sql

動態SQL就是指根據不一樣的條件生成不一樣的SQL語句app

  • 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 = new 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 = new 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> map = new 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

相關文章
相關標籤/搜索