1. 程式人生 > 其它 >Mybatis增刪改查

Mybatis增刪改查

Mybatis增刪改查

1,配置檔案實現CRUD

1.1 環境準備

  • 資料庫表(tb_brand)及資料準備

    -- 刪除tb_brand表
    drop table if exists tb_brand;
    -- 建立tb_brand表
    create table tb_brand
    (
        -- id 主鍵
        id           int primary key auto_increment,
        -- 品牌名稱
        brand_name   varchar(20),
        -- 企業名稱
        company_name varchar(20),
        -- 排序欄位
        ordered      int,
        -- 描述資訊
        description  varchar(100),
        -- 狀態:0:禁用  1:啟用
        status       int
    );
    -- 新增資料
    insert into tb_brand (brand_name, company_name, ordered, description, status)
    values ('三隻松鼠', '三隻松鼠股份有限公司', 5, '好吃不上火', 0),
           ('華為', '華為技術有限公司', 100, '華為致力於把數字世界帶入每個人、每個家庭、每個組織,構建萬物互聯的智慧世界', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1);
    
  • 實體類 Brand

    com.itheima.pojo 包下建立 Brand 實體類。

    public class Brand {
        // id 主鍵
        private Integer id;
        // 品牌名稱
        private String brandName;
        // 企業名稱
        private String companyName;
        // 排序欄位
        private Integer ordered;
        // 描述資訊
        private String description;
        // 狀態:0:禁用  1:啟用
        private Integer status;
        
        //省略 setter and getter。自己寫時要補全這部分程式碼
    }
    
  • 編寫測試用例

    測試程式碼需要在 test/java 目錄下建立包及測試用例。

  • 安裝 MyBatisX 外掛

    • MybatisX 是一款基於 IDEA 的快速開發外掛,為效率而生。

    • 主要功能

      • XML對映配置檔案 和 介面方法 間相互跳轉
      • 根據介面方法生成 statement
    • 外掛效果

      • 紅色頭繩的表示對映配置檔案,藍色頭繩的表示mapper介面。
      • 在mapper介面點選紅色頭繩的小鳥圖示會自動跳轉到對應的對映配置檔案,在對映配置檔案中點選藍色頭繩的小鳥圖示會自動跳轉到對應的mapper介面。
      • 也可以在mapper介面中定義方法,自動生成對映配置檔案中的 statement ,如圖所示

1.2 查詢所有資料

1.2.1 編寫介面方法

com.itheima.mapper 包寫建立名為 BrandMapper 的介面。並在該介面中定義 List<Brand> selectAll() 方法。

public interface BrandMapper {
    /**
     * 查詢所有
     */
    List<Brand> selectAll();
}

1.2.2 編寫SQL語句

reources 下建立 com/itheima/mapper 目錄結構,並在該目錄下建立名為 BrandMapper.xml 的對映配置檔案

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.BrandMapper">
    <select id="selectAll" resultType="brand">
        select *
        from tb_brand;
    </select>
</mapper>

1.2.3 編寫測試方法

MybatisTest 類中編寫測試查詢所有的方法

@Test
public void testSelectAll() throws IOException {
    //1. 獲取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    //2. 獲取SqlSession物件
    SqlSession sqlSession = sqlSessionFactory.openSession();

    //3. 獲取Mapper介面的代理物件
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

    //4. 執行方法
    List<Brand> brands = brandMapper.selectAll();
    System.out.println(brands);

    //5. 釋放資源
    sqlSession.close();

}

執行測試方法結果如下:

從上面結果我們看到了問題,有些資料封裝成功了,而有些資料並沒有封裝成功。為什麼這樣呢?

這個問題可以通過兩種方式進行解決:

  • 給欄位起別名
  • 使用resultMap定義欄位和屬性的對映關係

1.2.4 起別名解決上述問題

從上面結果可以看到 brandNamecompanyName 這兩個屬性的資料沒有封裝成功,查詢 實體類 和 表中的欄位 發現,在實體類中屬性名是 brandNamecompanyName ,而表中的欄位名為 brand_namecompany_name,如下圖所示 。那麼我們只需要保持這兩部分的名稱一致這個問題就迎刃而解。

