2022 Shang Silicon Valley SSM フレームワーク フォローアップ (3) MyBatis の基本 3

2022 Shang シリコンバレー SSM フレームワーク フォローアップ 3 MyBatis の基本 3

9. 動的SQL

Mybatisフレームワークの動的SQL技術は、特定の条件に従ってSQL文を動的に組み立てる機能であり、
SQL文の文字列を組み立てる際のペインポイント問題を解決することを目的としています。
例: 複数のクエリ条件を指定したクエリ 条件が設定されている場合は、SQL 中にそれらの条件が含まれている必要があります。デフォルト値の設定と指定に注意してくださいnull および " " (空の文字列)

新しいモジュールを作成します。ここでは具体的な手順は説明しません。
座標を構成するには前の章を参照してください。

グループ ID:com.atguigu.mybatis
名前:mybatis-dynamicSQL

関連ファイルの構成
設定関連ファイル
コア構成ファイル mybatis-config.xml を構成するときに設定を行う必要があることに注意してください
ハンプローディング

<!-- mapUnderscoreToCamelCase将下划线映射为驼峰 -->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 延迟加载由2个参数决定 lazyLoadingEnabled设置true
                                  aggressiveLazyLoading设置false
         -->
        <!-- 开启延迟加载(懒加载) -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--aggressiveLazyLoading 设置false按需加载 -->
        <!--aggressiveLazyLoading 设置true全部加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

pojoのエンティティクラスEmpを設定する

package com.atguigu.mybatis.pojo;

/**
 * @ClassName: Emp
 * @Description:
 * @Author: wty
 * @Date: 2023/1/7
 */

public class Emp {
    
    
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;

    public Emp() {
    
    
    }

    public Emp(Integer empId, String empName, Integer age, String gender) {
    
    
        this.empId = empId;
        this.empName = empName;
        this.age = age;
        this.gender = gender;
    }

    public Integer getEmpId() {
    
    
        return empId;
    }

    public void setEmpId(Integer empId) {
    
    
        this.empId = empId;
    }

    public String getEmpName() {
    
    
        return empName;
    }

    public void setEmpName(String empName) {
    
    
        this.empName = empName;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    public String getGender() {
    
    
        return gender;
    }

    public void setGender(String gender) {
    
    
        this.gender = gender;
    }

    @Override
    public String toString() {
    
    
        return "Emp{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

9.1if

ifタグはtest属性の式によって判定でき、式の結果がtrueの場合はタグの内容が実行され、そうでない場合はタグの内容は実行されません

DynamicSQLMapper.javaにメソッドを追加

 /**
     * @param
     * @return java.util.List<com.atguigu.mybatis.pojo.Emp>
     * @description //根据条件查询员工信息
     * @param: emp
     * @date 2023/1/7 12:03
     * @author wty
     **/
    List<Emp> getEmpByCondition(Emp emp);

DynamicSQLMapper.xmlにSQLを追加

    <!-- List<Emp> getEmpByCondition(Emp emp); -->
    <select id="getEmpByCondition" resultType="Emp">
        select *
        from t_emp
        where
        <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
        <if test="empName != null and empName != '' ">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </select>

テストクラス com.atguigu.mybatis.test.DynamicMapperTest を作成し、メソッドを追加します

    @Test
    public void getEmpByConditionTest() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        Emp emp = new Emp(1, "张三", 20, "男");

        List<Emp> list = mapper.getEmpByCondition(emp);

        list.forEach(System.out::println);

        sqlSession.close();
    }

検索結果
検索結果

9.2どこで

ここで、where の背後にある empName 条件が空に設定されている場合、テスト クラス クエリを使用するのは間違っています。
エラーを報告する
同様に、顔の鼻を押し続け、年齢と性別を空に設定すると、select * from t_emp の空のシェルが作成されます。これらの問題を解決する方法を見てみましょう。以下の
エラーを報告し続ける
方法

方法1:定数成立条件を追加する

DynamicSQLMapper.xmlに定数成立の条件を追加

    <!-- List<Emp> getEmpByCondition(Emp emp); -->
    <select id="getEmpByCondition" resultType="Emp">
        select *
        from t_emp
        where 1 = 1
        <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
        <if test="empName != null and empName != '' ">
            and emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </select>

常設事業所への加入条件
上記のフィールドがすべて空である状況でクエリを続け、結果がエラーを報告せず、クエリが正しいことを確認します。
検索結果

方法 2: where タグを使用する

DynamicSQLMapper.xml の SQL 句を次のように変更します。
whereタグを変更する

<!-- 动态sql拼接 方法二:用where标签 -->
    <!-- List<Emp> getEmpByCondition(Emp emp); -->
    <select id="getEmpByCondition" resultType="Emp">
        select *
        from t_emp
        <where>
            <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
            <if test="empName != null and empName != '' ">
                emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>
        </where>
    </select>

テスト クラス クエリを直接使用して
検索結果
結論を​​検証します。where
タグの if 条件が満たされない場合、where タグには機能がありません。つまり、where キーワードは追加されません。

次に、テストクラス DynamicMapperTest.java の条件を変更しましょう。

 @Test
    public void getEmpByConditionTest() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        Emp emp = new Emp(1, "", 20, "");

        List<Emp> list = mapper.getEmpByCondition(emp);

        list.forEach(System.out::println);

        sqlSession.close();
    }

割り当て条件を変更する
クエリ結果:
検索結果
検証済み 結論:
where タグの if 条件が満たされると、where タグは自動的に where キーワードを追加し、条件の先頭にある冗長な と を削除します。

Where と if は通常、組み合わせて使用​​されます。
a> where タグ内の if 条件が満たされない場合、where タグには機能がありません。つまり、where キーワードは追加されません。
b> where タグ内の if 条件が満たされない場合条件が満たされると、where タグは自動的に where キーワードを追加し、条件の先頭にある冗長な および を削除し
ます。 注: where タグは条件の末尾にある冗長な および を削除できません。

例:条件の後に と を入れても大丈夫でしょうか?

<!-- trim标签 -->
    <!-- List<Emp> getEmpByCondition(Emp emp); -->
    <select id="getEmpByCondition" resultType="Emp">
        select *
        from t_emp
        <where>
            <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
            <if test="empName != null and empName != '' ">
                emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                age = #{age} and
            </if>
            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>
        </where>
    </select>

入れてから
テストクラスを変更して結果を表示する

@Test
    public void getEmpByConditionTest() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        Emp emp = new Emp(1, "张三", 20, "");

