【01-02】Mybatis的配置文件與基于XML的使用

1、引入日志

  • 在這里我們引入SLF4J的日志門面,使用logback的具體日志實現;
  • 引入相關依賴:
		<!--日志的依賴--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency>
  • 添加logback的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true"><!--追加器:日志以哪種方式輸出,name:自定義追加器的名稱,class:追加器實現類的全限定名(不同實現類輸出的方式不同,下面是以控制臺方式輸出)--><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><!--設置日志輸出格式--><pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} ---> %msg%n</pattern><charset>UTF-8</charset></encoder></appender><!--設置全局日志級別--><root level="INFO"><!--設置當前日志級別輸出到哪個追加器上--><appender-ref ref="CONSOLE" /></root><!--設置某個包或者某個類的局部日志級別--><logger name="org.example.mapper" level="debug" /><logger name="org.apache.ibatis.transaction" level="debug" /></configuration>
  • 測試結果:
    測試結果

2、全局配置文件

在mybatis的項目中,有一個mybatis-config.xml的配置文件,這個配置文件是mybatis的全局配置文件,用來進行相關的全局配置。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><properties resource="db.properties"></properties><settings> </settings><typeAliases> </typeAliases><environments></environments><mappers></mappers>
</configuration>

1、propertis(屬性)

  <!--配置外部屬性資源文件,通過 ${} 來進行引用--><properties resource="db.properties"><!--也可以在內部自定義屬性--><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/trs-db?useUnicode=true&amp;characterEncoding=utf8&amp;tinyInt1isBit=false&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowMultiQueries=true&amp;zeroDateTimeBehavior=convertToNull"/><property name="username" value="root"/><property name="password" value="rootxq"/></properties>

2、setting(設置)

 	<settings><!--	設置默認執行器:SIMPLE(普通執行器)、REUSE(可重復使用執行器,會重用預處理語句)、BATCH(批量執行器,不僅重用預處理語句,而且可以批量更新)--><setting name="defaultExecutorType" value="SIMPLE"/><!--    開啟駝峰命名自動映射--><setting name="mapUnderscoreToCamelCase" value="true"/><!--	在懶加載下,哪些方法會觸發立即加載,默認:equals、toString、hashCode--><!--<setting name="lazyLoadTriggerMethods" value=""/>--><!--    開啟全局的延遲加載:true 所有的嵌套查詢都是懶加載,false 所有嵌套查詢都會被立即加載--><setting name="lazyLoadingEnabled" value="true"/><!--    設置加載的數據是否按需加載--><setting name="aggressiveLazyLoading" value="false"/><!--    開啟二級緩存--><setting name="cacheEnabled" value="true"/></settings>

3、typeAliases(類型別名)

	<!--設置類的別名,可以降低冗余的全局限定名的書寫--><typeAliases><!--1、可以設置包下所有類的別名:會使用類名作為別名(是忽略大小寫的)--><!--<package name="org.example.pojo"/>--><!--2、可以自定義設置某個類的別名--><typeAlias type="org.example.pojo.Emp" alias="emp"/><typeAlias type="org.example.pojo.Dept" alias="dept"/></typeAliases>

4、environments(環境配置)

 <!--配置數據源連接信息--><!--可以配置多個數據源(environment),例如:測試環境、生產環境各配置一個數據源,default:設置默認使用哪個數據源--><environments default="development"><environment id="development"><!--事務管理器:type 設置事務管理類型(1)JDBC:使用JDBC的事務管理方式(2)MANAGED:不運用事務 --><transactionManager type="JDBC"/><!--數據源:type 設置數據源類型(1)UNPOOLED:不使用連接池(2)POOLED:使用Mybatis的連接池--><dataSource type="POOLED"><property name="driver" value="${db.driver}"/><property name="url" value="${db.url}"/><property name="username" value="${db.username}"/><property name="password" value="${db.password}"/></dataSource></environment></environments>

5、mappers(映射器)

 <!--映射器:有4種配置方式--><mappers><!--1、設置MapperXML的方式,適用于根據statementId進行操作--><mapper resource="mapper/DeptMapper.xml"/><mapper resource="mapper/EmpMapper.xml"/><!--2、設置Mapper接口的方式,適用于接口綁定的方式--><!--<mapper class="org.example.mapper.EmpMapper"/>--><!--<mapper class="org.example.mapper.DeptMapper"/>--><!--3、使用磁盤的絕對路徑(基本不用)--><!--4、根據包路徑設置該包下的所有Mapper接口,適用于接口綁定和注解的方式(應用最多的方式)--><!--<package name="org.example.mapper"/>--></mappers>