我們可以在寫sql語句時給這兩個欄位起別名,將別名定義成和屬性名一致即可。

<select id="selectAll" resultType="brand">
    select
    id, brand_name as brandName, company_name as companyName, ordered, description, status
    from tb_brand;
</select>

而上面的SQL語句中的欄位列表書寫麻煩,如果表中還有更多的欄位,同時其他的功能也需要查詢這些欄位時就顯得我們的程式碼不夠精煉。Mybatis提供了sql 片段可以提高sql的複用性。

SQL片段:

  • 將需要複用的SQL片段抽取到 sql 標籤中

    <sql id="brand_column">
    	id, brand_name as brandName, company_name as companyName, ordered, description, status
    </sql>
    

    id屬性值是唯一標識,引用時也是通過該值進行引用。

  • 在原sql語句中進行引用

    使用 include 標籤引用上述的 SQL 片段,而 refid 指定上述 SQL 片段的id值。

    <select id="selectAll" resultType="brand">
        select
        <include refid="brand_column" />
        from tb_brand;
    </select>
    

1.2.5 使用resultMap解決上述問題

起別名 + sql片段的方式可以解決上述問題,但是它也存在問題。如果還有功能只需要查詢部分欄位,而不是查詢所有欄位,那麼我們就需要再定義一個 SQL 片段,這就顯得不是那麼靈活。

那麼我們也可以使用resultMap來定義欄位和屬性的對映關係的方式解決上述問題。

  • 在對映配置檔案中使用resultMap定義 欄位 和 屬性 的對映關係

    <resultMap id="brandResultMap" type="brand">
        <!--
                id:完成主鍵欄位的對映
                    column:表的列名
                    property:實體類的屬性名
                result:完成一般欄位的對映
                    column:表的列名
                    property:實體類的屬性名
            -->
        <result column="brand_name" property="brandName"/>
        <result column="company_name" property="companyName"/>
    </resultMap>
    

    注意:在上面只需要定義 欄位名 和 屬性名 不一樣的對映,而一樣的則不需要專門定義出來。

  • SQL語句正常編寫

    <select id="selectAll" resultMap="brandResultMap">
        select *
        from tb_brand;
    </select>
    

1.2.6 小結

實體類屬性名 和 資料庫表列名 不一致,不能自動封裝資料

  • 起別名:在SQL語句中,對不一樣的列名起別名,別名和實體類屬性名一樣
    • 可以定義 片段,提升複用性
  • resultMap:定義 完成不一致的屬性名和列名的對映

1.3 查詢詳情

1.3.1 編寫介面方法

BrandMapper 介面中定義根據id查詢資料的方法

/**
  * 檢視詳情:根據Id查詢
  */
Brand selectById(int id);

1.3.2 編寫SQL語句

BrandMapper.xml 對映配置檔案中編寫 statement,使用 resultMap 而不是使用 resultType

<select id="selectById"  resultMap="brandResultMap">
    select *
    from tb_brand where id = #{id};
</select>

1.3.3 編寫測試方法

test/java 下的 com.itheima.mapper 包下的 MybatisTest類中 定義測試方法

 @Test
public void testSelectById() throws IOException {
    //接收引數,該id以後需要傳遞過來
    int id = 1;

    //1. 獲取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    //2. 獲取SqlSession物件
    SqlSession sqlSession = sqlSessionFactory.openSession();

    //3. 獲取Mapper介面的代理物件
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

    //4. 執行方法
    Brand brand = brandMapper.selectById(id);
    System.out.println(brand);

    //5. 釋放資源
    sqlSession.close();
}

執行測試方法結果如下:

1.3.4 引數佔位符

查詢到的結果很好理解就是id為1的這行資料。而這裡我們需要看控制檯顯示的SQL語句,能看到使用?進行佔位。說明我們在對映配置檔案中的寫的 #{id} 最終會被?進行佔位。

mybatis提供了兩種引數佔位符:

->#{} :執行SQL時,會將 #{} 佔位符替換為?,將來自動設定引數值。從上述例子可以看出使用#{} 底層使用的是 PreparedStatement

