中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MyBatis 動態SQL和緩存機制實例詳解

發布時間:2020-09-19 05:05:06 來源:腳本之家 閱讀:204 作者:LWJJJ 欄目:編程語言

有的時候需要根據要查詢的參數動態的拼接SQL語句

常用標簽:

- if:字符判斷

- choose【when...otherwise】:分支選擇

- trim【where,set】:字符串截取,其中where標簽封裝查詢條件,set標簽封裝修改條件

- foreach:

if案例

1)在EmployeeMapper接口文件添加一個方法

public Student getStudent(Student student);

2)如果要寫下列的SQL語句,只要是不為空,就作為查詢條件,如下所示,這樣寫實際上是有問題的,所以我們要寫成動態SQL語句:

<select id="getEmployeeByConditionIf" resultType="com.neuedu.entity.Employee">
    select *from tbl_employee where id = #{id} and user_name = #{userName} and email = #{email} and gender = #{gender}
</select>

3)用if標簽改寫為動態SQL,如下所示:

 test:判斷表達式(OGNL):OGNL參照PPT或者官方文檔。

 test從參數中取值進行判斷

 遇見特殊符號,應該去寫轉義字符:如<>分別為&lt,&gt

<select id="getStudent" resultType="com.neuedu.mybatis.entity.Student">
   SELECT *
   FROM student
    where
      <if test="id != null">
         id=#{id}
      </if>
      <if test="name !=null and name!=''">
         and name=#{name}
      </if>
      <if test="password !=null and password !=''">
         and password=#{password}
      </if>
      <if test="email !=null and email !=''">
         and email=#{email}
      </if>
</select>

4)測試代碼

@Test
public void TestgetStudent(){
   StudentMapper bean = ioc.getBean(StudentMapper.class);
   Student student = new Student(4,"jack", "111", "jack@qq.com");
   System.out.println(student);
   Student student2 = bean.getStudent(student);
   System.out.println(student2);
}
 #測試結果沒問題,

但是仔細來說,上面的sql語句是有問題的,當我們不給動態sql語句傳遞id值的時候,sql語句的拼裝就會有問題!【name前有一個and】

- where 標簽

解決辦法

1.給where后面加上1=1,以后的條件都可以使用and xxx了

2.可以使用 where 標簽來將所有的查詢條件包括在內

   mybatis就會將where標簽中拼裝的sql,多出來的and或者or去掉!

<select id="getStudent" resultType="com.neuedu.mybatis.entity.Student">
   SELECT *
   FROM student
   <where>
      <if test="id != null">
         id=#{id}
      </if>
      <if test="name !=null and name!=''">
         and name=#{name}
      </if>
      <if test="password !=null and password !=''">
         and password=#{password}
      </if>
      <if test="email !=null and email !=''">
         and email=#{email}
      </if>
   </where>
</select>

3.需要注意:where標簽只會去掉第一個多出來的and或者or

   也就是說使用where標簽有時候還是不能解決問題的,那怎么辦呢?我們這里可以使用trim標簽!

- trim標簽:可以自定義字符串的截取規則

    后面多出的and或者or where標簽不能夠解決
    prefix="":前綴:trim標簽體是整個字符串拼串后的結果。
    prefix給拼串后的整個字符串加一個前綴
    prefixOverrides="":前綴覆蓋:去掉整個字符串前面多余的字符
    suffix="":后綴
    suffix給拼串后的整個字符串加一個后綴
    suffixOverrides="":后綴覆蓋:去掉整個字符串后面多余的字符

<select id="getStudent" resultType="com.neuedu.mybatis.entity.Student">
   SELECT *
   FROM student
   <trim prefix="where" prefixOverrides="and">
      <if test="id != null">
         id=#{id}
      </if>
      <if test="name !=null and name!=''">
         and name=#{name}
      </if>
      <if test="password !=null and password !=''">
         and password=#{password}
      </if>
      <if test="email !=null and email !=''">
         and email=#{email}
      </if>
   </trim>
</select>

- choose標簽:分支選擇,類似于Java中的帶了break的switch...case

相當于確保了第一個case 符合之后,就跳出

案例演示:

1.在EmployeeMapper接口中添加一個方法