        List<Emp> list = mapper.getEmpByCondition(emp);

        list.forEach(System.out::println);

        sqlSession.close();
    }

結果を表示: エラーが見つかりました。
結果を見る
この場合、次のトリム タグを使用して解決できます。

9.3トリム

トリムは、タグ内のコンテンツを削除または追加するために使用されます。
共通属性:
prefix: トリム タグのコンテンツの前にコンテンツを追加します。
prefixOverrides: トリム タグのコンテンツの前にあるコンテンツを削除します
。 suffix: トリム タグのコンテンツ後でコンテンツを追加する
suffixOverrides: トリム タグ内のコンテンツの後の一部のコンテンツを削除します

DynamicSQLMapper.xml を変更する
改訂

    <!-- trim标签 -->
    <!-- List<Emp> getEmpByCondition(Emp emp); -->
    <select id="getEmpByCondition" resultType="Emp">
        select *
        from t_emp
        <!-- trim的标签有4个
             prefix prefixOverrides suffix suffixOverrides
             prefix在内容前面加上指定内容
             prefixOverrides在内容前面去掉指定内容
             suffix在内容后面加上指定内容
             suffixOverrides在内容后面去掉指定内容
         -->
        <trim prefix="where" suffixOverrides="and">
            <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
            <if test="empName != null and empName != '' ">
                emp_name = #{empName} and
            </if>
            <if test="age != null and age != ''">
                age = #{age} and
            </if>
            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>
        </trim>
    </select>

テスト クラスを実行して結果を表示し
テスト結果を表示する
、テストします。条件が空の場合は、where
自動的に削除される場所
テストを自動的に削除することもできます。where 条件が空の場合は、入力およびテストのみを行ってください。
詰め物と

9.4選択、いつ、それ以外の場合

choose、when、 otherwise相当于if…、else if…、else

DynamicSQLMapper.javaにメソッドを追加

/**
     * @param
     * @return java.util.List<com.atguigu.mybatis.pojo.Emp>
     * @description //使用choose查询员工信息
     * @param: emp
     * @date 2023/1/7 13:43
     * @author wty
     **/
    List<Emp> getEmpByChoose(Emp emp);

DynamicSQLMapper.xml を変更する

 <!-- choose、when、 otherwise相当于if... 、else if.. 、else -->
    <!-- List<Emp> getEmpByChoose(Emp emp); -->
    <select id="getEmpByChoose" resultType="Emp">
        select *
        from t_emp
        <where>
            <choose>
                <!-- test表示当前标签中实体类的属性是否有效,如果有效,就拼接到sql中,无效就不拼接 -->
                <when test="empName != null and empName != ''">
                    emp_name = #{empName}
                </when>
                <when test="age != null and age != ''">
                    age = #{age}
                </when>
                <when test="gender != null and gender != ''">
                    gender = #{gender}
                </when>
                <otherwise>
                    1 = 1
                </otherwise>
            </choose>
        </where>
    </select>

テスト クラス DynamicMapperTest.java にメソッドを追加します。

@Test
    public void getEmpByChooseTest() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        Emp emp = new Emp(1, "", null, "");

        List<Emp> list = mapper.getEmpByChoose(emp);

        list.forEach(System.out::println);

        sqlSession.close();
    }

結果を確認します。choose
検索結果
、when、Others がすべて選択条件であることに注意してください。3 つの条件を組み合わせて使用​​すると、最初の条件のみが選択され、残りの条件は実行されないため、 と を記述する必要はありません状態。例:
複数の選択肢
複数の選択条件を確立できることがわかりますが、最初の選択条件が実行された後は、他の選択条件は実行されません。

9.5 フォーリーチ

一括追加や一括削除には、より重要なタグが使用されます。

9.51 バッチ追加

DynamicSQLMapper.javaにメソッドを追加

 /**
     * @param
     * @return int
     * @description //员工的批量添加
     * @param: emps
     * @date 2023/1/7 14:03
     * @author wty
     **/
    int insertMoreEmp(@Param("emps") List<Emp> emp);

DynamicSQLMapper.xml を変更する

<!-- int insertMoreEmp(@Param("emps") List<Emp> emp);  -->
    <insert id="insertMoreEmp" useGeneratedKeys="true" keyProperty="empId">
        insert into t_emp
        values
        <!--foreach标签
             collection属性:放入Mapper接口Param注解中定义的变量即可
             item 可以理解为一行数据,即一个对象
             separator 表示分隔符,每一次循环后以,分割,最后一次没有
        -->
        <foreach collection="emps" item="emp" separator=",">
            <!-- 这里用emp.empName是因为返回值类型是List,而emp才是每一行数据的实体对象 -->
            (null, #{emp.empName}, #{emp.age}, #{emp.gender}, null)
        </foreach>
    </insert>

テスト クラス DynamicMapperTest.java にメソッドを追加します。

 @Test
    public void insertMoreEmpTest() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        List<Emp> list = new ArrayList<>();
        list.add(new Emp(null, "周七", 29, "男"));
        list.add(new Emp(null, "朱八", 22, "男"));
        list.add(new Emp(null, "李九", 23, "女"));

        int i = mapper.insertMoreEmp(list);

        System.out.println("插入:" + i + "条数据");

        sqlSession.close();
    }