->${} :拼接SQL。底層使用的是 Statement,會存在SQL注入問題。如下圖將 對映配置檔案中的 #{} 替換成 ${} 來看效果

<select id="selectById"  resultMap="brandResultMap">
    select *
    from tb_brand where id = ${id};
</select>

重新執行檢視結果如下:

1.3.5 parameterType使用

對於有引數的mapper介面方法,我們在對映配置檔案中應該配置 ParameterType 來指定引數型別。只不過該屬性都可以省略。如下圖:

<select id="selectById" parameterType="int" resultMap="brandResultMap">
    select *
    from tb_brand where id = ${id};
</select>

1.3.6 SQL語句中特殊欄位處理

以後肯定會在SQL語句中寫一下特殊字元,比如某一個欄位大於某個值,如下圖

可以看出報錯了,因為對映配置檔案是xml型別的問題,而 > < 等這些字元在xml中有特殊含義,所以此時我們需要將這些符號進行轉義,可以使用以下兩種方式進行轉義

  • 轉義字元

    下圖的 &lt; 就是 < 的轉義字元。

1.4 多條件查詢

1.4.1 編寫介面方法

BrandMapper 介面中定義多條件查詢的方法。

而該功能有三個引數,我們就需要考慮定義介面時,引數應該如何定義。Mybatis針對多引數有多種實現

  • 使用 @Param("引數名稱") 標記每一個引數,在對映配置檔案中就需要使用 #{引數名稱} 進行佔位

    List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName,@Param("brandName") String brandName);
    
  • 將多個引數封裝成一個 實體物件 ,將該實體物件作為介面的方法引數。該方式要求在對映配置檔案的SQL中使用 #{內容} 時,裡面的內容必須和實體類屬性名保持一致。

    List<Brand> selectByCondition(Brand brand);
    
  • 將多個引數封裝到map集合中,將map集合作為介面的方法引數。該方式要求在對映配置檔案的SQL中使用 #{內容} 時,裡面的內容必須和map集合中鍵的名稱一致。

    List<Brand> selectByCondition(Map map);
    

1.4.2 編寫SQL語句

BrandMapper.xml 對映配置檔案中編寫 statement,使用 resultMap 而不是使用 resultType

<select id="selectByCondition" resultMap="brandResultMap">
    select *
    from tb_brand
    where status = #{status}
    and company_name like #{companyName}
    and brand_name like #{brandName}
</select>

1.4.3 編寫測試方法

test/java 下的 com.itheima.mapper 包下的 MybatisTest類中 定義測試方法

@Test
public void testSelectByCondition() throws IOException {
    //接收引數
    int status = 1;
    String companyName = "華為";
    String brandName = "華為";

    // 處理引數
    companyName = "%" + companyName + "%";
    brandName = "%" + brandName + "%";

    //1. 獲取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //2. 獲取SqlSession物件
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //3. 獲取Mapper介面的代理物件
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

    //4. 執行方法
	//方式一 :介面方法引數使用 @Param 方式呼叫的方法
    //List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName);
    //方式二 :介面方法引數是 實體類物件 方式呼叫的方法
     //封裝物件
    /* Brand brand = new Brand();
        brand.setStatus(status);
        brand.setCompanyName(companyName);
        brand.setBrandName(brandName);*/
    
    //List<Brand> brands = brandMapper.selectByCondition(brand);
    
    //方式三 :介面方法引數是 map集合物件 方式呼叫的方法
    Map map = new HashMap();
    map.put("status" , status);
    map.put("companyName", companyName);
    map.put("brandName" , brandName);
    List<Brand> brands = brandMapper.selectByCondition(map);
    System.out.println(brands);

    //5. 釋放資源
    sqlSession.close();
}

1.4.4 動態SQL

上述功能實現存在很大的問題。使用者在輸入條件時,肯定不會所有的條件都填寫,這個時候我們的SQL語句就不能那樣寫的

例如使用者只輸入 當前狀態 時,SQL語句就是

select * from tb_brand where status = #{status}