public List<Student> getStus(Student student);

2.sql映射文件

<select id="getStus" resultType="com.neuedu.mybatis.entity.Student">
   select * from student
   <where>
      <choose>
         <when test="id !=null">
            id = #{id}
         </when>
         <when test="name !=null and name!=''">
            name = #{name}
         </when>
         <when test="password !=null and password!=''">
            password = #{password}
         </when>
         <when test="email !=null and email!=''">
            email = #{email}
         </when>
         <otherwise>
            1 = 1
         </otherwise>
      </choose>
   </where>
</select>

- set標簽:字符串截取,可以寫在trim里面

set元素會動態前置set關鍵字,同時也會消除無關的逗號

1)在EmployeeMapper中添加一個更新的方法

public void updateStu(Student student);

 2)在sql映射文件中,填寫相應的sql語句,如下所示【set標簽可以將字段后面的逗號去掉】

<update id="updateStu">
   update student
   <set>
      <if test="name !=null and name!=''">
         name=#{name},
      </if>
      <if test="password !=null and password !=''">
         password=#{password},
      </if>
      <if test="email !=null and email !=''">
         email=#{email}
      </if>
   </set>
      where id = #{id}
</update>

 3)測試類代碼為

@Test
public void TestUpdateStu(){
   StudentMapper bean = ioc.getBean(StudentMapper.class);
   bean.updateStu(new Student(4, "jackk", null, null));
}

 將set標簽用trim標簽代替

<update id="updateStu">
   update student
   <trim prefix="set" suffixOverrides=",">
      <if test="name !=null and name!=''">
         name=#{name},
      </if>
      <if test="password !=null and password !=''">
         password=#{password},
      </if>
      <if test="email !=null and email !=''">
         email=#{email}
      </if>
   </trim>
      where id = #{id}
</update>

- foreach:遍歷元素

動態SQL的另一個常用的操作是需要對一個集合進行遍歷,通常在構建in條件語句的時候!

foreach元素允許指定一個集合,聲明集合項和索引變量,并可以指定開閉匹配的字符串以及在迭代之間放置分隔符。

案例演示:

1.在EmployeeMapper接口中加入一個方法

public List<Student> getStuByIdForEach(@Param("ids")List<Integer> ids);

2.在MyBatis的sql映射文件中寫相應的代碼

<select id="getStuByIdForEach" resultType="com.neuedu.mybatis.entity.Student">
   select * from student
   where id
   in
   <foreach collection="ids" item="id" open="(" close=")" separator=",">
      #{id}
   </foreach>
</select>

3.測試類代碼

@Test
public void getStuByIdForEach(){
   StudentMapper bean = ioc.getBean(StudentMapper.class);
   List<Integer> list = Arrays.asList(16,17,18,19);
   List<Student> stuByIdForEachlist = bean.getStuByIdForEach(list);
   for (Student student : stuByIdForEachlist) {
      System.out.println(student);
   }
}

 foreach標簽還可以用于批量保存數據,

1.在EmployeeMapper接口類中添加批量插入的方法

public void insertStus(@Param("stus")List<Student> student);

 2.在EmployeeMapper.xml的sql映射文件中添加響應的語句

foreach 中用 collection,collection中是從Mapper接口傳來的參數,separator是去掉中間符號