結果を挿入
データを挿入する
結果を挿入

9.52 一括削除
一括削除方法1

DynamicSQLMapper.javaにメソッドを追加

    /**
     * @param
     * @return int
     * @description //批量删除
     * @param: empIds
     * @date 2023/1/7 14:39
     * @author wty
     **/
    int deleteMoreEmp(@Param("empIds") Integer[] empIds);

DynamicSQLMapper.xml を変更する

    <!-- int deleteMoreEmp(@Param("empIds") Integer empIds); -->
    <delete id="deleteMoreEmp">
        delete
        from t_emp
        where emp_id in
        (
        <foreach collection="empIds" item="empId" separator=",">
            #{empId}
        </foreach>
        )
    </delete>

テスト クラス DynamicMapperTest.java にメソッドを追加します。

  @Test
    public void deleteMoreEmp() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);


        Integer empIds[] = {
    
    5, 6, 7};

        int i = mapper.deleteMoreEmp(empIds);

        System.out.println("删除:" + i + "条数据");

        sqlSession.close();
    }

削除結果の表示:
結果を削除
3 つのアイテムが削除されたことを確認します。
3 件が削除されました

一括削除方法2

一括削除の別の方法では、DynamicSQLMapper.xmlを変更します。

    <!-- int deleteMoreEmp(@Param("empIds") Integer empIds); -->
    <delete id="deleteMoreEmp">
        delete
        from t_emp
        where emp_id in
        <!-- open以什么开始 close以什么结束 -->
        <foreach collection="empIds" item="empId" separator="," open="(" close=")">
            #{empId}
        </foreach>
    </delete>

まず一括挿入メソッドを再実行します。
データを挿入する

もう一度削除して、この方法で正常に削除できるかどうかを確認します。
3件のデータを削除
結果を削除
結果を削除

一括削除方法3

DynamicSQLMapper.xml を変更する

<!-- int deleteMoreEmp(@Param("empIds") Integer empIds); -->
    <delete id="deleteMoreEmp">
        delete
        from t_emp
        where
        <foreach collection="empIds" item="empId" separator="or">
            emp_id = #{empId}
        </foreach>
    </delete>

テストクラス削除メソッドを実行する前に、一括挿入メソッドを実行してください。
入れる

テストクラスDynamicMapperTest.javaを実行します。

 @Test
    public void deleteMoreEmp() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);


        Integer empIds[] = {
    
    11, 12, 13};

        int i = mapper.deleteMoreEmp(empIds);

        System.out.println("删除:" + i + "条数据");

        sqlSession.close();
    }

実行結果の
結果1
正常に削除されました
概要

foreach タグの属性コレクション
: ループする配列またはコレクションを設定します。
item: 配列またはコレクション内の各データを表す文字列を使用します
。 separator: 各ループのデータ間の区切り文字を設定します
。 open: ループのすべての内容終了で開始
: ループのすべてが終了するもの

9.6 SQL フラグメント

SQL フラグメント。パブリック SQL フラグメントを記録し、それが使用される include タグを介してインポートできます。

DynamicSQLMapper.javaにメソッドを追加

    /**
     * @param
     * @return java.util.List<com.atguigu.mybatis.pojo.Emp>
     * @description //查询所有用户
     * @date 2023/1/7 15:10
     * @author wty
     **/
    List<Emp> getAllEmp();

DynamicSQLMapper.xml を変更する

<sql id="empColumns">
        emp_id,emp_name,age,gender,dept_id
    </sql>

    <!-- List<Emp> getAllEmp(); -->
    <select id="getAllEmp" resultType="Emp">
        select
        <!-- 使用的时候用 include  refid属性放sql中的id -->
        <include refid="empColumns"></include>
        from t_emp
    </select>

テスト クラス DynamicMapperTest.java にメソッドを追加します。

 @Test
    public void getAllEmpTest() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);

        List<Emp> list = mapper.getAllEmp();

        list.forEach(System.out::println);

        sqlSession.close();
    }

クエリ結果
検索結果
クエリ時に SQL のフィールドが呼び出されることがわかります。

10. MyBatis キャッシュ

10.1 MyBatis レベル 1 キャッシュ

MyBatis の 1 次キャッシュはデフォルトで有効になっており、プロジェクトの作成後に直接使用できます。
新しいモジュールを作成する

グループ ID:com.atguigu.mybatis
名前:mybatis-cache

構成情報とパラメーターについては前の章を参照してください。ここでは詳細には説明しません。作成後のプロジェクトは次のようになります。
モジュール
CacheMapper.java にメソッドを追加します。

    /**
     * @param
     * @return com.atguigu.mybatis.pojo.Emp
     * @description //根据员工Id查询员工信息
     * @param: empId
     * @date 2023/1/7 16:44
     * @author wty
     **/
    Emp getEmpById(@Param("empId") Integer empId);

CacheMapper.xml に新しいステートメントを追加

<sql id="empColumns">
        emp_id
        ,emp_name,age,gender,dept_id
    </sql>

    <!-- Emp getEmpById(@Param("empId") Integer empId); -->
    <select id="getEmpById" resultType="Emp">
        select
        <include refid="empColumns"></include>
        from t_emp
        where emp_id = #{empId}
    </select>

テストクラス CacheMapperTest.java にメソッド test を追加

  @Test
    public void getEmpByIdTest() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);

        Emp emp1 = mapper.getEmpById(4);
        System.out.println(emp1);

        Emp emp2 = mapper.getEmpById(4);
        System.out.println(emp2);

        sqlSession.close();
    }

