MyBatis(二)-CURD (ResultMap 一對一,一對多)

来源:https://www.cnblogs.com/xiaoqigui/archive/2022/08/22/16603203.html
-Advertisement-
Play Games

1、insert 標簽 1.1 獲取SqlSessionFactory 對象的通用方法 方便後面分測試; //獲取SqlSessionFactory 對象的通用方法 public SqlSessionFactory getSqlSessionFactory() throws IOException ...


1、insert 標簽

1.1 獲取SqlSessionFactory 對象的通用方法

方便後面分測試;

//獲取SqlSessionFactory 對象的通用方法
public SqlSessionFactory getSqlSessionFactory() throws IOException {
    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    return new SqlSessionFactoryBuilder().build(inputStream);
}

1.2 屬性說明

屬性名 說明
id namespace指定介面中的方法名
parameterType 指定介面方法入參類型,可寫可不寫(mybatis可用根據介面方法,自動推斷類型)
useGeneratedKey insert標簽的屬性,告訴mybatis,執行插入操作,需要返回自增的主鍵
keyColumn 自增主鍵的 欄位名(可以不寫,一張表只用能有一個自增主鍵)
keyPropert 指定返回的自增主鍵值,交給入參實體的哪個屬性保存

註意:增刪改操作,和select查詢標簽最大的區別是:返回只有影響行數,所有沒有resultType屬性,而查詢必須有resultType;

1.3 SQL

<!--   int insertAnime(Anime animeForm);  -->
<insert id="insertAnime" useGeneratedKeys="true" keyColumn="id" keyProperty="id" >
    insert into `animes`(
        `cid`,
        `name`
    )values(
        #{cid},
        #{name}
    )
</insert>

1.4 測試

註意:mybatis 預設對增刪改操作,事務不自動提交(自動提交是關閉的);

需要開啟自動提交或這是手動提交

開啟自動提交 openSession(true);
手動提交 sqlSession.commit();
@Test
public void testMybatisMapperC() throws IOException {
    //獲取SqlSession對象
    // SqlSession sqlSession = getSqlSessionFactory().openSession();
    //方式2:創建SqlSession對象時,指定事務自動提交-true,預設false
    SqlSession sqlSession = getSqlSessionFactory().openSession(true);

    //獲取mapper介面的代理實現對象
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
    System.out.println(animeMapper); //org.apache.ibatis.binding.MapperProxy@224edc67

    //模擬從前端獲取參數,封裝請求實體
    Anime animeForm = new Anime();
    animeForm.setCid(1);
    animeForm.setName("蠟筆小新");

    //執行添加動漫
    int row = animeMapper.insertAnime(animeForm);

    //mybatis 預設對增刪改操作,事務是不自動提交(自動提交是關閉的)
    //方式1:手動提交
    //sqlSession.commit();

    System.out.println(String.format("----------執行添加動漫,影響行數:%d--------", row));
    
    //獲取自增主鍵
    System.out.println(String.format("----------執行添加動漫,新增的自增id:%d--------", animeForm.getId()));
    
}

2、update 標簽

2.1 SQL

<!--  int updateAnimeById(Anime animeForm);  -->
<update id="updateAnimeById">
    update `animes` set
        `cid` = #{cid},
        `name` = #{name}
    where `id` = #{id}
</update>

2.2 測試

@Test
public void testMybatisMapperU() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession(true);
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);

    //模擬從前端獲取參數,封裝請求實體
    Anime animeForm = new Anime();
    animeForm.setId(648);
    animeForm.setCid(1);
    animeForm.setName("蠟筆小新5");
    //執行修改動漫
    int row = animeMapper.updateAnimeById(animeForm);

    System.out.println(String.format("----------執行修改動漫,影響行數:%d--------", row));

}

3、delete 標簽

3.1 SQL

<!--   int deleteAnimeById(Integer animeId);  -->
<delete id="deleteAnimeById">
    delete from `animes`
    where `id` =  #{animeId}
</delete>

3.2 測試

@Test
public void testMybatisMapperD() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession(true);
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
    //模擬從前端獲取參數,封裝請求實體
    Anime animeForm = new Anime();
    animeForm.setId(648);
    //執行刪除動漫
    int row = animeMapper.deleteAnimeById(animeForm.getId());

    System.out.println(String.format("----------執行刪除動漫,影響行數:%d--------", row));

}

4、select 標簽