<insert id="insertStus">
   insert into student (name,password,email) values
   <foreach collection="stus" item="stu" separator=",">
      (#{stu.name},#{stu.password},#{stu.email})
   </foreach>
</insert>

 3.測試代碼

@Test
public void TestInsertStus(){
   StudentMapper bean = ioc.getBean(StudentMapper.class);
   List<Student> list = new ArrayList<Student>();
   list.add(new Student("123","123", "123"));
   list.add(new Student("123","123", "123"));
   list.add(new Student("123","123", "123"));
   bean.insertStus(list);
}

MyBatis-緩存機制  

MyBatis 包含一個非常強大的查詢緩存特性,它可以非常方便地配置和定制。緩存可以極大的提升查詢效率。

只在MyBatis中,在SSM整合文件中沒用,因為SqlSession 定義在 bean.xml中,無法重新定義SqlSession 

MyBatis系統中默認定義了兩級緩存。

一級緩存和二級緩存

     一級緩存:(本地緩存):SqlSession級別的緩存,一級緩存是一直開啟的,沒法關閉。方法之間不共用!

            與數據庫同一次會話期間查詢到的數據放在本地緩存中。

            以后如果需要獲取相同的數據,直接從緩存中拿,沒必要再去查詢數據庫; 

    二級緩存(全局緩存): 

        –1、默認情況下,只有一級緩存(SqlSession級別的緩存,也稱為本地緩存)開啟。

        –2、二級緩存需要手動開啟和配置,他是基于namespace級別的緩存。

        –3、為了提高擴展性。MyBatis定義了緩存接口Cache。我們可以通過實現Cache接口來自定義二級緩存。 

一級緩存:

案例:測試一級緩存【默認是開啟的】

將返回一條select查詢語句,

將返回true,說明emp與emp2是緩存,而不是重新查找

@Test
public void TestFirstCache(){
   SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
   session = sqlSessionFactory.openSession();
   mapper = session.getMapper(EmployeeMapper.class);
   Employee emp = mapper.getEmpInfoById(4);
   System.out.println(emp);
   Employee emp2 = mapper.getEmpInfoById(4);
   System.out.println(emp2);
   System.out.println(emp == emp2);
   session.commit();
   session.close();
}

 一級緩存失效的情況【4種】(沒有使用到當前一級緩存的情況,效果就是,還需要再向數據庫發出查詢)

1.sqlSession不同,重新定義SqlSession

將返回兩條select語句

將返回false,說明emp2不是emp的緩存

@Test
public void TestFirstCache(){
   SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
   session = sqlSessionFactory.openSession();
   mapper = session.getMapper(EmployeeMapper.class);
   Employee emp = mapper.getEmpInfoById(4);
   System.out.println(emp);
   SqlSession session2 = sqlSessionFactory.openSession();
   EmployeeMapper mapper2 = session2.getMapper(EmployeeMapper.class);
   Employee emp2 = mapper2.getEmpInfoById(4);
   System.out.println(emp2);
   System.out.println(emp == emp2);
   session.commit();
   session.close();
}

2.SqlSession相同,但是查詢條件不一樣[當前緩存中還沒有這個數據]

就是相當于根據不同條件再次查找

@Test
public void TestFirstCache(){
   SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
   session = sqlSessionFactory.openSession();
   mapper = session.getMapper(EmployeeMapper.class);
   Employee emp = mapper.getEmpInfoById(4);
   System.out.println(emp);
   Employee emp2 = mapper.getEmpInfoById(16);
   System.out.println(emp2); 
   System.out.println(emp == emp2);
   session.commit();
   session.close();
}

3.SqlSession相同,但是兩次查詢之間執行了增刪改操作【這次增刪改可能對當前數據有影響】

因為默認自動刷新了緩存

@Test
public void TestFirstCache(){
   SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
   session = sqlSessionFactory.openSession();
   mapper = session.getMapper(EmployeeMapper.class);
   Employee emp = mapper.getEmpInfoById(4);
   System.out.println(emp);
   mapper.deleteEmp(16);
   Employee emp2 = mapper.getEmpInfoById(4);
   System.out.println(emp2);
   System.out.println(emp == emp2);
   session.commit();
   session.close();
}

4.SqlSession相同,手動清除了一級緩存[緩存清空]

手動清除了緩存,所以得重新查找

@Test
public void TestFirstCache(){
   SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
   session = sqlSessionFactory.openSession();
   mapper = session.getMapper(EmployeeMapper.class);
   Employee emp = mapper.getEmpInfoById(4);
   System.out.println(emp);
   session.clearCache();
   Employee emp2 = mapper.getEmpInfoById(4);
   System.out.println(emp2);
   System.out.println(emp == emp2);
   session.commit();
   session.close();
}

二級緩存:

【全局緩存】:基于namespace級別的緩存:一個namespace對應一個二級緩存。

【一級緩存的范圍還是太小了,每次SqlSession一關閉,一級緩存中的數據就消失】

所以從這個角度講:能跨sqlSession的緩存為二級緩存! 

工作機制:

1.一個會話,查詢一條數據,這個數據就會被放在當前會話的一級緩存中。

2.如果會話關閉,一級緩存中的數據會被保存到二級緩存中;新的會話查詢信息,就可以參照二級緩存中。

不同namespace查出的數據會放在自己對應的緩存中(map)  

效果:數據會從二級緩存中獲取

          查出的數據都會被默認先放在一級緩存中。

          只有會話提交或者關閉之后,一級緩存中的數據才會轉移到二級緩存中。

          需要注意的是:在哪個Mapper.xml文件中開啟了<cache>緩存標簽,哪個Mapper中就開啟了二級緩存。 

案例:

1)開啟全局二級緩存配置:

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