クエリ結果は次のとおりです。
検索結果

1 次キャッシュは SqlSession レベルにあります。同じ SqlSession を通じてクエリされたデータはキャッシュされます。次回同じデータがクエリされたとき、そのデータはキャッシュから直接取得され、データベースから再アクセスされることはありません。

第 1 レベルのキャッシュは SqlSession レベルにあるため、これが当てはまるかどうかを確認してみましょう。
CacheMapperTest.javaを変更する

@Test
    public void getEmpByIdTest() {
    
    
        SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);

        Emp emp1 = mapper1.getEmpById(4);
        System.out.println(emp1);

        Emp emp2 = mapper1.getEmpById(4);
        System.out.println(emp2);

        sqlSession1.close();

        SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();

        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);

        Emp emp3 = mapper2.getEmpById(4);

        System.out.println(emp3);

        sqlSession2.close();
    }

結果の表示
結果
同じ SqlSession が 2 回目にクエリを実行するときにキャッシュが使用され、別の SqlSession が同じ SQL をクエリするときに再クエリが行われることがわかります。これにより、第 1 レベルのキャッシュが SqlSession レベルにあることが確認されます。 。

一次キャッシュが無効になる 4 つの状況:

  1. 異なる SqlSessions は異なる 1 次キャッシュに対応します。
  2. 同じ SqlSession ですが、クエリ条件が異なります。
  3. 追加、削除、変更の操作はすべて、同じ SqlSession の 2 つのクエリ中に実行されます。
  4. キャッシュは、同じ SqlSession 内の 2 つのクエリ間で手動でクリアされました。


ケース (3) については、 CacheMapper.java の Add メソッドを理解するための例を示します。

 /**
     * @param
     * @return int
     * @description //添加员工信息
     * @param: emp
     * @date 2023/1/7 17:08
     * @author wty
     **/
    int insertEmp(Emp emp);

CacheMapper.xml に新しいステートメントを追加

 <!-- int insertEmp(Emp emp); -->
    <insert id="insertEmp">
        insert into t_emp
        values (null, #{empName}, #{age}, #{gender}, null)
    </insert>

テスト クラス CacheMapperTest.java の getEmpByIdTest メソッド テストを変更します。

 @Test
    public void getEmpByIdTest() {
    
    
        SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);

        Emp emp1 = mapper1.getEmpById(4);
        System.out.println(emp1);

        // 如果执行了任意的增删改,则会清空缓存,重新查询
        Emp emp = new Emp(null, "周七", 29, "男");
        int i = mapper1.insertEmp(emp);

        System.out.println("插入了" + i + "条");

        Emp emp2 = mapper1.getEmpById(4);
        System.out.println(emp2);

        sqlSession1.close();
    }

2 つのクエリの間に新しい操作を実行する
テストクラス
クエリの結果
結果
追加、削除、変更後、キャッシュがクリアされ、データベースがクエリされることがわかります。

状況を理解するために例を見てみましょう (3)
CacheMapperTest.java の getEmpByIdTest メソッドを変更します

sqlSession1.clearCache(); // キャッシュをクリアします

@Test
    public void getEmpByIdTest() {
    
    
        SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);

        Emp emp1 = mapper1.getEmpById(4);
        System.out.println(emp1);

        sqlSession1.clearCache();

        Emp emp2 = mapper1.getEmpById(4);
        System.out.println(emp2);

        sqlSession1.close();
    }

結果を見る
クエリデータベース

10.2 MyBatis の 2 次キャッシュ

2 次キャッシュは SqlSessionFactory レベルにあり、同じ SqlSessionFactory を通じて作成された SqlSession クエリの結果がキャッシュされ、後で同じクエリ ステートメントが再度実行されると、結果がキャッシュから取得されます。
二次キャッシュを有効にする条件:
< a >。コア構成ファイルで、グローバル構成属性cacheEnabled="true"を設定します。この属性はデフォルトでtrueに設定されているため、設定する必要はありません。

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

< b >.マッパーマッピングファイルにラベルを設定します。

<cache/>

< c >. 2 次キャッシュは、SqlSession が閉じられるか送信された後も有効である必要があります。

sqlSession1.close();

< d >. クエリされたデータによって変換されたエンティティ クラス タイプは、シリアル化されたインターフェイスを実装する必要があります。

public class Emp implements Serializable {
    
    }

上記の知識ポイントを学習した後、2次キャッシュを見てみましょう。
コア構成ファイルにステートメントを追加します (省略可能)
コア構成ファイル

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

CacheMapper.xml に新しいステートメントを追加します。
キャッシュを開くステートメント
マッパー設定ファイル
を追加します。 テスト クラス CacheMapperTest.java にメソッド テストを追加します。

    @Test
    public void testCache() throws IOException {
    
    
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println("emp1 =" + emp1);

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println("emp2 =" + emp2);

    }

クエリ結果
データベース
クエリ結果を見ると、データベースに 2 回クエリを実行しており、2 次キャッシュがまだ有効になっていないことがわかります。sqlSession を閉じていないことが判明したので、閉じてみましょう。

@Test
    public void testCache() throws IOException {
    
    
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println("emp1 =" + emp1);

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println("emp2 =" + emp2);

        sqlSession1.close();
        sqlSession2.close();
    }

テストクラスを実行してエラーを見つけます。
エラーを報告する

org.apache.ibatis.cache.CacheException: オブジェクトのシリアル化中にエラーが発生しました。原因: java.io.NotSerializableException: com.atguigu.mybatis.pojo.Emp

カスタム クラス Emp はシリアル化を実装していないため、Emp を実装します。
連載