4.1 屬性說明

屬性名 說明
id 對應就是namespace指定介面中的查詢方法名
parameterType 指定介面方法入參類型可寫可不寫(建議不寫)
resultType 指定介面返回的目標類型(建議使用全類名,也可以使用別名)
  • #{id}:這就告訴 MyBatis 創建一個預處理語句(PreparedStatement)參數,在 JDBC 中,這樣的一個參數在 SQL 中會由一個“?”來標識,並被傳遞到一個新的預處理語句中;
  • 如果介面只有一個參數參數名可以隨便寫,建議跟形參名保持一致

4.2 一個參數

4.2.1 SQL

介面只有一個參數,參數名,可以隨便寫,建議跟形參名保持一致;

<!--  Anime selectAnimeById(Integer animeId);  -->
<select id="selectAnimeById" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`
    from `animes`
    where `id` = #{animeId}
</select>

4.2.2 測試

@Test
public void testMybatisMapperSelectParams1() throws IOException{
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
    //調用mapper介面,根據動漫編號查詢動漫信息
    Anime anime = animeMapper.selectAnimeById(101);

    System.out.println(String.format("1.一個參數 根據動漫編號:%d,查詢動漫詳情%s",anime.getId(),anime));

}

4.3 兩個參數

多個參數,沒有自定義參數別名時可以使用

  • 形參名
  • 內置參數 0,1,...
  • 內置參數 param1,param2,...

自定義參數別名@Param("自定義參數名")時可以使用:

  • 自定義參數名
  • 內置參數 param1,param2,...

4.3.1 SQL

4.3.1.1 沒有自定義參數別名:
Anime selectAnimeByNameAndCid(String animeName,Integer animeId); 
<!-- Anime selectAnimeByNameAndCid(String animeName,Integer animeId);   -->
<select id="selectAnimeByNameAndCid" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`
     from `animes`

    where `name` = #{animeName}
    and `cid` = #{animeId}

<!--
    where `name` = #{0}
    and `cid` = #{1}
-->
<!--
    where `name` = #{ param1}
    and `cid` = #{param2}
-->
</select>
4.3.1.2 自定義參數別名
Anime selectAnimeByNameAndCid(@Param("animeName") String animeName,@Param("animeId") Integer animeId);
Anime selectAnimeByNameAndCid(@Param("animeName") String animeName,@Param("animeId") Integer animeId);
<select id="selectAnimeByNameAndCid" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`
     from `animes`
    where `name` = #{animeName}
    and `cid` = #{animeId}
<!--
    where `name` = #{ param1}
    and `cid` = #{param2}
--> 
</select>

自定義了參數名,如果使用#{0},#{1}會報錯

Cause: org.apache.ibatis.binding.BindingException: Parameter '0' not found. Available parameters are [animeId, animeName, param1, param2]

4.3.2 測試

@Test
public void testMybatisMapperSelectParams2() throws IOException{
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
    //通過動漫名稱和分類編號查詢動漫信息
    Anime anime = animeMapper.selectAnimeByNameAndCid("完美世界",3);

    System.out.println(String.format("2.兩個參數 根據動漫編號:%d,查詢動漫詳情%s",anime.getId(),anime));

}

4.4 實體參數

不自定義參數別名:

  • 必須 只寫 屬性名 cid author

自定義參數別名:

  • 使用 別名.屬性名
  • 使用 param1.屬性名

4.4.1 SQL

4.4.1.1 不自定義參數別名
Anime selectAnimeByAnime(Anime animeForm);
<select id="selectAnimeByAnime" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`
    from `animes`
	where `cid` = #{cid}
    and `author` = #{author}
</select>
4.4.1.2 自定義參數別名
 Anime selectAnimeByAnime(@Param("animeForm") Anime animeForm);
<select id="selectAnimeByAnime" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`
    from `animes`
<!--    
 	where `cid` = #{animeForm.cid}
     and `author` = #{animeForm.author}
 -->
     where `cid` = #{param1.cid}
     and `author` = #{param1.author}
</select>

4.4.2 測試

@Test
public void testMybatisMapperSelectParams3() throws IOException{
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
    //通過動漫分類編號和作者查詢動漫信息
    Anime animeForm = new Anime();
    animeForm.setCid(1);
    animeForm.setAuthor("三少");
    Anime anime = animeMapper.selectAnimeByAnime(animeForm);
    System.out.println(String.format("3.實體參數 根據動漫編號:%d,查詢動漫詳情%s",anime.getId(),anime));

}

4.5 Map集合參數

  • 通過Map 的 **鍵值 **獲取參數

4.5.1 SQL

<!--
  Anime selectAnimeByActorAndCid(Map<String,Object> queryMap);
-->
<select id="selectAnimeByActorAndCid" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`
     from `animes`
    where `cid` = #{cid}
    and `actor` = #{actor}