3、SQL映射文件

  • MyBatis 的真正強大之處在于它的語句映射。由于它的異常強大,映射器的XML 文件就顯得相對簡單。MyBatis 致力于減少使用成本,讓用戶能更專注于 SQL 代碼。
  • 映射文件中極其重要的幾大標簽:
    • select:映射查詢語句
    • insert:映射插入語句
    • update:映射更新語句
    • delete:映射刪除語句
    • sql:定義可重用的sql語句;
    • cache:設置當前命名空間下的緩存配置;
    • cache-ref:引用其他命名空間下的緩存配置;
    • resultMap:描述如何從數據庫的結果集中加載對象;
  • 每個頂級元素標簽中可以添加很多個屬性,下面介紹相關屬性的作用
    • (1)id:設置當前命名空間中各個映射標簽的唯一標識符(同一個命名空間中的id不允許重復,對應mapper接口中的方法名稱);
    • (2)paramType:設置SQL的參數類型(mybatis會根據接口方法的參數自動讀取參數的類型,所以不強制要求設置);
    • (3)statementType:設置當前的Statement類型(默認為PREPARED):
      • STATEMENT:代表JDBC的Statement,不支持參數預解析;
      • PREPARED:代表JDBC的PreparedStatement,支持參數預解析;
      • CALLABLE:代表JDBC的CallableStatement,支持存儲過程調用;
    • (4)useGeneratedKeys:啟用主鍵生成策略,設置是否獲取插入后的自增長主鍵的值,默認是false,設置為true時,才會獲取自增長主鍵的值;
    • (5)keyProperty:設置將獲取到的自增長主鍵值映射到實體類的哪個屬性上;
    • (6)keyColumn:如果存在組合主鍵的情況,指定獲取哪個主鍵的字段名;
  • 例如:
	<insert id="insertEmp" useGeneratedKeys="true" keyProperty="eId" ><!--如果數據庫不支持列值自增長的話,可以使用下面的方法:selectKey:可以在增刪改操作之前或者之后執行相關屬性:order:設置執行時機(BEFORE表示之前,AFTER表示之后)keyProperty:設置將當前查詢結果放到哪個POJO的屬性上resultType:設置返回值的類型--><selectKey order="BEFORE" keyProperty="eId" resultType="int">SELECT MAX(eid)+1 FROM emp</selectKey>INSERT INTO emp (eid,e_name,e_mail,salary,did) values (#{eId},#{eName},#{eMail},#{salary},#{did})</insert>

4、基于XML的詳細使用

  • POJO實體類
    public class Emp{private Integer eId;private String eName;private String eMail;private Double salary;private Integer did;
    }public class Dept{private Integer did;private String dName;
    }
    

1、參數的獲取方式

  • #{} ==> sql = “SELECT * FROM emp WHERE eid = ?”
    • a、會經過JDBC中的PreparedStatement對象進行預編譯處理,會根據不同的數據類型來編譯成對應數據庫所對應的數據類型;
      例如:String id = “100010”,#{id} ==> sql = "SELECT * FROM emp WHERE eid = ‘100010’;
      例如:Integer id = 100010,#{id} ==> sql = "SELECT * FROM emp WHERE eid = 100010;
    • b、能夠有效的防止SQL注入;
  • ${} ==> sql = “SELECT * FROM emp WHERE eid =” + id;
    • a、不會進行預編譯,會直接將獲取到的的參數直接拼接在sql中;
    • b、存在SQL注入的風險;
    • 特殊用法:
      (1)調試時可以臨時使用,這樣可以直接將攜帶參數的完整sql語句打印在控制臺;
      (2)需要動態拼接的時候,可以使用${},但是要在保證數據的安全性的前提下操作;

2、參數的傳遞方式

  • 單個參數的傳遞:

    • (1)參數類型是普通數據類型時:使用#{參數名稱}來獲取參數,即:#{id};

        public interface EmpMapper {Emp selectEmpById(Integer id);
      }
      
        <select id="selectEmpById"  resultMap="empResultSet">select * from emp where eid = #{id}</select>
      
    • (2)參數類型是javaBean時:使用#{屬性名}來獲取參數,emp.eId ==> #{eId}, emp.eName ==> #{eName}

        public interface EmpMapper {Emp selectEmpInfo(Emp emp);}
      
       <select id="selectEmpInfo" resultType="org.example.pojo.Emp">select * from emp where eid = #{eId} and e_name = #{eName}</select>
      
    • (3)參數類型是數組或者list集合時:mybatis會自動封裝成map

      • 數組:{key:array,value:array},獲取方式:#{arg0.下標} 或者 #{array.下標}
      • 集合:{key:list,value:list},獲取方式:#{arg0.下標} 或者 #{list.下標}
      • 如果方法中使用了@Param()注解來指定別名,則獲取方式為:#{別名.下標}
        public interface EmpMapper {List<Emp> selectEmpByNames(List<String> names);}
      
      <select id="selectEmpByNames" resultType="org.example.pojo.Emp">select * from emp where e_name in (#{arg0.0}, #{list.1}, #{arg0.2})
      </select>
      
    • (4)參數類型是map集合時:與javaBean的參數傳遞情況一樣;
       public interface EmpMapper {Emp selectEmpByMap(Map<String,Object> paramMap);
      }Map<String, Object> paramMap = new HashMap<>();paramMap .put("id",1);paramMap .put("ename","lq");
      
       <select id="selectEmpByMap" resultType="org.example.pojo.Emp">select * from emp where eid = #{id} and e_name = #{ename}</select>
      
  • 多個參數的傳遞

    • mybatis會對參數按順序進行封裝,將參數封裝成map集合;
       public interface EmpMapper {Emp selectEmpByIdAndName( Integer id, String ename);
      }
      
      • id ==> {key : arg0,value : id的值} 或者 {key : param1,value : id的值}
      • ename ==> {key : arg1,value : ename的值} 或者 {key : param2,value : ename的值}
      • 可以使用#{key}來獲取對應的值,
      <select id="selectEmpByIdAndName" resultType="org.example.pojo.Emp">select * from emp where eid = #{arg0} and e_name = #{param2}
      </select>
      
    • 可以給每個參數設置別名,使其具有參數意義:
      • 語法:使用注解:@Param("參數別名")
      public interface EmpMapper {Emp selectEmpByIdAndName( @Param("id")Integer id, @Param("ename")String ename);
      }
      
      • id ==> #{id} 或者 #{param1}
      • ename ==> #{ename} 或者 #{param2}
      • 可以使用#{參數別名}來獲取對應的值
       <select id="selectEmpByIdAndName" resultType="org.example.pojo.Emp">select * from emp where eid = #{id} and e_name = #{ename}</select>
      
    • 如果是參數類型既有普通數據類型又有javaBean時:
      public interface EmpMapper {Emp selectEmpInfoByDid(Integer did,@Param("emp") Emp emp);
      }
      
      • id ==> #{param1} 或者 @Param(“did”)
      • emp.eName ==> #{param2.eName} 或者 emp.eName
      • 注意:多個參數時,獲取JavaBean中的屬性時,使用#{參數別名.屬性名};
       <select id="selectEmpInfoByDid" resultType="org.example.pojo.Emp">select * from emp where did = #{param1} and e_name = #{emp.eName}</select>
      

3、處理返回結果

  • 返回類型設置:
    • 如果返回單行數據,可是使用Java基礎數據類型或者POJO或者Map接收;
    • 如果返回多行數據,可以使用List< POJO>或者List< Map >接收,需要在resultType中指定List中的泛型類型;
  • 當返回結果是集合的時候,返回值的類型依然寫的是集合中具體的類型
     <select id="selectAllEmp" resultType="org.example.pojo.Emp">select * from emp</select>
    
  • 在查詢時可以設置返回值的類型為map,當mybatis查詢完成之后會把列的名稱作為key,列的值作為value,轉換到map中;
    <select id="selectEmpByEmpReturnMap" resultType="map">select * from emp where empno = #{empno}
    </select>
    

4、自定義結果集

  • 如果數據庫表的字段與POJO的屬性名不一致時,除了可使用'AS'來設置別名,還可以使用resultMap來設置自定義結果集,注意:resultType與resultMap二者只能使用其一。
  • 相關屬性:
    • id:唯一標識,需要與select標簽中的resultMap進行關聯;
    • type:需要映射的Pojo類型;
    • autoMapping:是否自動映射,默認為false,只要字段名與屬性名遵循映射規則就可以自動映射;
    • extends:如果同一命名空間內,如果有多個resultMap有重復的映射,可以聲明父resultMap,將公共的映射提取出來,可以減少子resultMap的映射冗余;
     <resultMap id="empResultSet" type="org.example.pojo.Emp"><!--<id>:用來指定主鍵字段的映射關系<result>:用來指定普通字段的映射關系column:需要映射的數據庫表中字段的名稱property:需要映射的POJO中的屬性名稱--><id column="eid" property="eId"/><result column="e_name" property="eName"/><result column="e_mail" property="eMail"/><result column="salary" property="salary"/><result column="did" property="did"/></resultMap><select id="selectEmp" resultMap="empResultSet">select * from emp where did = #{dept_id}</select>
    

5、高級結果映射

1、聯合查詢

public class EmpDeptDto extends Emp{private Dept dept;public Dept getDept() {return dept;}public void setDept(Dept dept) {this.dept = dept;}@Overridepublic String toString() {return super.toString() + "EmpDeptDto{" +"dept=" + dept +'}';}
}

1、多對一映射

  • 查詢所有員工的信息以及對應的部門(多員工同屬一個部門)
<resultMap id="empAndDeptMap" extends="empResultSet" type="org.example.pojo.EmpDeptDto"><!--普通方式:對象屬性名.屬性--><!--<result property="dept.dName" column="d_name"/>--><!--<result property="dept.did" column="did"/>--><!--association方式:會強行使我們的結果映射為多對一property:指定的“一”javaType:“一“的類型(自定義映射的時候才需要指定,與resultType二者使用其一)resultMap:調用已經存在的映射關系(重用resultMap)columnPrefix: 如果出現兩張表的字段有重復時,則需要使用as來起別名,可以給字段加上前綴,在映射的時候,可以使用columnPrefix自動將前綴去掉,這樣就能映射成功--><association property="dept" columnPrefix="dept_" javaType="org.example.pojo.Dept" resultMap="org.example.mapper.DeptMapper.baseDeptMap"><!--<id property="did" column="did"/>--><!--<result property="dName" column="d_name"/>--></association></resultMap><select id="selectEmpAndDept" resultMap="empAndDeptMap">SELECTe.*,d.did AS dept_did,d.d_name AS dept_d_nameFROMemp AS eLEFT JOIN dept AS d ON e.did = d.did</select>

2、一對多映射

  • 查詢部門信息以及所屬的員工信息(一個部門包含多個員工)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="org.example.mapper.DeptMapper"><resultMap id="baseDeptMap" type="org.example.pojo.Dept"><id column="did" property="did"/><result column="d_name" property="dName"/></resultMap><!--一對多映射關系property:指定的“多”ofType:“多”的類型(自定義映射的時候才需要指定,與resultType二者使用其一)resultMap:調用已經存在的映射關系(重用resultMap)無論是association還是collection,都需要查詢主鍵值--><resultMap id="deptAndEmpMap" extends="baseDeptMap" type="org.example.pojo.DeptEmpDto"><collection property="emps" ofType="org.example.pojo.Emp" resultMap="org.example.mapper.EmpMapper.empResultSet"><!--也可以自定義映射關系--><!--<id column="eid" property="eId"/>--><!--<result column="e_name" property="eName"/>--><!--<result column="e_mail" property="eMail"/>--><!--<result column="salary" property="salary"/>--><!--<result column="did" property="did"/>--></collection></resultMap><select id="getDeptAndEmp" resultMap="deptAndEmpMap">SELECTd.*,e.*FROM dept d LEFT JOIN emp eON d.did = e.did</select>
</mapper>

2、嵌套查詢

<!--嵌套查詢:分步查詢select:查詢關聯對象的sql語句column:需要傳遞的參數值的字段fetchType:懶加載(延遲查詢):嵌套查詢的對象用到的時候才回去查詢數據--><resultMap id="queryDeptAndEmpMap" type="org.example.pojo.DeptEmpDto" extends="baseDeptMap"><collection property="emps" fetchType="lazy" select="org.example.mapper.EmpMapper.selectEmp" column="did"/></resultMap><select id="queryDeptAndEmp" resultMap="queryDeptAndEmpMap">select * from dept</select>

3、延遲查詢

  • 當我們在進行表關聯的時候,有可能在查詢結果的時候不需要關聯對象的屬性值,那么此時可以通過延遲加載來實現功能。在全局配置文件中添加如下屬性:
	<!‐‐ 開啟延遲加載,所有分步查詢都是懶加載 (默認是立即加載)‐‐><setting name="lazyLoadingEnabled" value="true"/><!‐‐當開啟式, 使用pojo中任意屬性都會加載延遲查詢 ,默認是false<setting name="aggressiveLazyLoading" value="false"/>‐‐><!‐‐設置對象的哪些方法調用會加載延遲查詢 默認:equals,clone,hashCode,toString‐‐><setting name="lazyLoadTriggerMethods" value=""/>
  • 如果設置了全局加載,但是希望在某一個sql語句查詢的時候不使用延時策略,可以添加fetchType下屬性;
 <association property="dept" column="dept_id" fetchType="eager" resultMap="org.example.mapper.DeptMapper.baseDeptMap"></association>

6、動態SQL

動態 SQL 是 MyBatis 的強大特性之一。如果你使用過 JDBC 或其它類似的框架,你應該能理解根據不同條件拼接 SQL 語句有多痛苦,例如拼接時要確保不能忘記添加必要的空格,還要注意去掉列表最后一個列名的逗號。利用動態 SQL,可以徹底擺脫這種痛苦。

如果出現SQL語句中因特殊字符報錯的話,可以使用轉義字符或者<![CDATA[]]>來解決

1、動態SQL之if

  • 語法:< if test="條件表達式 可以是OGNL表達式">< /if>
  • 作用:完成簡單的條件判斷,加載動態條件
  • 問題:如果無法確定第一個條件是否成立,導致無法確定是否拼接 and或者or 的拼接
    • (1)可以設置 1=1 避免報錯
    • (2)可以使用< where>標簽,它會自動拼接或者刪除and或者or
    • (3)可以使用< trim>標簽
    	 <select id="queryEmps" resultType="org.example.pojo.Emp">select * from emp where 1=1<if test="salary != null and salary != ''">AND salary <![CDATA[<=]]> #{salary}</if><if test="eName != null and salary != ''">AND e_name = #{eName}</if><if test="eId != null and salary != ''">AND eid = #{eId}</if>	       </select>
    

2、動態SQL之where

  • 語法:< where>< /where>
  • 作用:如果存在條件則自動拼接where關鍵字,也可以動態的刪除條件語句中的and或者or
     	<select id="queryEmps" resultType="org.example.pojo.Emp">select * from emp <where><if test="salary != null and salary != ''">AND salary <![CDATA[<=]]> #{salary}</if><if test="eName != null and salary != ''">AND e_name = #{eName}</if><if test="eId != null and salary != ''">AND eid = #{eId}</if></where></select>
    

3、動態SQL之trim

  • 語法:< trim prefix="" prefixOverrides="" suffix="" suffixOverrides="">< /trim>
  • 作用:它的功能比較靈活、廣泛,可以在條件判斷完的SQL語句前后添加或者去掉指定的字符
  • 相關屬性:
    • prefix:前綴,需要添加的前綴
    • prefixOverrides:需要去掉的前綴,例如:and|or
    • suffix:后綴,需要添加的后綴
    • suffixOverrides:需要去掉的后綴,例如:,
 	<select id="queryEmps" resultType="org.example.pojo.Emp">select * from emp <trim prefix="where" prefixOverrides="and|or" suffix="" suffixOverrides=""><if test="salary != null and salary != ''">AND salary <![CDATA[<=]]> #{salary}</if><if test="eName != null and salary != ''">AND e_name = #{eName}</if><if test="eId != null and salary != ''">AND eid = #{eId}</if></trim></select>

4、動態SQL之choose、when、otherwise

  • 作用:它有著類似于if、elseif、else的作用。
    	<select id="queryEmps2" resultMap="empResultSet">select * from emp<where><choose><when test="eName == 'lv'">eid = 1</when><when test="eName == 'zlq'">eid = 2</when><otherwise>eid = 3</otherwise></choose></where></select>
    

5、動態SQL之set

  • 作用:主要用于解決修改操作中SET關鍵字以及SQL語句中可能多出的逗號問題
    	<update id="updateEmp">update emp<set><if test="eName != null and eName != ''">e_name = #{eName},</if><if test="eMail != null and eMail != ''">e_mail = #{eMail},</if><if test="salary != null and salary != ''">salary = #{salary},</if><if test="did != null and did != ''">did = #{did},</if></set>where eid = #{eId}</update>
    

6、動態SQL之foreach

  • 作用:循環遍歷集合或者數組
  • 相關屬性:
    • collection:指定需要遍歷的集合名稱
    • item:每次遍歷的集合元素
    • index:遍歷時的下標
    • separator:分隔符
    • open:循環開始時添加的字符
    • close:循環結束時添加的字符
    	<select id="queryEmpByNames" resultMap="empResultSet">select * from empwhere e_name in<foreach collection="names" item="name" index="i" separator="," open="(" close=")">#{name}</foreach></select>
    

7、動態SQL之sql片段

  • 作用:提取重復冗余的sql語句,使其可以被共用
  • 相關屬性:
    • id:唯一標識,使用< include refid=“sql片段的Id” />標簽來引用
     	<sql id="querySQL">select * from emp</sql><select id="selectEmpByMap" resultType="org.example.pojo.Emp"><include refid="querySQL"/>where eid = #{id} and e_name = #{ename}</select>
    

8、常用的OGNL表達式

  • (1)e1 or e2:邏輯或
  • (2)e1 and e2:邏輯與
  • (3)e1 != e2 或者 e1 neq e2:判斷兩個對象是否不相等
  • (4)e1 == e2 或者 e1 eq e2:判斷兩個對象是否相等
  • (5)e1 > e2 或者 e1 gt e2:判斷e1是否大于e2
  • (6)e1 >= e2 或者 e1 gte e2:判斷e1是否大于等于e2
  • (7)e1 < e2 或者 e1 lt e2:判斷e1是否小于e2
  • (8)e1 <= e2 或者 e1 lte e2:判斷e1是否小于等于e2
  • (9)e1 instanceof e2:判斷e1是否是e2的實例
  • (10)e1.method(e2):調用e1對象的method方法,并將e2作為參數傳遞給method方
  • (11)e1 in e2:判斷e1是否在e2中
  • (12)e1 not in e2:判斷e1是否不在e2中(13)e1 like e2:判斷e1是否和e2匹配
  • (13)e1 not like e2:判斷e1是否和e2不匹配
  • (14)e1 between e2 and e3:判斷e1是否在e2和e3之間
  • (15)e1 not between e2 and e3:判斷e1是否不在e2和e3之間
  • (16)e1 is null:判斷e1是否為null
  • (17)e1 is not null:判斷e1是否不為null
  • (18)!e1:邏輯非
  • (19)e1+e2,e1-e2,e1*e2,e1/e2:加減乘除

7、緩存

  • MyBatis 內置了一個強大的事務性查詢緩存機制,它可以非常方便地配置和定制。
  • 在進行配置的時候還會分為一級緩存和二級緩存:
    • 一級緩存:線程級別的緩存,是本地緩存,sqlSession級別的緩存;
    • 二級緩存:全局范圍的緩存,不僅局限于當前會話;

1、一級緩存

  • 特性:
    • 1、默認開啟,也可以關閉一級緩存,localCacheScope=STATENENT
    • 2、作用域默認是基于sqlSession的,就是一次數據庫操作會話
    • 3、緩存默認的實現類是:PerpetualCache,使用map進行存儲,key ==> hashcode + sqlid + sql + hashcode + environment的id
    • 4、查詢完就會進行數據的緩存
  • 失效情況:
    • 1、不同的sqlSession會使一級緩存失效
    • 2、同一個sqlSession,但是查詢語句不同,也會使一級緩存失效
    • 3、同一個sqlSession,查詢語句相同,但在中間過程中執行了增刪改操作,也會使一級緩存失效
    • 4、同一個sqlSession,查詢語句相同,執行手動清除緩存,會使一級緩存失效
  • 例如:
    一級緩存

2、二級緩存

  • 特性:
    • 1、默認開啟,但沒有實現
    • 2、作用域,是全局范圍的,存儲到Java進程當中的,如果線程過多,會出現OOM
    • 3、緩存默認的實現類也是PerpetualCache,使用map進行存儲,但是,使用map存儲的是二級緩存根據不同的mapper命名空間多包了一層的map。即:key:mapper的命名空間,value:Map<k,PerpetualCache.map>;
    • 4、提交事務時或者sqlSession關閉的時候進行數據緩存
  • 實現:
    • 1、在全局配置文件中開啟二級緩存,< setting name="cacheEnabled" value="true"/>
    • 2、在需要用到二級緩存的mapper映射文件中加入,< cache>< /cache>,它是基于Mapper映射文件來實現存儲的.
  • 查詢順序:
    • 先從二級緩存中獲取,再從一級緩存中獲取,如果都沒有,則查詢數據庫
  • 失效情況:
    • 1、同一個命名空間下進行增刪改操作,會使二級緩存失效
    • 2、如果不想增刪改操作后緩存被清空,則可以給對應的增刪改sql設置flushCache="false",但是設置要慎重,因為會造成數據臟讀問題。
    • 3、讓查詢到的數據不緩存到二級緩存中:設置useCache=“false” 即:<select id="getDeptById" useCache="false">
    • 4、如果希望其他mapper映射文件的命名空間執行了增刪改也清空另外的命名空間的緩存,可以在某個命名空間下使用:< cache-ref namespace=""/>
  • 例如
    開啟二級緩存
    設置二級緩存
    二級緩存的實現

8、分頁插件

  • Mybatis通過提供插件機制,讓我們可以根據自己的需要去增強Mybatis的功能。Mybatis的插件可以在不修改原來代碼的情況下,通過攔截的方式,改變四大核心對象的行為,例如:處理參數、處理SQL、處理結果等等;
  • Mybatis的分頁默認是基于內存分頁的(查出所有,再截取),在數據量大的情況下效率較低,不過使用mybatis插件可以改變該行為,只需要攔截StatementHandler類的prepare方法,改變要執行的SQL語句為分頁語句即可;

1、應用過程

1、添加依賴

 	<!--mybatis分頁插件依賴--><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.11</version></dependency>

2、插件注冊

  • 在mybatis-config.xml配置文件中進行注冊:
 	<plugins><!--注冊分頁插件--><plugin interceptor="com.github.pagehelper.PageInterceptor"><!--設置當前數據庫的方言(默認會自動檢查當前數據庫環境實用的數據庫)--><property name="helperDialect" value="mysql"/><!--自動合理化設置分頁參數--><property name="reasonable" value="true"/><!--支持通過Mapper接口的參數來傳遞分頁參數,默認值為false,分頁參數名稱為:pageNum、pageSize--><property name="supportMethodsArguments" value="true"/></plugin></plugins>

3、調用

	<select id="queryEmpList" resultType="org.example.pojo.Emp">select * from emp</select>
 @Testpublic void testMybatis9(){EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);PageHelper.startPage(1,2);List<Emp> emps = mapper.queryEmpList();System.out.println(emps);//PageInfo對象中包含了很多分頁相關的屬性,例如,當前頁,總頁數,總記錄數,是否有上/下一頁等等PageInfo<Emp> pageInfo = new PageInfo<>(emps);pageInfo.getList().forEach(System.out::println);System.out.println(pageInfo.getTotal());System.out.println(Arrays.toString(pageInfo.getNavigatepageNums()));}

2、代理和攔截的實現

  • 四大對象什么時候被代理
    • Executor 是openSession()的時候創建的;
    • StatementHandler 是SimpleExecutor.doQuery()創建的,里面包含了處理參數的ParameterHandler 和 處理結果集的ResultSetHandler 的創建,創建之后即調用InterceptorChain.pluginAll(),返回層層代理后的對象。
    • 代理是由Plugin 類創建。在我們重寫的plugin() 方法里面可以直接調用returnPlugin.wrap(target, this)?返回代理對象。
    • 因為代理類是Plugin,所以最后調用的是Plugin 的invoke()方法。它先調用了定義的攔截器的intercept()方法。可以通過invocation.proceed()調用到被代理對象被攔截的方法。
      關鍵的對象
  • 調用流程時序圖
    時序圖

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/37993.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/37993.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/37993.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

338. 比特位計數(leetcode)

338. 比特位計數&#xff08;leetcode&#xff09; 題目描述 給你一個整數 n &#xff0c;對于 0 < i < n 中的每個 i &#xff0c;計算其二進制表示中 1 的個數 &#xff0c;返回一個長度為 n 1 的數組 ans 作為答案。 示例1 輸入&#xff1a;n 2 輸出&#xff1a;[0…

Sorting

本節提供有關在數據網格中對數據進行排序的信息。 GridControl-Grid View Sort Data 默認情況下&#xff0c;最終用戶可以按任何列對數據進行排序&#xff0c;但使用MemoExEdit、ImageEdit和PictureEdit在位編輯器的列除外。在運行時&#xff0c;單擊列標題一次以升序排列數…

中國電信股份有限公司江西分公司招聘信息 7.5日截止

法律事務管理(南昌) 學歷要求 本科及以上學歷 崗位職責 1.依據國家法律、法規和相關規章規定,為公司其他部門提供日常法律服務與支持; 2.負責公司各類合同審核工作; 3.負責公司法律文件的起草和法律事務談判; 4.圍繞與公司業務有關的法律問題及法…

如何在Java中實現分布式緩存?

如何在Java中實現分布式緩存&#xff1f; 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01;今天我們將深入探討在Java應用程序中如何實現分布式緩存&#xff0c;探…

【SQL注入】

SQL注入&#xff1a;通過可輸入/修改sql參數實現攻擊的過程 文章目錄 0x00 SQL注入漏洞原理0x01 前置知識1 SQL注入分類2 數據庫知識 0x02 是否存在SQL注入&#xff1f;0x03 不同SQL注入1. Union注入2. 盲注Blind3. base64注入 0x04 SQL注入繞過技術0x05 SQL防注入 0x00 SQL注入…

網絡爬蟲的應用場景

網絡爬蟲的應用場景 網絡爬蟲的應用場景在現代信息化社會中顯得尤為廣泛和重要。除了我們熟知的搜索引擎利用爬蟲技術抓取互聯網上的信息以提供用戶搜索服務外&#xff0c;還有許多其他領域也依賴于網絡爬蟲的高效運作。 在電商領域&#xff0c;網絡爬蟲被廣泛應用于價格監控…

最強文生圖模型Stable Diffusion 3 Medium 正式開源

Stability AI 宣布 Stable Diffusion 3 Medium 現已開源&#xff0c;是 Stable Diffusion 3 系列中最新、最先進的文本生成圖像 AI 模型 —— 官方聲稱是 “迄今為止最先進的開源模型”&#xff0c;其性能甚至超過了 Midjourney 6。 Stable Diffusion 3 Medium 模型規格參數達到…

獲取 url 地址欄 ? 后面的查詢字符串,并以鍵值對形式放到對象里面

寫在前面 在前端面試當中&#xff0c;關于 url 相關的問題很常見&#xff0c;而對于 url 請求參數的問題也很常見&#xff0c;大部分以筆試題常見&#xff0c;今天就根據這道面試題一起來看一下。 問題 獲取 url 地址欄?后面的查詢字符串&#xff0c;并以鍵值對形式放到對象…

[分布式網絡通訊框架]----MprpcController以及Logger類

在calluserservice.cc中&#xff0c;使用UserServiceRpc_Stub類的時候&#xff0c;我們最終調用形式為&#xff1a;stub.Login(&controller,&request,&response,nullptr); 注意到其中有一個controller對象&#xff0c;這個是由MprpcController類定義出來的對象&…

LLVM AliasAnalysis別名分析 TBAA TypeBasedAliasAnalysis

一、什么是別名分析 Alias Analysis (又名 Pointer Analysis)是用于確定兩個指針是否指向內存中的同一對象&#xff0c;這里有很多不同的別名分析算法&#xff0c;分為幾種類型&#xff1a;流敏感vs流非敏感、上下文敏感vs上下文非敏感、域敏感vs域非敏感、基于一致性的vs基于…

單片機學習(16)--直流電機驅動

直流電機驅動 15.1直流電機驅動基礎知識1.直流電機介紹2.電機驅動電路3.PWM介紹 15.2LED呼吸燈和直流電機調速1.LED呼吸燈代碼2.直流電機調速&#xff08;1&#xff09;產生PWM的方法&#xff08;2&#xff09;工程目錄&#xff08;3&#xff09;main.c函數 15.1直流電機驅動基…

isdecimal()方法——判斷字符串是否只包含十進制字符

自學python如何成為大佬(目錄):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 語法參考 isdecimal()方法用于檢查字符串是否只包含十進制字符。這種方法只適用于unicode對象。 注意&#xff1a;定義一個十進制字符串&#xff0c…

linux高級編程(進程)(2)

父子進程的關系&#xff1a; 子進程是父進程的副本。子進程獲得父進程數據段&#xff0c;堆&#xff0c;棧&#xff0c;正文段共享。&#xff08;子分配了一塊新的內存&#xff0c;但是代碼段指向父進程&#xff0c;也就是說不論幾個子進程都只有一個code段&#xff09; …

SpringCloud中復制模塊然后粘貼,文件圖標缺少藍色方塊

再maven中點擊&#xff0b;號&#xff0c;把當前pom文件交給maven管理即可

RabbitMq的基礎及springAmqp的使用

RabbitMq 官網:RabbitMQ: One broker to queue them all | RabbitMQ 什么是MQ&#xff1f; mq就是消息隊列&#xff0c;消息隊列遵循這先入先出原則。一般用來解決應用解耦&#xff0c;異步消息&#xff0c;流量削峰等問題&#xff0c;實現高性能&#xff0c;高可用&#xf…

容器技術-docker2

容器化技術Docker Docker介紹 官網&#xff1a; docker.io docker.com 公司名稱&#xff1a;原名dotCloud 14年改名為docker 容器產品&#xff1a;docker 16年已經被更名為Moby docker-hub docker.io docker容器歷史 和虛擬機一樣&#xff0c;容器技術也是一種資源隔…

java基于ssm+jsp 二手手機回收平臺系統

1前臺首頁功能模塊 二手手機回收平臺系統&#xff0c;在系統首頁可以查看首頁、手機商城、新聞資訊、我的、跳轉到后臺、購物車等內容&#xff0c;如圖1所示。 圖1前臺首頁功能界面圖 用戶注冊&#xff0c;在用戶注冊頁面可以填寫賬號、密碼、姓名、手機、郵箱、照片、地址、…

深度解析RocketMq源碼-消息推送、持久化、消費全流程

1.緒論 前面的幾篇文章都剖析了broker的存儲文件。那么生產者發送一條消息到達broker過后是如何處理的&#xff0c;這條消息結果什么處理過后&#xff0c;消費者才能夠消費這條消息。接下來&#xff0c;帶我們將仔細剖析一下一條消息從生產者生產消息&#xff0c;到到達broker…

在線字節大端序小端序轉換器

具體請前往&#xff1a;在線字節大端序小端序轉換器

操作系統期末復習真題四

一、前言&#x1f680;&#x1f680;&#x1f680; 小鄭在刷題的過程中幫大家整理了一些常見的考試題目&#xff0c;以及易于遺忘的知識點&#xff0c;希望對大家有所幫助。 二、正文?????? 1.OS的不確定性是指(ABC)。 A.程序的運行次序不確定 B.程序多次運行的時間不…