シリアル化されたバージョン番号を迅速に生成する
連載

package com.atguigu.mybatis.pojo;

import java.io.Serializable;

/**
 * @ClassName: Emp
 * @Description:
 * @Author: wty
 * @Date: 2023/1/7
 */

public class Emp implements Serializable {
    
    
    private static final long serialVersionUID = -936807110083368555L;
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;

    public Emp() {
    
    
    }

    public Emp(Integer empId, String empName, Integer age, String gender) {
    
    
        this.empId = empId;
        this.empName = empName;
        this.age = age;
        this.gender = gender;
    }

    public Integer getEmpId() {
    
    
        return empId;
    }

    public void setEmpId(Integer empId) {
    
    
        this.empId = empId;
    }

    public String getEmpName() {
    
    
        return empName;
    }

    public void setEmpName(String empName) {
    
    
        this.empName = empName;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    public String getGender() {
    
    
        return gender;
    }

    public void setGender(String gender) {
    
    
        this.gender = gender;
    }

    @Override
    public String toString() {
    
    
        return "Emp{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

ここでテストクラスのメソッドを変更します

 @Test
    public void testCache() throws IOException {
    
    
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println("emp1 =" + emp1);
        sqlSession1.close();

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println("emp2 =" + emp2);

        sqlSession2.close();
    }

実行結果の表示
演算結果

2 次キャッシュの無効化: 2 つのクエリ間で追加、削除、変更を行うと、1 次キャッシュと 2 次キャッシュが同時に無効になります。

このようにして、MyBatis の 2 次キャッシュが実現されます。
2 次キャッシュを無効にしたい場合は、 2 つのクエリの途中で追加、削除、変更を行うことで
CacheMapperTest.java を変更しようとします。

 @Test
    public void testCache() throws IOException {
    
    
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println("emp1 =" + emp1);

        // 二级缓存失效
        Emp emp = new Emp(null, "朱八", 26, "男");

        int i = mapper1.insertEmp(emp);
        System.out.println("插入了" + i + "条");
        sqlSession1.close();

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println("emp2 =" + emp2);

        sqlSession2.close();
    }

クエリ結果
検索結果
この 2 番目のクエリは引き続きデータベースにクエリを実行し、追加、削除、および変更を示します。二次キャッシュはクリアされ、データベースを再度クエリする必要があります。

10.3 2次キャッシュの関連構成

マッパー設定ファイルに追加されたキャッシュ タグは、いくつかの属性を設定できます。
①エビクション属性: キャッシュのリサイクル戦略。デフォルトは LRU です。
LRU (最も最近使用されていない) – 最も長い間使用されていないオブジェクトを削除します。
FIFO (先入れ先出し) - 先入れ先出し: オブジェクトはキャッシュに入った順序で削除されます。
SOFT - ソフト参照: ガベージ コレクターの状態とソフト参照ルールに基づいてオブジェクトを削除します。
WEAK - 弱い参照: ガベージ コレクターの状態と弱い参照ルールに基づいて、より積極的にオブジェクトを削除します。
②flushInterval 属性: リフレッシュ間隔 (ミリ秒単位)。
デフォルトは設定されていません。つまり、更新間隔はありません。キャッシュはステートメントが呼び出されたときにのみ更新されます。 ③size 属性: 参照数、正の整数。
キャッシュに最大で保存できるオブジェクトの数を表します、大きすぎるとメモリオーバーフローが起こりやすくなります
④readOnly 属性: 読み取り専用、true/false
true: 読み取り専用キャッシュ; すべての呼び出し元にキャッシュ オブジェクトの同じインスタンスを返します。したがって、これらのオブジェクトは変更できません。これにより、パフォーマンスが大幅に向上します。
false: 読み取り/書き込みキャッシュ; キャッシュされたオブジェクトのコピーが (シリアル化経由で) 返されます。これは遅くなりますが安全なので、デフォルトは false です。

10.4 MyBatis キャッシュ クエリの順序

広い範囲から狭い範囲へ (sqlSessionFactory レベル 2 キャッシュ → SqlSession レベル 1 キャッシュ)

2 次キャッシュには、他のプログラムがチェックアウトしたデータが直接使用できる可能性があるため、最初に 2 次キャッシュにクエリを実行します。
2 次キャッシュがヒットしない場合は、1 次キャッシュをクエリします
。1 次キャッシュもヒットしない場合は、
クエリ データベース SqlSession が閉じられた後、1 次キャッシュ内のデータが 2 次キャッシュに書き込まれます。 -レベルキャッシュ

10.5 サードパーティキャッシュ EHCache の統合

10.5.1 依存関係の追加

pom.xml に依存関係を追加する

<!-- Mybatis EHCache整合包 -->
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.2.1</version>
        </dependency>
        <!-- slf4j日志门面的一个具体实现 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

簡単に伝えます
簡単に伝えます

10.5.2 各jarパッケージの機能
jarパッケージ名 効果
mybatis-ehcache MybatisとEHCacheの統合パッケージ
ehcache EHCache コア パッケージ
slf4j-api SLF4Jログポータルパッケージ
ログバッククラシック SLF4J ファサード インターフェイスの具体的な実装をサポートします。
10.5.3 EHCache設定ファイルehcache.xmlの作成

設定ファイルを作成する

<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <!-- 磁盘保存路径 -->
    <diskStore path="F:\javawebwork\ehcache"/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>
10.5.4 L2キャッシュのタイプを設定する

CacheMapper.xmlで設定
L2キャッシュ

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
10.5.5 ログバックログの追加

SLF4J が存在する場合、単純なログとしての log4j は無効になるため、ログを出力するには SLF4J logback の特定の実装を使用する必要があります。ログバック構成ファイル logback.xml を作成する

パッケージ名を追加

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- 指定日志输出的位置 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 日志输出的格式 -->
            <!-- 按照顺序分别是: 时间、日志级别、线程名称、打印日志的类、日志主体内容、换行
            -->
            <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger]
                [%msg]%n
            </pattern>
        </encoder>
    </appender>
    <!-- 设置全局日志级别。日志级别按顺序分别是: DEBUG、INFO、WARN、ERROR -->
    <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
    <root level="DEBUG">
        <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
        <appender-ref ref="STDOUT"/>
    </root>
    <!-- 根据特殊需求指定局部日志级别 -->
    <logger name="com.atguigu.mybatis.mapper" level="DEBUG"/>
</configuration>

CacheMapperTest.javaを変更する

 @Test
    public void testCache() throws IOException {
    
    
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
        Emp emp1 = mapper1.getEmpById(1);
        System.out.println("emp1 =" + emp1);

        sqlSession1.close();

        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
        CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
        Emp emp2 = mapper2.getEmpById(1);
        System.out.println("emp2 =" + emp2);

        sqlSession2.close();
    }

クエリ結果の
検索結果
キャッシュの場所
キャッシュの場所

10.5.6 EHCache設定ファイルの説明
属性名 それは必要ですか 効果
maxElementsInMemory はい メモリにキャッシュされる要素の最大数
maxElementsOnDisk はい ディスク上にキャッシュされる要素の最大数 (0 が無限を意味する場合)
永遠 はい キャッシュされた要素が期限切れにならないかどうかを設定します。trueの場合、キャッシュされたデータは常に有効ですが、falseの場合、timeToIdleSecondsとtimeToLiveSecondsに従って判断する必要があります
オーバーフローからディスクへ はい メモリ キャッシュがオーバーフローした場合に、期限切れの要素をディスクにキャッシュするかどうかを設定します
アイドルまでの時間秒 いいえ EhCache にキャッシュされたデータが timeToIdleSeconds 属性の値を超える前後に 2 回アクセスされると、データは削除されます。デフォルト値は 0 で、アイドル時間が無限であることを意味します。
生存時間秒 いいえ キャッシュ要素の有効期間。デフォルトは 0 です。つまり、要素の生存時間は無限です。
ディスクスプールバッファサイズMB いいえ DiskStore (ディスク キャッシュ) のバッファ サイズ。デフォルトは 30MB です。各キャッシュには独自のバッファーが必要です
ディスク永続的 いいえ VM の再起動時にディスクがデータを EhCache に保存できるようにするかどうか。デフォルトは false です。
ディスクExpiryThreadIntervalSeconds いいえ ディスク キャッシュ クリーニング スレッドの実行間隔。デフォルトは 120 秒です。120 秒ごとに、対応するスレッドが EhCache 内のデータをクリーンアップします。
メモリストアエビクションポリシー いいえ メモリ キャッシュが最大値に達し、新しい要素が追加された場合、キャッシュ内の要素を削除するポリシー。デフォルトは LRU (最も最近使用されていない)、オプションの LFU (最も頻繁に使用されていない)、および FIFO (先入れ先出し) です。

11. MyBatisのリバースエンジニアリング

フォワード エンジニアリング: 最初に Java エンティティ クラスを作成します。フレームワークは、エンティティ クラスに基づいてデータベース テーブルを生成します。Hibernate はフォワード エンジニアリングをサポートします。
リバース エンジニアリング: 最初にデータベース テーブルを作成します。フレームワークは、データベース テーブルに基づいて次のリソースを逆生成します。
Java エンティティ クラス
マッパー インターフェイス
マッパー マッピング ファイル
注: リバース エンジニアリングは 1 つのテーブルに対してのみ実行でき、サポートされていません。複数のテーブル

11.1 リバースエンジニアリングを作成する手順

新しいモジュールを作成する

グループ ID:com.atguigu.mybatis
名前:mybatis-mbg

モジュールを作成する

(1) 依存関係とプラグインを追加する

pom.xml に依存関係を追加します。
ここでは mysql のバージョンに注意し、独自のインストールと一致するように構成します。

<!-- 依赖MyBatis核心包 -->
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!-- junit测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- log4j日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.20</version>
        </dependency>
    </dependencies>
    <!-- 控制Maven在构建过程中相关配置 -->
    <build>
        <!-- 构建过程中用到的插件 -->
        <plugins>
            <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.0</version>
                <!-- 插件的依赖 -->
                <dependencies>
                    <!-- 逆向工程的核心依赖 -->
                    <dependency>
                        <groupId>org.mybatis.generator</groupId>
                        <artifactId>mybatis-generator-core</artifactId>
                        <version>1.3.2</version>
                    </dependency>
                    <!-- MySQL驱动 -->
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>5.1.20</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

梱包方法の追加
梱包方法を設定する

<packaging>jar</packaging>
(2) MyBatisのコア設定ファイルを作成する

コア構成ファイルを作成する

(3) リバースエンジニアリング用設定ファイルの作成

ファイル名は次のようにする必要があります:generatorConfig.xml

リバースエンジニアリング
ここで作成したのは MyBatis3Simple: 新鮮でシンプルなバージョンです

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--
    targetRuntime: 执行生成的逆向工程的版本
    MyBatis3Simple: 生成基本的CRUD(清新简洁版)
    MyBatis3: 生成带条件的CRUD(奢华尊享版)
    -->
    <context id="DB2Tables" targetRuntime="MyBatis3Simple">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm?"
                        userId="root"
                        password="hsp">
        </jdbcConnection>
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="com.atguigu.mybatis.pojo"
                            targetProject=".\src\main\java">
            <!-- enableSubPackages 设置成true表示可以使用子包 -->
            <property name="enableSubPackages" value="true"/>
            <!-- 把数据库字段的前后空格去掉生成实体类的属性  -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"
                         targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_emp" domainObjectName="Emp"/>
        <table tableName="t_dept" domainObjectName="Dept"/>
    </context>
</generatorConfiguration>
(4) MBGプラグインの生成ターゲットを実行

さらに依存関係を設定した後
プラグイン
、プラグインをダブルクリックして
ダブルクリック
、最終的にプラグインを正常に作成します。
正常に作成されました

(5) 効果

正常に作成されました
Mapper インターフェースの 5 つのメソッドを見てください。

package com.atguigu.mybatis.mapper;

import com.atguigu.mybatis.pojo.Emp;
import java.util.List;

public interface EmpMapper {
    
    
    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table t_emp
     *
     * @mbggenerated Sun Jan 08 13:28:24 CST 2023
     */
    int deleteByPrimaryKey(Integer empId);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table t_emp
     *
     * @mbggenerated Sun Jan 08 13:28:24 CST 2023
     */
    int insert(Emp record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table t_emp
     *
     * @mbggenerated Sun Jan 08 13:28:24 CST 2023
     */
    Emp selectByPrimaryKey(Integer empId);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table t_emp
     *
     * @mbggenerated Sun Jan 08 13:28:24 CST 2023
     */
    List<Emp> selectAll();

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table t_emp
     *
     * @mbggenerated Sun Jan 08 13:28:24 CST 2023
     */
    int updateByPrimaryKey(Emp record);
}

MyBatis3: Luxury Premium Edition を作成してみましょ
うgeneratorConfig.xml を変更します

    <context id="DB2Tables" targetRuntime="MyBatis3">

プレミアムエディションの作成
リバース エンジニアリングによって作成されたパッケージとクラスを削除します。
消去
プラグインを再実行します
プラグインを再実行する
。 結果を実行し、表示します。
演算結果

11.2 QBCクエリ

MBGTest.java テスト クラスを作成する
テストクラスを作成する
MBGTest.java にメソッドを追加する

主キーに基づいてクエリをテストする
 @Test
    public void testMBG() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        Emp emp = mapper.selectByPrimaryKey(1);

        System.out.println(emp);

        sqlSession.close();
    }

MBGTest.javaの実行結果
ここに画像の説明を挿入
EmpにtoString()メソッドを追加
toString() メソッド
実行結果
の結果

MBGTest.java にメソッドを追加します——

無条件クエリをテストする
@Test
    public void testMBG1() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        List<Emp> list = mapper.selectByExample(null);

        list.forEach(System.out::println);

        sqlSession.close();
    }

条件が null の場合、すべてをクエリするのと同じです。
検索結果

条件によるクエリのテスト

ここでは、EmpExample オブジェクトを作成する必要があります。
方法
MBGTest.java にメソッドを追加します。
条件に基づいてクエリを実行します。 Zhang San という名前の従業員