</select>

4.5.2 測試

 @Test
public void testMybatisMapperSelectParams4() throws IOException{
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
    //通過動漫分類編號和主角查詢動漫信息
    Map<String,Object> queryMap = new HashMap<>();
    queryMap.put("cid","2");
    queryMap.put("actor","路飛");

    Anime anime = animeMapper.selectAnimeByActorAndCid(queryMap);

    System.out.println(String.format("4.集合參數 根據動漫編號:%d,查詢動漫詳情%s",anime.getId(),anime));

}

4.6 #{} 和 ${} 的區別

#{}:

  • 類似於PreparedStatement

  • 可以獲取普通參數,自定義參數,實體參數,集合參數等;

  • 底層使用的是?占位符,會進行預編譯處理,可以防止SQL註入問題,安全性高;

  • 不可以進行表達式運算

${}:

  • 類似於Statement

  • 正常情況下,跟#{}獲取參數的寫法沒有區別;

  • 區別:不能隨意獲取參數不能使用內置參數必須起別名;

  • 底層是字元串拼接,不是占位符,不安全,當#{}解決不了,就必須使用${};

  • 可以使用,動態表名,動態列名,表達式運算等

建議:MyBatis的SQL映射文件中,能優先使用#{},就必須使用,除非特殊情況,必須使用字元串拼接,才可以使用${};

4.6.1 SQL

使用動態表名查詢動漫;

<!--   Anime selectProduceAndCid(@Param("produce") String produce,@Param("cid")Integer cid,@Param("tableName")String tableName);  -->
    <select id="selectProduceAndCid" resultType="com.kgc.mybatis.bean.Anime">
        select `id`,
                `cid`,
                `name`
        from    ${tableName}
        where  `produce` = #{produce}
        and `cid` = #{cid}
</select>

4.6.2 測試

@Test
public void testMybatisMapperSelectParams5() throws IOException{
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);

    Anime anime = animeMapper.selectProduceAndCid("騰訊動漫", 2, "animes");

    System.out.println(String.format("4.集合參數 根據動漫編號:%d,查詢動漫詳情%s",anime.getId(),anime));

}

4.7 查詢多條數據

查詢多條數據, resultType 屬性值還是實體類

resultType="com.kgc.mybatis.bean.Anime"

Mybatis會自己走 返回集合的方法自動將數據放到集合中

 //var1 select標簽的id屬性的值
<E> List<E> selectList(String var1);

//var2 為介面方法的參數
<E> List<E> selectList(String var1, Object var2);

//var3 為分頁對象
<E> List<E> selectList(String var1, Object var2, RowBounds var3);

4.7.1 SQL