而使用者如果只輸入企業名稱時,SQL語句就是

select * from tb_brand where company_name like #{companName}

而使用者如果輸入了 當前狀態企業名稱 時,SQL語句又不一樣

select * from tb_brand where status = #{status} and company_name like #{companName}

針對上述的需要,Mybatis對動態SQL有很強大的支撐:

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

我們先學習 if 標籤和 where 標籤:

  • if 標籤:條件判斷

    • test 屬性:邏輯表示式
    <select id="selectByCondition" resultMap="brandResultMap">
        select *
        from tb_brand
        where
            <if test="status != null">
                and status = #{status}
            </if>
            <if test="companyName != null and companyName != '' ">
                and company_name like #{companyName}
            </if>
            <if test="brandName != null and brandName != '' ">
                and brand_name like #{brandName}
            </if>
    </select>
    

    如上的這種SQL語句就會根據傳遞的引數值進行動態的拼接。如果此時status和companyName有值那麼就會值拼接這兩個條件。

    執行結果如下:

    但是它也存在問題,如果此時給的引數值是

    Map map = new HashMap();
    // map.put("status" , status);
    map.put("companyName", companyName);
    map.put("brandName" , brandName);
    

    拼接的SQL語句就變成了

    select * from tb_brand where and company_name like ? and brand_name like ?
    

    而上面的語句中 where 關鍵後直接跟 and 關鍵字,這就是一條錯誤的SQL語句。這個就可以使用 where 標籤解決

  • where 標籤

    • 作用:
      • 替換where關鍵字
      • 會動態的去掉第一個條件前的 and
      • 如果所有的引數沒有值則不加where關鍵字
    <select id="selectByCondition" resultMap="brandResultMap">
        select *
        from tb_brand
        <where>
            <if test="status != null">
                and status = #{status}
            </if>
            <if test="companyName != null and companyName != '' ">
                and company_name like #{companyName}
            </if>
            <if test="brandName != null and brandName != '' ">
                and brand_name like #{brandName}
            </if>
        </where>
    </select>
    

    注意:需要給每個條件前都加上 and 關鍵字。

1.5 單個條件(動態SQL)

1.5.1 編寫介面方法

BrandMapper 介面中定義單條件查詢的方法。

/**
  * 單條件動態查詢
  * @param brand
  * @return
  */
List<Brand> selectByConditionSingle(Brand brand);

1.5.2 編寫SQL語句

BrandMapper.xml 對映配置檔案中編寫 statement,使用 resultMap 而不是使用 resultType

<select id="selectByConditionSingle" resultMap="brandResultMap">
    select *
    from tb_brand
    <where>
        <choose><!--相當於switch-->
            <when test="status != null"><!--相當於case-->
                status = #{status}
            </when>
            <when test="companyName != null and companyName != '' "><!--相當於case-->
                company_name like #{companyName}
            </when>
            <when test="brandName != null and brandName != ''"><!--相當於case-->
                brand_name like #{brandName}
            </when>
        </choose>
    </where>
</select>

1.5.3 編寫測試方法

test/java 下的 com.itheima.mapper 包下的 MybatisTest類中 定義測試方法

@Test
public void testSelectByConditionSingle() throws IOException {
    //接收引數
    int status = 1;
    String companyName = "華為";
    String brandName = "華為";

    // 處理引數
    companyName = "%" + companyName + "%";
    brandName = "%" + brandName + "%";

    //封裝物件
    Brand brand = new Brand();
    //brand.setStatus(status);
    brand.setCompanyName(companyName);
    //brand.setBrandName(brandName);

    //1. 獲取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //2. 獲取SqlSession物件
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //3. 獲取Mapper介面的代理物件
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //4. 執行方法
    List<Brand> brands = brandMapper.selectByConditionSingle(brand);
    System.out.println(brands);

    //5. 釋放資源
    sqlSession.close();
}

執行測試方法結果如下:

1.6 新增資料

1.6.1 編寫介面方法

BrandMapper 介面中定義新增方法。

 /**
   * 新增
   */
void add(Brand brand);

1.6.2 編寫SQL語句