 @Test
    public void testMBG2() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 根据条件查询:一个叫张三的员工
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三");

        List<Emp> list = mapper.selectByExample(empExample);

        list.forEach(System.out::println);

        sqlSession.close();
    }

検索結果
検索結果

複数条件クエリ
複数とクエリ

従業員が Zhang San であることに基づいて、クエリ条件: 年齢が 20 歳以上という条件を追加すると、後でスプライシングを続行するだけで済みます。
お問い合わせ

 @Test
    public void testMBG2() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 根据条件查询:一个叫张三的员工
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);

        List<Emp> list = mapper.selectByExample(empExample);

        list.forEach(System.out::println);

        sqlSession.close();
    }

検索結果
多条件

複数またはクエリ

では、それが混在している場合、またはたとえば、年齢が 20 歳以上、または性別が女性である Zhang San という名前の従業員をクエリする必要がある場合はどうなるでしょうか。 MBGTest.java クラスのメソッドを変更します

修正方法

@Test
    public void testMBG2() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 根据条件查询:一个叫张三的员工
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
        empExample.or().andGenderEqualTo("女");

        List<Emp> list = mapper.selectByExample(empExample);

        list.forEach(System.out::println);

        sqlSession.close();
    }

検索結果
検索結果

選択的修飾

Emp.java がパラメータ構造体
パラメータ化された構造
を追加 MBGTest.java にメソッドを追加

    @Test
    public void testMBG4() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 根据选择性修改:
        Emp emp = new Emp(14, "小丽", null, "女");
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);

        int i = mapper.updateByPrimaryKeySelective(emp);

        System.out.println("更新了" + i + "条数据");

        sqlSession.close();
    }