<!--   List<Anime> selectAnimeListByCid(Integer Cid);  -->
<select id="selectAnimeListByCid" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`
    from   `animes`
    where  `cid` = #{cid}
</select>

4.7.2 測試

@Test
public void testMyBatisMapperSelectResults() throws  IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
	//根據動漫分類編號查詢動漫
    List<Anime> animeList = animeMapper.selectAnimeListByCid(3);

    for (Anime anime : animeList) {
        System.out.println(anime);
    }

}

4.8 模糊查詢

使用 #{} 建議使用 concat('%',#{name},'%');

使用 ${name} 必須給參數起別名

4.8.1 SQL

4.8.1.1 使用 #{name}
<!--  List<Anime> selectAnimeListByName(String name);   -->
<select id="selectAnimeListByName" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`
    from   `animes`
    <!-- where  name like '%'#{name}'%'-->
    where  name like concat('%',#{name},'%')
</select>
4.8.1.2 使用${name}
<!-- List<Anime> selectAnimeListByName(@Param("name") String name);  -->
<select id="selectAnimeListByName" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`
    from   `animes`
    where  name like '%${name}%'
</select>

使用${name} 如果不取別名, 取不到參數;

There is no getter for property named 'name' in 'class java.lang.String'

4.8.2 測試

 @Test
public void testMyBatisMapperSelectResults2() throws  IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
    //根據動漫名稱 模糊 查詢動漫列表
    List<Anime> animeList = animeMapper.selectAnimeListByName("魁");
    for (Anime anime : animeList) {
        System.out.println(anime);
    }
}

4.9 分頁查詢

  • 方法一:調用介面的時候,計算好分頁起始行,SQL中直接獲取參數((pageNo - 1)*pageSize),實現分頁;
  • 方法二:使用 limit ${(pageNo - 1)*pageSize},#{pageSize} (不建議使用)
  • 方法三:使用select的子標簽bind自定義屬性,<bind name="pageIndex" value="((pageNo - 1)*pageSize)"/>

4.9.1 SQL

<select id="selectAnimeListByProduce" resultType="com.kgc.mybatis.bean.Anime">
    <bind name="pageIndex" value="((pageNo - 1)*pageSize)"/>
    select `id`,
    `cid`
    from   `animes`
    where  `produce` like concat('',#{produce},'%')
    <!-- 方式一:$符進行計算 -->
    <!-- limit ${(pageNo - 1)*pageSize},#{pageSize} -->
    <!-- 方式2:bind,自定義參數 -->
    limit #{pageIndex},#{pageSize}
</select>

4.9.2 測試

@Test
public void testSelectAnimeListByProduce() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);

    //模擬獲取分頁參數
    Integer pageNo = 1;
    Integer pageSize = 3;

    //調用mapper介面,模糊查詢,查詢分頁列表

    //方法一:調用介面的時候,計算好分頁起始行,SQL中直接獲取參數,實現分頁
    //方法二:使用 limit ${(pageNo - 1)*pageSize},#{pageSize}
    //方法三:使用select的子標簽bind,<bind name="pageIndex" value="((pageNo - 1)*pageSize)"/>

    List<Anime> animeList = animeMapper.selectAnimeListByProduce("愛奇藝",pageNo,pageSize);

    animeList.forEach(System.out::println);
}

4.10 返回Map集合

4.10.1 列名作為key,數值作為value

  • 以動漫詳情為例模擬返回map集合,將列名作為key,數值作為value;
  • 實際開發中,查詢結果集,是單條記錄,且沒有實體對應,比如:數據統計,只有統計結果,沒有統計實體;
5.10.1.1 SQL

Map<String,Object>,方法的返回類型是Map,key是String類型,value是Object類型,因為每個欄位有不同的類型

resultType="java.util.HashMap",因為將數據映射到map中;

<!--   Map<String,Object> selectAnimeMapById(Integer id);  -->
<select id="selectAnimeMapById" resultType="java.util.HashMap">
    select  `id`,
    `cid`,
    `name`
    from   `animes`
    where  `id` = #{id}
</select>
4.10.1.1 測試
@Test
public  void testSelectAnimeByMapById() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);

    Map<String, Object> animeMap = animeMapper.selectAnimeMapById(301);

    System.out.println(animeMap);

    Object actor = animeMap.get("actor");
    System.out.println("actor==>"+actor);
}

4.10.2主鍵key,實體為value

  • 以動漫詳情為例模擬返回map集合,將數據主鍵列值作為key,整條數據作為value
  • 實際開發中返回多條記錄,並需要根據key,快速遍歷,比如分組查詢;
4.10.2.1 SQL

因為它不知道你要將哪個屬性作為map的key值,所以需要@MapKey("id")指定一個實體的屬性作為map的key值;

//以動漫詳情為例模擬返回map集合,將數據主鍵列值作為key,整條數據作為value
@MapKey("id")   //這裡的MapKey 是實體的一個屬性
Map<Integer,Anime> selectAnimeMapByCid(Integer cid);

resultType="com.kgc.mybatis.bean.Anime",雖然返回的結果是map,但是數據是映射到Anime動漫實體中;

<!--   @MapKey("id")   //這裡的MapKey 是實體的一個屬性  -->
<!--   Map<Integer,Anime> selectAnimeMapByCid(Integer cid);  -->
<select id="selectAnimeMapByCid" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`
    from   `animes`
    where  `cid` = #{cid}
</select>
4.10.2.2 測試
@Test
public void  testSelectAnimeMapByCid() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);

    Map<Integer, Anime> animeMap = animeMapper.selectAnimeMapByCid(3);

    System.out.println(animeMap);

    Anime anime = animeMap.get(301);
    System.out.println(anime);
}