BrandMapper.xml 對映配置檔案中編寫新增資料的 statement

<insert id="add">
    insert into tb_brand (brand_name, company_name, ordered, description, status)
    values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>

1.6.3 編寫測試方法

test/java 下的 com.itheima.mapper 包下的 MybatisTest類中 定義測試方法

@Test
public void testAdd() throws IOException {
    //接收引數
    int status = 1;
    String companyName = "波導手機";
    String brandName = "波導";
    String description = "手機中的戰鬥機";
    int ordered = 100;

    //封裝物件
    Brand brand = new Brand();
    brand.setStatus(status);
    brand.setCompanyName(companyName);
    brand.setBrandName(brandName);
    brand.setDescription(description);
    brand.setOrdered(ordered);

    //1. 獲取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //2. 獲取SqlSession物件
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //SqlSession sqlSession = sqlSessionFactory.openSession(true); //設定自動提交事務,這種情況不需要手動提交事務了
    //3. 獲取Mapper介面的代理物件
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //4. 執行方法
    brandMapper.add(brand);
    //提交事務
    sqlSession.commit();
    //5. 釋放資源
    sqlSession.close();
}

執行結果如下:

1.6.4 新增-主鍵返回

在資料新增成功後,有時候需要獲取插入資料庫資料的主鍵(主鍵是自增長)。

我們將上面新增品牌資料的案例中對映配置檔案裡 statement 進行修改,如下

<insert id="add" useGeneratedKeys="true" keyProperty="id">
    insert into tb_brand (brand_name, company_name, ordered, description, status)
    values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>

在 insert 標籤上新增如下屬性:

  • useGeneratedKeys:是夠獲取自動增長的主鍵值。true表示獲取
  • keyProperty :指定將獲取到的主鍵值封裝到哪兒個屬性裡

1.7 修改

1.7.1 編寫介面方法

BrandMapper 介面中定義修改方法。

 /**
   * 修改
   */
void update(Brand brand);

上述方法引數 Brand 就是封裝了需要修改的資料,而id肯定是有資料的,這也是和新增方法的區別。

1.7.2 編寫SQL語句

BrandMapper.xml 對映配置檔案中編寫修改資料的 statement

<update id="update">
    update tb_brand
    <set>
        <if test="brandName != null and brandName != ''">
            brand_name = #{brandName},
        </if>
        <if test="companyName != null and companyName != ''">
            company_name = #{companyName},
        </if>
        <if test="ordered != null">
            ordered = #{ordered},
        </if>
        <if test="description != null and description != ''">
            description = #{description},
        </if>
        <if test="status != null">
            status = #{status}
        </if>
    </set>
    where id = #{id};
</update>

set 標籤可以用於動態包含需要更新的列,忽略其它不更新的列。

1.7.3 編寫測試方法

test/java 下的 com.itheima.mapper 包下的 MybatisTest類中 定義測試方法

@Test
public void testUpdate() throws IOException {
    //接收引數
    int status = 0;
    String companyName = "波導手機";
    String brandName = "波導";
    String description = "波導手機,手機中的戰鬥機";
    int ordered = 200;
    int id = 6;

    //封裝物件
    Brand brand = new Brand();
    brand.setStatus(status);
    //        brand.setCompanyName(companyName);
    //        brand.setBrandName(brandName);
    //        brand.setDescription(description);
    //        brand.setOrdered(ordered);
    brand.setId(id);

    //1. 獲取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //2. 獲取SqlSession物件
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //SqlSession sqlSession = sqlSessionFactory.openSession(true);
    //3. 獲取Mapper介面的代理物件
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //4. 執行方法
    int count = brandMapper.update(brand);
    System.out.println(count);
    //提交事務
    sqlSession.commit();
    //5. 釋放資源
    sqlSession.close();
}

執行測試方法結果如下:

從結果中SQL語句可以看出,只修改了 status 欄位值,因為我們給的資料中只給Brand實體物件的 status 屬性設定值了。這就是 set 標籤的作用。

1.8 刪除一行資料

1.8.1 編寫介面方法