これは選択的な変更であるため、null の値は変更を置き換えません。
null は変更されていません

共通の変更

MBGTest.javaにメソッドを追加

@Test
    public void testMBG3() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 根据主键修改:
        Emp emp = new Emp(14, "小美", 26, "女");
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);

        int i = mapper.updateByPrimaryKey(emp);

        System.out.println("更新了" + i + "条数据");

        sqlSession.close();
    }

結果を変更する
結果を変更する
結果を変更する

12ページネーションプラグイン

制限インデックス、pageSize
pageSize: 各ページに表示される項目の数
pageNum: 現在のページのページ番号 Index
: 現在のページの開始インデックス、index=(pageNum-1)*pageSize
count: レコードの合計数
totalPage : 総ページ数
totalPage = count / pageSize;
if(count % pageSize != 0){ totalPage += 1; } pageSize=4、pageNum=1、index=0 制限 0,4 pageSize=4、pageNum=3 、index=8 制限 8,4 pageSize= 4、pageNum=6、index=20 制限 20,4ナビゲーション ページネーション:最初のページ 前のページ 2 3 4 5 6 次のページ 最後のページ






12.1 ページネーション プラグインを使用する手順

(1) 依存関係を追加する

pom.xml に依存関係を追加する

<!-- 分页插件 -->
                    <dependency>
                        <groupId>com.github.pagehelper</groupId>
                        <artifactId>pagehelper</artifactId>
                        <version>5.2.0</version>
                    </dependency>