5、ResultMap 結果集映射

5.1 列名 和 屬性名 不匹配

  • 可以取別名,查詢出來的列名,取別名,跟實體的屬性名一致
  • 自定義resultMap映射

5.1.1 SQL

resultMap的參數 說明
id resultMap唯一id
type 返回值類型
autoMapping 是否開啟自動映射

resultMap自定義標簽內指定的列才會映射,如果查詢的結果列,不在自定義映射標簽中,但是滿足自動映射的條件(列名和實體屬性名一致), 仍然會自動映射;

除非指定resultMap標簽的autoMapping屬性為falseautoMapping="false"),沒有自定義映射的其他欄位才不會自動映射

<!--  Anime selectAnimeByResultMap(Integer id);  -->
<select id="selectAnimeByResultMap" resultMap="animeResultMap">
    select `id`,
    `cid`,
    `name`,
    `author`,
    `actor`,
    `produce`,
    `create_date` `crateTime`
    from   `animes`
    where  `id` = #{id}
</select>
<!-- 
  autoMapping="false"  關閉自動映射,只使用自定義映射;
-->
<resultMap id="animeResultMap" type="com.kgc.mybatis.bean.Anime" autoMapping="false">
    <!--   主鍵映射標簽  -->
    <id column="id" property="id"></id>
    <!--  普通列映射標簽     -->
    <result column="cid" property="cid"></result>
    <result column="name" property="name"></result>
    <result column="crateTime" property="createDate"></result>
</resultMap>

5.1.2 測試

@Test
public void  testSelectAnimeByResultMap() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);

    //使用自定義映射,查詢動漫詳情,解決列名和屬性名不同意的映射
    Anime anime = animeMapper.selectAnimeByResultMap(301);

    System.out.println(anime);
}

5.2 級聯映射

實體屬性,級聯映射;

5.2.1 一對一

級聯映射只適合一對一;

要求:查詢動漫Anime,並且查詢出動漫的 實體屬性category 的信息;

一個動漫一個動漫分類

5.2.1.1 實體

動漫實體Anime

public class Anime {
    //動漫編號
    private Integer id;
    //分類編號
    private  Integer cid;
    //名稱
    private  String name;
	......
    //分類詳情實體,一對一  (也可以定義分類名稱冗餘到實體中也可以解決)
    private Category category;
}

分類實體Category

public class Category {
    //分類編號
    private  Integer id;
    //分類名稱
    private  String name;
}
5.2.1.2 SQL
<result column="cid" property="category.id"></result>
參數 說明
column="cid" 連表查詢出來的欄位
property="category.id" 實體屬性 的屬性

先通過連表查詢,將動漫信息和分類信息查詢出來,再根據欄位一 一 映射

<resultMap id="animeResultMapCascade" type="com.kgc.mybatis.bean.Anime" >
    <!--   主鍵映射標簽  -->
    <id column="id" property="id"></id>
    <!--  普通列映射標簽     -->
    <result column="cid" property="cid"></result>
    <result column="name" property="name"></result>
    <result column="author" property="author"></result>
    <result column="create_date" property="createDate"></result>
    <!-- 級聯映射,通過 內部實體屬性名.屬性 -->
    <result column="cid" property="category.id"></result>
    <result column="cname" property="category.name"></result>
</resultMap>
5.2.1.3 測試
@Test
public void  testSelectAnimeByResultMapCascade() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);

    //級聯映射,動漫實體內部,分類實體屬性的 級聯映射
    Anime anime = animeMapper.selectAnimeByResultMapCascade(301);

    System.out.println(anime);
    //Anime(id=301,
    //		cid=3, 
    //		name=完美世界,
    //        ......
    //		category=Category(id=3, name=科幻)
    //      )
}

5.3 關聯映射 (高級映射)

實體屬性,關聯映射;

5.3.1 association 一對一

要求:查詢動漫Anime,並且查詢出動漫的 實體屬性category 的信息 ;

一個動漫一個動漫分類

5.3.1 實體

動漫實體Anime

public class Anime {
    //動漫編號
    private Integer id;
    //分類編號
    private  Integer cid;
    //名稱
    private  String name;
	......
    //分類詳情實體,一對一  
    private Category category;
}

分類實體Category

public class Category {
    //分類編號
    private  Integer id;
    //分類名稱
    private  String name;
}
5.3.2 SQL