BrandMapper 介面中定義根據id刪除方法。

/**
  * 根據id刪除
  */
void deleteById(int id);

1.8.2 編寫SQL語句

BrandMapper.xml 對映配置檔案中編寫刪除一行資料的 statement

<delete id="deleteById">
    delete from tb_brand where id = #{id};
</delete>

1.8.3 編寫測試方法

test/java 下的 com.itheima.mapper 包下的 MybatisTest類中 定義測試方法

 @Test
public void testDeleteById() throws IOException {
    //接收引數
    int id = 6;

    //1. 獲取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //2. 獲取SqlSession物件
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //SqlSession sqlSession = sqlSessionFactory.openSession(true);
    //3. 獲取Mapper介面的代理物件
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //4. 執行方法
    brandMapper.deleteById(id);
    //提交事務
    sqlSession.commit();
    //5. 釋放資源
    sqlSession.close();
}

執行過程只要沒報錯,直接到資料庫查詢資料是否還存在。

1.9 批量刪除

1.9.1 編寫介面方法

BrandMapper 介面中定義刪除多行資料的方法。

/**
  * 批量刪除
  */
void deleteByIds(int[] ids);

引數是一個數組,陣列中儲存的是多條資料的id

1.9.2 編寫SQL語句

BrandMapper.xml 對映配置檔案中編寫刪除多條資料的 statement

編寫SQL時需要遍歷陣列來拼接SQL語句。Mybatis 提供了 foreach 標籤供我們使用

foreach 標籤

用來迭代任何可迭代的物件(如陣列,集合)。

  • collection 屬性:
    • mybatis會將陣列引數,封裝為一個Map集合。
      • 預設:array = 陣列
    • 使用@Param註解改變map集合的預設key的名稱
  • item 屬性:本次迭代獲取到的元素。
  • separator 屬性:集合項迭代之間的分隔符。foreach 標籤不會錯誤地新增多餘的分隔符。也就是最後一次迭代不會加分隔符。
  • open 屬性:該屬性值是在拼接SQL語句之前拼接的語句,只會拼接一次
  • close 屬性:該屬性值是在拼接SQL語句拼接後拼接的語句,只會拼接一次
<delete id="deleteByIds">
    delete from tb_brand where id
    in
    <foreach collection="array" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
    ;
</delete>

假如陣列中的id資料是{1,2,3},那麼拼接後的sql語句就是:

delete from tb_brand where id in (1,2,3);

1.9.3 編寫測試方法

test/java 下的 com.itheima.mapper 包下的 MybatisTest類中 定義測試方法

@Test
public void testDeleteByIds() throws IOException {
    //接收引數
    int[] ids = {5,7,8};

    //1. 獲取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //2. 獲取SqlSession物件
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //SqlSession sqlSession = sqlSessionFactory.openSession(true);
    //3. 獲取Mapper介面的代理物件
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //4. 執行方法
    brandMapper.deleteByIds(ids);
    //提交事務
    sqlSession.commit();
    //5. 釋放資源
    sqlSession.close();
}

1.10 Mybatis引數傳遞

Mybatis 介面方法中可以接收各種各樣的引數,如下:

  • 多個引數
  • 單個引數:單個引數又可以是如下型別
    • POJO 型別
    • Map 集合型別
    • Collection 集合型別
    • List 集合型別
    • Array 型別
    • 其他型別

1.10.1 多個引數

如下面的程式碼,就是接收兩個引數,而接收多個引數需要使用 @Param 註解,那麼為什麼要加該註解呢?這個問題要弄明白就必須來研究Mybatis 底層對於這些引數是如何處理的。

User select(@Param("username") String username,@Param("password") String password);
<select id="select" resultType="user">
	select *
    from tb_user
    where 
    	username=#{username}
    	and password=#{password}
</select>

我們在介面方法中定義多個引數,Mybatis 會將這些引數封裝成 Map 集合物件,值就是引數值,而鍵在沒有使用 @Param 註解時有以下命名規則:

  • 以 arg 開頭 :第一個引數就叫 arg0,第二個引數就叫 arg1,以此類推。如:

    map.put("arg0",引數值1);

    map.put("arg1",引數值2);

  • 以 param 開頭 : 第一個引數就叫 param1,第二個引數就叫 param2,依次類推。如:

    map.put("param1",引數值1);

    map.put("param2",引數值2);