依存関係を追加する

(2) ページネーションプラグインの設定

MyBatis のコア設定ファイルでプラグインを設定します。
mybatis-config.xml で設定します。
インターセプターの構成

    <plugins>
        <!--设置分页插件-->
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>

ここで完全なクラス名を見つけるのが難しい場合は、IDEA に付属の完全なクラス名検索を使用できます。ショートカット キー Ctrl+Shift+a を押し、検索バーでクラスをクリックし、PageInterceptor を検索して完全なクラス名をコピーし
ます
検索
。新しいテスト クラス PageTest.java
完全なクラス名をコピーする
作成します。 ページング関数をテストします。
テストクラス
sqlyog に移動して、テーブル t_emp を切り詰め、データを再挿入します。 30

12.2 ページネーションプラグインの使用

< a > PageHelper.startPage(int pageNum, int pageSize) を使用して、クエリ関数の前にページング関数を開始します。

pageNum: 現在のページのページ番号
pageSize: 各ページに表示される項目の数

テストクラス PagTest.java にメソッドを追加

 @Test
    public void testPage() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 分页查询
        // 开启分页功能
        PageHelper.startPage(1, 4);

        List<Emp> list = mapper.selectByExample(null);
        list.forEach(System.out::println);

        sqlSession.close();
    }

クエリ結果:
検索結果
クエリ結果を分析:
ページ値を出力

    @Test
    public void testPage() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 分页查询
        // list前开启分页功能
        Page<Object> page = PageHelper.startPage(1, 4);

        List<Emp> list = mapper.selectByExample(null);
        list.forEach(System.out::println);
        System.out.println(page);

        sqlSession.close();
    }

出力結果:
出力結果
Page は ArrayList から継承されていることに注意してください
ここに画像の説明を挿入
。ここで結論を導き出すことができ、インターフェイスの戻り値 Page をカスタマイズしてクエリ結果を取得できます。
カスタムインターフェイスの戻り値

< b > クエリを実行してリスト コレクションを取得した後、PageInfo pageInfo = new PageInfo<>(List list, int navigatePages) を使用してページ関連データを取得します。

list: ページネーション後のデータ
navigatePages: ナビゲーション ページネーションのページ番号

PageTest.java のメソッドを変更する

 /**
     * PageInfo{
     * pageNum=4, pageSize=4, size=4, 当前是第4页,此页中有4条数据
     * startRow=13, endRow=16,  当前页的数据是从第13行数据到16条数据
     * total=30, pages=8, 所有页一共30条数据,一共8页。符合30/4 = 7……2 则总页数是7 + 1 = 8
     * list=Page{count=true, pageNum=4, pageSize=4, startRow=12, endRow=16, total=30, pages=8, reasonable=false, pageSizeZero=false}[Emp{empId=13, empName='a', age=null, gender='null', deptId=null}, Emp{empId=14, empName='a', age=null, gender='null', deptId=null}, Emp{empId=15, empName='a', age=null, gender='null', deptId=null}, Emp{empId=16, empName='a', age=null, gender='null', deptId=null}],
     * prePage=3, nextPage=5, 当前页是第4页,所以上一页的页码是3,后一页的页码是5
     * isFirstPage=false, isLastPage=false, 是否是第一页,是否是最后一夜
     * hasPreviousPage=true, hasNextPage=true, 是否有上一页,是否有下一页
     * navigatePages=4, 当前页
     * navigateFirstPage=2,导航分页的初始页
     * navigateLastPage=5, 导航分页的最终页
     * navigatepageNums=[2, 3, 4, 5]}导航分页的页码
     */
    @Test
    public void testPage1() {
    
    
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        // 分页查询
        Page<Object> page = PageHelper.startPage(4, 4);

        List<Emp> list = mapper.selectByExample(null);

        // list后开启分页功能
        // navigatePages:导航分页的个数,比如设置4,导航分页就是2,3,4,5
        // 比如设置5,导航分页是2,3,4,5,6
        PageInfo<Emp> pageInfo = new PageInfo<>(list, 5);

        list.forEach(System.out::println);
        System.out.println(pageInfo);

        sqlSession.close();
    }

クエリ結果:
検索結果
< c > ページング関連データ

PageInfo{ pageNum=8、pageSize=4、size=2、startRow=29、endRow=30、total=30、pages=8、list=Page{ count=true、pageNum=8、pageSize=4、startRow=28、 endRow=32、total=30、pages=8、reasonable=false、pageSizeZero=false}、prePage=7、nextPage=0、isFirstPage=false、isLastPage=true、hasPreviousPage=true、hasNextPage=false、navigatePages=5、navigateFirstPage4 , navigateLastPage8, navigatepageNums=[4, 5, 6, 7, 8] } pageNum: 現在のページのページ番号pageSize: 各ページに表示されるアイテムの数 size : 現在のページに表示される実際のアイテムの合計数:レコードの総数Pages: 総ページ数prePage: 前のページのページ番号nextPage: 次のページのページ番号isFirstPage/isLastPage: 最初のページか最後のページかhasPreviousPage/hasNextPage: あるかどうか前のページ/次のページnavigatePages: ナビゲーション ページのページ番号

















navigatepageNums: ナビゲーション ページのページ番号、[1,2,3,4,5]

おすすめ

転載: blog.csdn.net/sinat_38316216/article/details/128588502#comments_27517006