先通過連表查詢,查詢出動漫信息,和動漫分類信息;

再通過association標簽,對動漫的 實體屬性 category 進行賦值

<!--  Anime selectAnimeByResultMapAssociation(Integer id);   -->
<select id="selectAnimeByResultMapAssociation" resultMap="animeResultMapAssociation">
    select a.`id`,
    a.`cid`,
    a.`name`,
    a.`author`,
    a.`actor`,
    a.`produce`,
    a.`create_date`,
    c.`name` 'cname'
    from   `animes` a,`category` c
    where  a.`cid` = c.`id`
    and a.`id` = #{id}
</select>

<resultMap id="animeResultMapAssociation" type="com.kgc.mybatis.bean.Anime" >
    <!--   主鍵映射標簽  -->
    <id column="id" property="id"></id>
    <!--  普通列映射標簽     -->
    <result column="cid" property="cid"></result>
    <result column="name" property="name"></result>
    <result column="author" property="author"></result>
    <result column="produce" property="produce"></result>
    <result column="create_date" property="createDate"></result>
    <!-- 關聯映射,內部實體一對一 -->
    <association property="category" javaType="com.kgc.mybatis.bean.Category">
        <id column="cid" property="id"></id>
        <result column="cname" property="name"></result>
    </association>
</resultMap>
5.3.3 測試
@Test
public void  testSelectAnimeByResultMapAssociation() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);

    Anime anime = animeMapper.selectAnimeByResultMapAssociation(301);

    System.out.println(anime);
    //Anime(id=301,
    //		cid=3, 
    //		name=完美世界,
    //        ......
    //		category=Category(id=3, name=科幻)
    //      )
}

5.3.2 collection 一對多

要求:查詢分類Category,並且查詢出分類下的動漫集合屬性 animes 信息

一個動漫分類多個動漫

5.3.1 實體

分類實體Category

public class Category {
    //分類編號
    private  Integer id;
    //分類名稱
    private  String name;
    //當前 分類下的 動漫集合
    private List<Anime> animes;
}

動漫實體Anime

public class Anime {
    //動漫編號
    private Integer id;
    //分類編號
    private  Integer cid;
    //名稱
    private  String name;
	......
}
5.3.2 SQL

先通過連表查詢,查詢出動漫分類信息,和動漫信息;

再通過collection標簽,對動漫分類的 集合屬性 animes 進行賦值

<!--   Category selectCategoryByResultMapCollection(Integer id);    -->
<select id="selectCategoryByResultMapCollection" resultMap="categoryByResultMapCollection">
    select c.`id`,
    c.`name`,
    a.`id` 'aid',
    a.`cid`,
    a.`name` 'aname',
    a.`author`,
    a.`actor`,
    a.`create_date`,
    a.`produce`
    from   `category` c,`animes` a
    where  c.`id` = a.`cid`
    and c.`id` = #{id}
</select>

<resultMap id="categoryByResultMapCollection" type="com.kgc.mybatis.bean.Category">
    <id column="id" property="id"></id>
    <result column="name" property="name"></result>
    <!-- 高級映射,使用集合 關聯映射,解決內部集合映射,一對多 -->
    <collection property="animes" ofType="com.kgc.mybatis.bean.Anime">
        <id column="aid" property="id"></id>
        <result column="cid" property="cid"></result>
        <result column="aname" property="name"></result>
        <result column="author" property="author"></result>
        <result column="actor" property="actor"></result>
        <result column="produce" property="produce"></result>
        <result column="create_date" property="createDate"></result>
    </collection>
</resultMap>
5.3.3 測試
@Test
public void  testSelectCategoryByResultMapCollection() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    CategoryMapper categoryMapper = sqlSession.getMapper(CategoryMapper.class);

    //查詢動漫分類詳情,內部集合類型 映射
    Category category = categoryMapper.selectCategoryByResultMapCollection(3);

    System.out.println(category);
    //Category(id=3, 
    //		   name=科幻, 
    //		   animes=[Anime(id=301, cid=3, name=完美世界, ...), 
    //                 Anime(id=649, cid=3, name=蠟筆小新, ...)
    //                 ]
    //         )
}