程式碼驗證:

  • UserMapper 介面中定義如下方法

    User select(String username,String password);
    
  • UserMapper.xml 對映配置檔案中定義SQL

    <select id="select" resultType="user">
    	select *
        from tb_user
        where 
        	username=#{arg0}
        	and password=#{arg1}
    </select>
    

    或者

    <select id="select" resultType="user">
    	select *
        from tb_user
        where 
        	username=#{param1}
        	and password=#{param2}
    </select>
    
  • 執行程式碼結果如下

    在對映配合檔案的SQL語句中使用用 arg 開頭的和 param 書寫,程式碼的可讀性會變的特別差,此時可以使用 @Param 註解。

在介面方法引數上使用 @Param 註解,Mybatis 會將 arg 開頭的鍵名替換為對應註解的屬性值。

程式碼驗證:

  • UserMapper 介面中定義如下方法,在 username 引數前加上 @Param 註解

    User select(@Param("username") String username, String password);
    

    Mybatis 在封裝 Map 集合時,鍵名就會變成如下:

    map.put("username",引數值1);

    map.put("arg1",引數值2);

    map.put("param1",引數值1);

    map.put("param2",引數值2);

  • UserMapper.xml 對映配置檔案中定義SQL

    <select id="select" resultType="user">
    	select *
        from tb_user
        where 
        	username=#{username}
        	and password=#{param2}
    </select>
    
  • 執行程式結果沒有報錯。而如果將 #{} 中的 username 還是寫成 arg0

    <select id="select" resultType="user">
    	select *
        from tb_user
        where 
        	username=#{arg0}
        	and password=#{param2}
    </select>
    
  • 執行程式則可以看到錯誤

結論:以後介面引數是多個時,在每個引數上都使用 @Param 註解。這樣程式碼的可讀性更高。

1.10.2 單個引數

  • POJO 型別

    直接使用。要求 屬性名引數佔位符名稱 一致

  • Map 集合型別

    直接使用。要求 map集合的鍵名引數佔位符名稱 一致

  • Collection 集合型別

    Mybatis 會將集合封裝到 map 集合中,如下:

    map.put("arg0",collection集合);

    map.put("collection",collection集合;

    可以使用 @Param 註解替換map集合中預設的 arg 鍵名。

  • List 集合型別

    Mybatis 會將集合封裝到 map 集合中,如下:

    map.put("arg0",list集合);

    map.put("collection",list集合);

    map.put("list",list集合);

    可以使用 @Param 註解替換map集合中預設的 arg 鍵名。

  • Array 型別

    Mybatis 會將集合封裝到 map 集合中,如下:

    map.put("arg0",陣列);

    map.put("array",陣列);

    可以使用 @Param 註解替換map集合中預設的 arg 鍵名。

  • 其他型別

    比如int型別,引數佔位符名稱 叫什麼都可以。儘量做到見名知意

2,註解實現CRUD

使用註解開發會比配置檔案開發更加方便。如下就是使用註解進行開發

@Select(value = "select * from tb_user where id = #{id}")
public User select(int id);

注意:

  • 註解是用來替換對映配置檔案方式配置的,所以使用了註解,就不需要再對映配置檔案中書寫對應的 statement

Mybatis 針對 CURD 操作都提供了對應的註解,已經做到見名知意。如下:

  • 查詢 :@Select
  • 新增 :@Insert
  • 修改 :@Update
  • 刪除 :@Delete

注意:在官方文件中 入門 中有這樣的一段話:

所以,註解完成簡單功能,配置檔案完成複雜功能。

而我們之前寫的動態 SQL 就是複雜的功能,如果用註解使用的話,就需要使用到 Mybatis 提供的SQL構建器來完成,而對應的程式碼如下:

上述程式碼將java程式碼和SQL語句融到了一塊,使得程式碼的可讀性大幅度降低。