2)去mapper.xml中配置使用二級緩存

<cache eviction="FIFO" size="100" readOnly="false"/>

其中屬性:

eviction=“FIFO”:緩存回收策略:

LRU –最近最少使用的:移除最長時間不被使用的對象。

FIFO –先進先出:按對象進入緩存的順序來移除它們。

SOFT –軟引用:移除基于垃圾回收器狀態和軟引用規則的對象。

WEAK –弱引用:更積極地移除基于垃圾收集器狀態和弱引用規則的對象。

默認的是LRU。

flushInterval:緩存刷新間隔 ?緩存多長時間清空一次,默認不清空,設置一個毫秒值。

size:引用數目,正整數,默認1024

      代表緩存最多可以存儲多少個對象,太大容易導致內存溢出

readOnly:是否只讀,true/false

      true:只讀緩存;mybatis認為所有從緩存中獲取數據的操作都是只讀操作,不會修改數據。             

       mybatis為了加快獲取速度,直接就會將數據在緩存中的引用交給用戶。不安全,速度快。      

      false:非只讀:mybatis覺得獲取的數據可能會被修改。

              mybatis會利用序列化&反序列化的技術克隆一份。安全,速度慢。
type:指定自定義緩存的全類名 實現cache接口即可! 

3)我們的POJO需要實現序列化接口[implements Serializable]

4)必須先關閉之前的sqlsession對象

測試:

可以看到只發送了一次SQL語句,第二次查詢時從二級緩存中拿到的數據,并沒有發送新的sql語句。

@Test
public void TestFirstCache(){
   SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
   session = sqlSessionFactory.openSession();
   mapper = session.getMapper(EmployeeMapper.class);
   Employee emp = mapper.getEmpInfoById(4);
   System.out.println(emp);
   session.close();
   SqlSession session2 = sqlSessionFactory.openSession();
   EmployeeMapper mapper2 = session2.getMapper(EmployeeMapper.class);
   Employee emp2 = mapper2.getEmpInfoById(4);
   System.out.println(emp2);
   session2.close();
}

需要注意的是:只有一級緩存中關閉的情況下,二級緩存才會被使用。

需要注意的是:在哪個Mapper.xml文件中開啟了<cache>緩存標簽,哪個Mapper中就開啟了二級緩存。

和緩存有關的設置/屬性:

1)cacheEnabled="true": false:關閉緩存(二級緩存關閉)【一級緩存一直可用】

2)每個select標簽都有useCache="true";

                  false:不使用緩存(一級緩存依然使用,二級緩存不使用)

3)每個增刪改標簽都有一個flushCache="true":增刪改執行完成后就會清楚緩存【一級二級緩存都會被清空】

           查詢標簽:flushCache = "false"

           如果flushCache = true;每次查詢之前都會清空緩存,緩存是沒有被使用!

總結

以上所述是小編給大家介紹的MyBatis 動態SQL和緩存機制實例詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

休宁县| 黑龙江省| 文化| 九龙城区| 汶川县| 邻水| 土默特左旗| 万山特区| 布拖县| 应城市| 闽侯县| 天长市| 双鸭山市| 策勒县| 华池县| 云和县| 大兴区| 崇义县| 偃师市| 黄石市| 苍梧县| 泸西县| 镇安县| 浦城县| 江孜县| 石楼县| 陕西省| 湛江市| 仪征市| 伊春市| 高青县| 左云县| 江北区| 商水县| 根河市| 金阳县| 郑州市| 禄劝| 南平市| 日土县| 虹口区|