5.4 嵌套select, 延遲載入 和 分步查詢

  • 開啟延遲載入,預設false,需要支持延遲,改為true;
    • <setting name="lazyLoadingEnabled" value="true"></setting>
  • 按需載入 ,是否全部載入,
    • (前提必須是言辭載入是打開的,而且是自定義映射,配合高級嵌套select查詢);
    • 3.4.1及之前的版本中預設為true,全部載入(任意一方法的調用都會載入該對象的所有延遲載入屬性);
    • 只有改為false,才會分步載入,需要調用該方法時,才進行 延遲載入屬性;
    • <setting name="aggressiveLazyLoading" value="false"/>

5.4.1 association 一對一

要求:查詢動漫Anime,並且查詢出動漫的 實體屬性category 的信息 ;

一個動漫一個動漫分類

5.4.1.1 實體

跟 關聯映射 association 一對一 的實體一樣;

5.4.1.2 SQL
<association property="category" select="com.kgc.mybatis.mapper.CategoryMapper.selectCategoryById" column="cid" fetchType="eager">
</association>
參數 說明
property 實體的屬性
select 指定嵌套的select語句的唯一標識
column 指定嵌套的sleect語句執行需要的參數,多參數JSON格式{key1=col1,key2=col2}
fetchType 是否適配系統延遲載入,預設是lazy,如果需要局部關閉延遲載入,改為eager

先通過id查詢動漫Anime,再通過動漫的cid,去查詢 動漫分類

AnimeMapper.xml

<!--Anime selectAnimeByResultMapAssociationLazyLoadingStep(Integer id);-->
<select id="selectAnimeByResultMapAssociationLazyLoadingStep" resultMap="associationLazyLoadingStep">
    select `id`,
    `cid`,
    `name`,
    `author`,
    `actor`,
    `produce`,
    `create_date` `crateTime`
    from   `animes`
    where  `id` = #{id}
</select>
<!--  嵌套select語句實現 延遲載入 和 分佈查詢  -->
<resultMap id="associationLazyLoadingStep" type="com.kgc.mybatis.bean.Anime">
    <!--   主鍵映射標簽  -->
    <id column="id" property="id"></id>
    <!--  普通列映射標簽     -->
    <result column="cid" property="cid"></result>
    <result column="name" property="name"></result>
    <result column="author" property="author"></result>
    <result column="produce" property="produce"></result>
    <result column="crateTime" property="createDate"></result>
    <!-- 高級映射,內部實體一對一 ,嵌套select語句, 延遲載入和分佈查詢  -->
    <!-- fetchType="eager" 局部覆蓋按需載入  -->
    <!--
     select屬性,指定嵌套的select語句的唯一標識(myabtis框架可識別的)
     column屬性:指定嵌套的sleect語句執行需要的參數,即將當前查詢某列的值作為參數,傳遞到指定的查詢語句中,如果有多個參數,可以使用JSON格式{key1=col1,key2=col2}
     fetchType屬性:設置當前自定高級映射是否適配系統延遲載入,預設是lazy,如果需要局部關閉延遲載入,改為eager
     -->
    <association property="category" select="com.kgc.mybatis.mapper.CategoryMapper.selectCategoryById" column="cid" fetchType="eager">
    </association>
</resultMap>

CategoryMapper.xml

<!--   Category selectCategoryById(Integer id);  -->
<select id="selectCategoryById" resultType="com.kgc.mybatis.bean.Category">
    select `id`,
    `name`
    from `category`
    where `id`= #{id}
</select>
5.4.1.3 測試
 @Test
public void  testSelectAnimeByResultMapAssociationLazyLoadingStep() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
    
    //高級映射,內部實體一對一 ,使用嵌套select 延遲載入和分佈查詢
    Anime anime = animeMapper.selectAnimeByResultMapAssociationLazyLoadingStep(301);

    System.out.println("如果只使用動漫的信息,不使用載入 動漫分類的SQL");
    System.out.println(anime.getName());

    System.out.println("=============================================");
    System.out.println("動漫的分類名稱:"+anime.getCategory().getName());
}

開啟延遲載入和按需載入

關閉延遲載入和按需載入,或者局部關閉延遲載入

5.4.2 collection 一對多

要求:查詢分類Category,並且查詢出分類下的動漫集合屬性 animes 信息

一個動漫分類多個動漫

5.4.2.1 實體

跟 關聯映射 collection 一對多 的實體一樣;

5.4.2.2 SQL

先通過id查詢分類Category,再通過動漫的id,去查詢cid等於id的動漫

CategoryMapper.xml

<!--Category selectCategoryByResultMapCollectionAssociationLazyLoadingStep(Integer id); -->
<select id="selectCategoryByResultMapCollectionAssociationLazyLoadingStep" resultMap="associationLazyLoadingStep" >
    select `id`,
    `name`
    from `category`
    where `id`= #{id}
</select>

<resultMap id="associationLazyLoadingStep" type="com.kgc.mybatis.bean.Category">
    <id column="id" property="id"></id>
    <result column="name" property="name"></result>
    <!-- 高級映射,使用集合映射,解決內部 集合映射,一對多 -->
    <collection property="animes" select="com.kgc.mybatis.mapper.AnimeMapper.selectAnimeListByCid" column="{cid=id}" fetchType="lazy">
    </collection>
</resultMap>

AnimeMapper.xml

<!--   Map<Integer,Anime> selectAnimeMapByCid(Integer cid);  -->
<select id="selectAnimeMapByCid" resultType="com.kgc.mybatis.bean.Anime">
    select `id`,
    `cid`,
    `name`,
    `author`,
    `actor`,
    `produce`,
    `create_date`
    from   `animes`
    where  `cid` = #{cid}
</select>
5.4.2.3 測試
@Test
public void testSelectCategoryByResultMapCollectionAssociationLazyLoadingStep() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();
    CategoryMapper categoryMapper = sqlSession.getMapper(CategoryMapper.class);

    Category category = categoryMapper.selectCategoryByResultMapCollectionAssociationLazyLoadingStep(1);

    System.out.println("分類名稱:"+category.getName());

    System.out.println("=============================================");
    System.out.println("該分類下的動漫:"+category.getAnimes());
}

開啟延遲載入和按需載入

關閉延遲載入和按需載入,或者局部關閉延遲載入


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • 關於安裝 進入pom.xml文件目錄下,使用命令mvn install 當然也可以使用類似idea這類本身已經集成好maven插件按鈕的編輯器進行安裝 安裝過程會輸出安裝jar包的目錄信息,同樣的,跟class編譯後的目標文件一起,放在target目錄下 註意:開發編譯過程中,如果只 編譯 mvn ...
  • 編碼問題,誰不想避其鋒芒; 一、業務背景 在搜索引擎的功能上,曾經遇到過這樣一個問題,資料庫中某個公司名稱中存在特殊編碼,儘管數據已經正常同步到索引中,但是系統中關鍵詞始終也無法匹配到該公司; 然後在庫中模糊匹配,將公司名稱複製到搜索框中,這樣就可以正常命中索引,那麼問題也就很清楚了,這種數據"隱身 ...
  • Python小游戲——外星人入侵(保姆級教程) 第一章:武裝飛船 06:讓飛船移動 下麵來讓玩家能夠左右移動飛船。我們將編寫代碼,在用戶按左或右箭頭鍵時做出響應。我們將首先專註於向右移動,再使用同樣的原理來控制向左移動。通過這樣做,你將學會如何控制屏幕圖像的移動。 ...
  • 哈嘍,大家好,今天咱們試試只用20行代碼來實現批量獲取網抑雲文件保存本地,炒雞簡單! 悄悄的告訴你,其實不到20行代碼~ 你需要準備 本次使用的環境是Python3.8,編輯器是pycharm 模塊使用的是requests、re、os 三個,其中requests是第三方模塊,需要手動安裝一下,re、 ...
  • 鋼鐵知識庫,一個學習python爬蟲、數據分析的知識庫。人生苦短,快用python。 上一章我們講解針對結構化的html、xml數據,使用Xpath實現網頁內容爬取。本章我們再來聊另一個高效的神器:Beautiful Soup4。相比於傳統正則表達方式去解析網頁源代碼,這個就簡單得多,實踐是檢驗真理 ...
  • “談談常用的分散式ID設計方案”! 一個工作了7年的同學,被問到了這樣一個問題。 問題並不難,但是在實際面試的時候,如果只是回答1,2,3 很難通過面試,因為作為一個高級程式員,還需要有自己的理解和思考。 大家好,我是Mic,一個工作了14年的Java程式員。 這個問題的高手回答,我整理到了15W字 ...
  • 二、流程式控制制 1、用戶交互Scanner java.util.Scanner是Java5的新特性,我們可以通過Scanner類來獲取用戶輸入。 基本語法: Scanner s = new Scanner(System.in); 通過Scanner類的net()與nextLine()方法獲取輸入的字元 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...