日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

mybatis学习笔记

發布時間:2025/5/22 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mybatis学习笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. HelloWorld

導入mybatis

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version> </dependency>

1.1 配置文件法

從XML中構建SqlSessionFactory

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><mappers><mapper resource="mapper/employee-mapper.xml"/></mappers> </configuration>

mapper

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace: 名稱空間id: 唯一標識returnType: 返回值類型#{id} 從傳遞過來的參數中取出id值 --> <mapper namespace="com.meituan.mybatis.bean.EmployeeMapper"><select id="selectEmp" resultType="com.meituan.mybatis.bean.Employee">select * from employee where id = #{id}</select> </mapper>

JavaBean

public class Employee {private Integer id;private String lastName;private String email;private String gender;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}@Overridepublic String toString() {return "Employee{" +"id=" + id +", lastName='" + lastName + '\'' +", email='" + email + '\'' +", gender='" + gender + '\'' +'}';} }

單元測試

/*** 1. 根據xml配置文件(全局配置文件)創建一個SqlSessionFactory對象* 有數據源一些運行環境信息 * 2. sql映射文件,配置了每一個sql,以及sql的封裝規則等* 3. 將sql映射文件注冊在全局配置文件中* 4. 寫代碼* 1) 根據全局配置文件得到SqlSessionFactory* 2) 通過SqlSession工廠獲取到SqlSession,使用SqlSession執行增刪改查,一個SqlSession就是代表和數據庫的一次會話,用完關閉* 3) 使用sql的唯一標識(id)來告訴mybatis執行哪個sql,sql全部保存在sql映射文件(mapper)中* @throws Exception*/@Testpublic void test() throws Exception{String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 獲取SqlSession實例,能直接執行已經映射的sql語句SqlSession sqlSession = sqlSessionFactory.openSession();/*** Retrieve a single row mapped from the statement key and parameter.* @param <T> the returned object type* @param statement Unique identifier matching the statement to use. 傳入唯一標識* @param parameter A parameter object to pass to the statement. 傳入參數* @return Mapped object*/Employee employee = sqlSession.selectOne("com.meituan.mybatis.bean.EmployeeMapper.selectEmp", 1);System.out.println(employee);}

駝峰命名法問題:

mybatis-config.xml配置文件配置時,要注意節點順序

<properties>...</properties> <settings>...</settings> <typeAliases>...</typeAliases> <typeHandlers>...</typeHandlers> <objectFactory>...</objectFactory> <objectWrapperFactory>...</objectWrapperFactory> <plugins>...</plugins> <environments>...</environments> <databaseIdProvider>...</databaseIdProvider> <mappers>...</mappers>

增加設置

支持駝峰命名法 <setting name="mapUnderscoreToCamelCase" value="true"/>

1.2 接口式編程

配置文件

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace: 名稱空間;接口式編程中,須指定為接口的全類名id: 唯一標識returnType: 返回值類型#{id} 從傳遞過來的參數中取出id值;接口式編程中,id改為方法名 --> <mapper namespace="com.meituan.mybatis.dao.EmployeeMapper"><select id="getEmpById" resultType="com.meituan.mybatis.bean.Employee">select * from employee where id = #{id}</select> </mapper>

mapper接口

@Mapper public interface EmployeeMapper {public Employee getEmpById(Integer id); }

單元測試

@Testpublic void test01() throws Exception {//1. 獲取SqlSessionFactory對象SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();//2. 獲取SqlSession對象SqlSession sqlSession = sqlSessionFactory.openSession();try {//3. 獲取接口的實現類對象// mybatis會為接口自動創建一個代理對象,代理對象去執行增刪改查方法EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);Employee employee = mapper.getEmpById(1);System.out.println(employee);} finally {sqlSession.close();}}private SqlSessionFactory getSqlSessionFactory() throws Exception{String resources = "mybatis-config.xml";InputStream is = Resources.getResourceAsStream(resources);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);return sqlSessionFactory;}

1.3 總結

  • 接口式編程

    原生: Dao ====> DaoImpl

    mybatis: Mapper ==== > xxMapper.xml

  • SqlSession代表和數據庫的一次,用完必須關閉
  • SqlSession和connection一樣,都是非線程安全的,每次使用都應該去獲取新的對象,不能寫為成員變量。
  • mapper接口沒有實現類,但是mybatis會為這個接口生成一個代理對象
  • 兩個重要的配置文件

    全局配置文件:mybatis-config.xml 包含數據庫連接池信息,事務管理器信息等系統運行環境

    sql映射文件:保存了每一個sql語句的映射信息

  • 2. Mybatis全局配置文件

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><!--1. mybatis可以使用properties來引入外部properties配置文件的內容屬性:resource:引入類路徑下的資源url:引入網絡路徑或者磁盤路徑下的資源--><properties resource="dbconfig.properties"></properties><!--2. 這是 MyBatis 中極為重要的調整設置,它們會改變 MyBatis 的運行時行為。setting:用來設置每一個設置項name:設置項名value:設置項取值--><settings><setting name="mapUnderscoreToCamelCase" value="true"/></settings><!--3. typeAliases 類型別名是為 Java 類型設置一個短的名字。它只和 XML 配置有關,存在的意義僅在于用來減少類完全限定名的冗余。別名不區分大小寫typeAlias:為某個java類型起別名type:指定要起別名的類型全類名;默認別名就是類名小寫:employeealias:指定新的別名<package> :為某個包下的所有類批量起別名每一個在包 domain.blog 中的 Java Bean,在沒有注解的情況下,會使用 Bean 的首字母小寫的非限定類名來作為它的別名。 比如 domain.blog.Author 的別名為 author;若有注解,則別名為其注解值。name:指定包名(為當前包以及下面所有的后代包的每一類都起一個包名)如果子包下有相同的類名,mybatis會起相同的包名從而報錯。可以使用@Alias給特定類指定別名--><typeAliases><!--<typeAlias type="com.meituan.mybatis.config.bean.Employee" alias="emp"></typeAlias>--><package name="com.meituan.mybatis.config"/></typeAliases><!--4. typeHandler 無論是 MyBatis 在預處理語句(PreparedStatement)中設置一個參數時,還是從結果集中取出一個值時, 都會用類型處理器將獲取的值以合適的方式轉換成 Java 類型。--><!--5. plugins 插件--><!--6. environment MyBatis 可以配置成適應多種環境,這種機制有助于將 SQL 映射應用于多種數據庫之中, 現實情況下有多種理由需要這么做。default指定使用某種環境來切換環境,可以達到快速切換環境。environment配置一個具體的環境信息,id代表當前環境的唯一標識,必須有兩個標簽:transactionManager:事務管理器,type指定事務管理器的類型 在 MyBatis 中有兩種類型的事務管理器(也就是 type=”[JDBC|MANAGED]”):JDBC:typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);MANAGED:typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);支持自定義事務管理器,實現TransactionFactory接口即可dataSource:數據源type:數據源類型,有三種內建的數據源類型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):支持自定義數據源,實現DataSourceFactory接口,type為自定義數據源的全類名--><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--7. databaseIdProvider: 支持多數據庫廠商--><!--8. mappers映射器mapper注冊一個sql映射resource:引用類路徑下的sql映射文件url:引用網絡路徑下或者磁盤路徑下的映射文件class:使用映射器接口實現類的完全限定類名1. 有sql映射文件,映射文件名必須和接口同名,并且放在與接口同一目錄下2. 沒有sql映射文件,所有的sql都是利用注解寫在接口上package:將包內的映射器接口實現全部注冊為映射器--><mappers><mapper resource="mapper/employee-mapper.xml"/></mappers><!--標簽的編寫是有順序的--> </configuration>

    3. Mybatis映射文件

    MyBatis 的真正強大在于它的映射語句,也是它的魔力所在。由于它的異常強大,映射器的 XML 文件就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 代碼進行對比,你會立即發現省掉了將近 95% 的代碼。MyBatis 就是針對 SQL 構建的,并且比普通的方法做的更好。

    3.1 獲取自增主鍵

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace: 名稱空間id: 唯一標識returnType: 返回值類型#{id} 從傳遞過來的參數中取出id值 --> <mapper namespace="com.meituan.mybatis.mapper.dao.EmployeeMapper"><select id="getEmpById" resultType="com.meituan.mybatis.mapper.bean.Employee">SELECT *FROM employeeWHERE id = #{id}</select><!--parameterType:可以省略mysql支持自增主鍵,自增主鍵的獲取,mybatis也是利用statement.getGeneratedKeys(),useGeneratedKeys="true":使用自增主鍵獲取主鍵值策略keyProperty:指定對應的主鍵屬性,也就是mybatis獲取到主鍵值以后,將這個值封裝給JavaBean的哪個屬性--><insert id="addEmp" parameterType="com.meituan.mybatis.mapper.bean.Employee"useGeneratedKeys="true" keyProperty="id">INSERT INTO employee (last_name, email, gender)VALUES (#{lastName}, #{email}, #{gender})</insert><update id="updateEmp">UPDATE employeeSET last_name = #{lastName}, email = #{email}, gender = #{gender}WHERE id = #{id}</update><delete id="deleteEmpById">DELETE FROM employee WHERE id=#{id}</delete> </mapper>

    單元測試

    /*** 1. mybatis允許增刪改直接定義以下類型返回值* Integer Long Boolean* 2. 手動提交數據* @throws Exception*/@Testpublic void test02() throws Exception {SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();//1. 獲取到的SqlSession不會自動提交SqlSession sqlSession = sqlSessionFactory.openSession();try {EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);Employee employee = new Employee(null, "jerry", "jerry@tom.com", "2");System.out.println(employee);System.out.println("============");mapper.addEmp(employee);System.out.println(employee);// employee.setLastName("jason"); // employee.setId(3); // mapper.updateEmp(employee); // mapper.deleteEmpById(3);sqlSession.commit();} finally {sqlSession.close();}}private SqlSessionFactory getSqlSessionFactory() throws Exception{String resources = "mybatis-config.xml";InputStream is = Resources.getResourceAsStream(resources);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);return sqlSessionFactory;}

    3.2 參數處理

    1)單個參數:mybatis不會做特殊處理

    2)多個參數

    ? 異常:

    org.apache.ibatis.exceptions.PersistenceException: ### Error querying database. Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2] ### Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2]

    ? 操作:

    ? 方法:public Employee getEmpByIdAndLastName(Integer id ,String lastName);

    ? 取值:#{id},#{lastName}

    ? mybatis會特殊處理,多個參數會被封裝成一個map

    ? key:param1....paramN

    ? value:傳入的參數值

    ? #{}就是從map中獲取指定的key值,或者參數的索引也可以

    命名參數:

    ? 明確指定封裝參數值map的key: @Param("id")

    POJO:

    ? 如果多個參數正好是業務邏輯的數據模型,可以直接傳入POJO:

    ? #{屬性名}:取出傳入的pojo的屬性值

    Map:

    如果多個參數不是業務模型中的數據,沒有對應的pojo,不經常使用,為了方便,也可以傳入map

    如果多個參數不是業務模型中的數據,但是經常使用,推薦寫一個TO(Transfer Object) 數據傳輸對象

    3)參數封裝擴展思考:

  • public Employee getEmp(@Param("id"))Integer id, String lastName);

    取值:id==》#{id/param1} lastName===>#{param2}

  • public Employee getEmp(Integer id, @Param("e") Employee emp);

    取值:id===》#{param1} lastName===》#{param2.LastName/e.lastName}

  • 特別注意:如果是Collection(List、Set)類型或者數組

    也會特殊處理,也是把傳入的list或者數組封裝在map中

    ? key:Collection(collection),如果是List還可以使用(list)

    ? 數組(array)

    public Employee getEmpById(List<Integer> ids);

    取值:取出第一個id的值:#{list[0]}

  • 3.3 結合源碼,mybatis如何處理參數

    ParamNameResolver解析參數封裝map

    (1) names:(0=id, 1=lastName)

    ? 1) 獲取每個標注Param注解的參數param值:id,lastName,賦值給name

    ? 2)每次解析一個參數給map中保存信息:key是索引值, value是name的值

    ? name的值:

    ? 標注了param注解,注解的值

    ? 沒有標注:

    ? 1、全局配置:useActualParamName,name=參數名(要求JDK1.8)

    ? 2、name=map.size() 相當于當前元素的索引

    ? names:{0=id, 1=lastName}

    public Object getNamedParams(Object[] args) {final int paramCount = names.size();//1. 參數為null直接返回if (args == null || paramCount == 0) {return null;//2. 如果只有一個元素并且沒有param注解:args[0],單個參數直接返回} else if (!hasParamAnnotation && paramCount == 1) {return args[names.firstKey()];//3. 多個元素或者有Param標注} else {final Map<String, Object> param = new ParamMap<Object>();int i = 0;// 4. 遍歷names,構造器的時候就已經確定for (Map.Entry<Integer, String> entry : names.entrySet()) {//names的value作為新map的key,nameskey作為取值的參考//eg:{id=args[0], lastName=args[1]},因此可以在映射文件中取到相應的值param.put(entry.getValue(), args[entry.getKey()]);// add generic param names (param1, param2, ...)final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);// ensure not to overwrite parameter named with @Paramif (!names.containsValue(genericParamName)) {param.put(genericParamName, args[entry.getKey()]);}i++;}return param;}}

    3.4 參數值的獲取

    #{}:可以獲取map中的值或者pojo對象屬性的值

    ${}:可以獲取map中的值或者pojo對象屬性的值

    區別:#{}是以預編譯的形式,將參數設置到sql語句中,PreparedStatement

    ? ${}:取出的值直接拼裝在sql語句中,會有安全問題

    ? 大多情況下,取參數的值都應該使用#{},在某些情況下,原生jdbc不支持占位符的地方可以使用${}進行取值,

    比如分表;按年份分表拆分 select from 2017_salary可以寫為 select from ${year}_salary

    3.5 #{}取值規則

    更豐富的用法

    規定參數的一些規則:

    ? javaType、jdbcType、mode(存儲過程)、numericScale、resultMap、typeHandler、jdbcTypeName、expression

    jdbcType參演需要在某種特定的條件下被設置

    ? 在數據為null的時候,有些數據庫可能無法識別mybatis對null的默認處理,如oracle,mybatis對所有的null都映射為原生Jdbc的OTHER類型, oracle無法處理,mysql可以處理

    1、#{email, jdbcType=OTHER}

    2、全局配置文件mybatis-config.xml中:<setting name="jdbcTypeForNull" value="NULL" />

    3.6 Select返回List、Map

    • 返回List
    <!--resultType:如果返回的是一個集合,要寫集合中元素的類型--><select id="getEmpsByLastNameLike" resultType="com.meituan.mybatis.mapper.bean.Employee">SELECT * FROM employee WHERE last_name LIKE #{lastName}</select>
    • 返回Map,key就是列名,值是對應的值
    <!--map是mybatis自定義的別名--> <select id="getEmpByIdReturnMap" resultType="map">SELECT * FROM employee WHERE id=#{id} </select>
    • 多條紀錄封裝成一個map,Map<Integer, Employee> 鍵是這條紀錄的主鍵,值是記錄封裝的JavaBean
    <select id="getEmpByLastNameLikeReturnMap" resultType="com.meituan.mybatis.mapper.bean.Employee">SELECT * FROM employee WHERE last_name LIKE #{lastName}</select> @MapKey("id") public Map<Integer, Employee> getEmpByLastNameLikeReturnMap(String lastName);

    3.7 自定義結果映射封裝規則

    resultMap?元素是 MyBatis 中最重要最強大的元素。它可以讓你從 90% 的 JDBC?ResultSets?數據提取代碼中解放出來, 并在一些情形下允許你做一些 JDBC 不支持的事情。 實際上,在對復雜語句進行聯合映射的時候,它很可能可以代替數千行的同等功能的代碼。 ResultMap 的設計思想是,簡單的語句不需要明確的結果映射,而復雜一點的語句只需要描述它們的關系就行了。

    <resultMap id="myEmp" type="com.meituan.mybatis.mapper.bean.Employee"><!--column指定哪一列, property指定對應JavaBean屬性id:指定主鍵列的封裝規則,會在底層優化規則--><id column="id" property="id"/><!--定義普通列的封裝規則--><result column="last_name" property="lastName"/><!--其他不指定的列會自動封裝,推薦只要寫resultMap,就將全列的映射規則都寫上--><result column="email" property="email"/><result column="gender" property="gender"/></resultMap><select id="getEmpById" resultMap="myEmp">SELECT *FROM employeeWHERE id = #{id}</select>

    3.8 關聯查詢

    • 第一種resultMap的寫法:
    <!--場景一:查詢Employee的同時查詢員工所在的部門--><resultMap id="myDifEmp" type="com.meituan.mybatis.mapper.bean.Employee"><id column="id" property="id" /><result column="last_name" property="lastName"/><result column="email" property="email"/><result column="gender" property="gender"/><result column="did" property="dept.id"/><result column="dept_name" property="dept.departmentName"/></resultMap><select id="getEmpAndDept" resultMap="myDifEmp">SELECT e.id id, e.last_name lastName, e.email email, e.gender gender, e.d_id d_id, d.id did , d.dept_name dept_name from employee e, department d WHERE e.d_id = d.id AND e.id=#{id}</select>
    • 第二種resultMap的寫法
    <resultMap id="myDifEmp2" type="com.meituan.mybatis.mapper.bean.Employee"><id column="id" property="id" /><result column="last_name" property="lastName"/><result column="email" property="email"/><result column="gender" property="gender"/><!--association可以指定聯合的JavaBean對象property ="dept" 指定哪個屬性是聯合的對象javaType:指定這個屬性對象的類型--><association property="dept" javaType="com.meituan.mybatis.mapper.bean.Department"><id column="did" property="id"/><result column="dept_name" property="departmentName"/></association></resultMap>
    • 使用association進行分步查詢
    <resultMap id="myEmpByStep" type="com.meituan.mybatis.mapper.bean.Employee"><id column="id" property="id" /><result column="last_name" property="lastName"/><result column="email" property="email"/><result column="gender" property="gender"/><!--association定義關聯對象的封裝規則select:表明當前屬性是調用select指定的方法查出的結果column:指定將哪一列的值傳給這個方法--><association property="dept" select="com.meituan.mybatis.mapper.dao.DepartmentMapper.getDeptById"column="d_id"></association></resultMap><select id="getEmpByIdStep" resultMap="myEmpByStep">SELECT * FROM employee WHERE id=#{id}</select>

    其中association中select的部分為

    <mapper namespace="com.meituan.mybatis.mapper.dao.DepartmentMapper"><select id="getDeptById" resultType="com.meituan.mybatis.mapper.bean.Department">SELECT* FROM department WHERE id=#{id}</select></mapper>

    3.9 延遲加載

    <!--可以使用延遲加載Employee===》Dept每次查詢Employee對象的時候,都將部門信息一起查詢出來,而需要是:部門信息在使用的時候再去查詢分步查詢的基礎之上,加上兩個配置,即可實現延遲加載 -->

    mybatis-config.xml

    <!--顯示指定每個需要更改的配置的值,即使是默認的,以防版本更替帶來的問題--><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/>

    測試

    @Testpublic void test07() throws Exception {SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();SqlSession sqlSession = sqlSessionFactory.openSession();try {Employee employee = sqlSession.selectOne("com.meituan.mybatis.mapper.dao.EmployeeMapperPlus.getEmpByIdStep", 1);System.out.println(employee.getLastName());System.out.println(employee.getDept().getDeptName());} finally {sqlSession.close();}}

    輸出:

    在兩次輸出中出現一段sql查詢

    14:23:18.093 [main] DEBUG com.meituan.mybatis.mapper.dao.EmployeeMapperPlus.getEmpByIdStep - ==> Preparing: SELECT * FROM employee WHERE id=? 14:23:18.133 [main] DEBUG com.meituan.mybatis.mapper.dao.EmployeeMapperPlus.getEmpByIdStep - ==> Parameters: 1(Integer) 14:23:18.227 [main] DEBUG com.meituan.mybatis.mapper.dao.EmployeeMapperPlus.getEmpByIdStep - <== Total: 1 tom 14:23:18.228 [main] DEBUG com.meituan.mybatis.mapper.dao.DepartmentMapper.getDeptById - ==> Preparing: SELECT* FROM department WHERE id=? 14:23:18.228 [main] DEBUG com.meituan.mybatis.mapper.dao.DepartmentMapper.getDeptById - ==> Parameters: 2(Integer) 14:23:18.269 [main] DEBUG com.meituan.mybatis.mapper.dao.DepartmentMapper.getDeptById - <== Total: 1 銷售部

    3.10 collection定義關聯集合封裝規則

    • 嵌套結果集的方式
    <!--場景二查詢部門的時候將部門對應的所有員工信息也查詢出來 --><resultMap id="MyDept" type="com.meituan.mybatis.mapper.bean.Department"><id column="did" property="id" /><result column="dept_name" property="deptName"/><!--collection定義關聯集合類型的屬性的封裝規則--><collection property="emps" ofType="com.meituan.mybatis.mapper.bean.Employee"><!--定義這個今本中元素的封裝規則--><id column="eid" property="id"/><result column="last_name" property="lastName"/><result column="email" property="email"/><result column="gender" property="gender"/></collection></resultMap><select id="getDeptByIdPlus" resultMap="MyDept">SELECT d.id did, d.dept_name dept_name, e.id eid, e.last_name last_name,e.email email, e.gender genderFROM department d LEFT JOIN employee e ON d.id=e.d_idWHERE d.id=#{id}</select>
    • 分步方式
    <resultMap id="MyDeptStep" type="com.meituan.mybatis.mapper.bean.Department"><id column="id" property="id"/><result column="departmentName" property="deptName"/><collection property="emps" select="com.meituan.mybatis.mapper.dao.EmployeeMapper.getEmpByDeptId"column="id"></collection></resultMap><select id="getDeptByIdStep" resultMap="MyDeptStep">SELECT id,dept_name departmentName FROM department WHERE id=#{id}</select>
    • 擴展:

      多列傳值

      ? 封裝成map傳遞

      ? column="{key1=val1, key2=val2}"

      fetchType="lazy",表示使用延遲加載

      • lazy:延遲加載
      • eager:立即加載

    3.11 descriminator 鑒別器

    <discriminator javaType="int" column="draft"><case value="1" resultType="DraftPost"/> </discriminator>

    有時一個單獨的數據庫查詢也許返回很多不同 (但是希望有些關聯) 數據類型的結果集。 鑒別器元素就是被設計來處理這個情況的, 還有包括類的繼承層次結構。 鑒別器非常容易理 解,因為它的表現很像 Java 語言中的 switch 語句。

    定義鑒別器指定了 column 和 javaType 屬性。 列是 MyBatis 查找比較值的地方。 JavaType 是需要被用來保證等價測試的合適類型(盡管字符串在很多情形下都會有用)。比如:

    <resultMap id="vehicleResult" type="Vehicle"><id property="id" column="id" /><result property="vin" column="vin"/><result property="year" column="year"/><result property="make" column="make"/><result property="model" column="model"/><result property="color" column="color"/><discriminator javaType="int" column="vehicle_type"><case value="1" resultMap="carResult"/><case value="2" resultMap="truckResult"/><case value="3" resultMap="vanResult"/><case value="4" resultMap="suvResult"/></discriminator> </resultMap>

    4. 動態sql

    MyBatis 的強大特性之一便是它的動態 SQL。 mybatis支持OGNL表達式。

    4.1 if where trim

    <!--查詢員工,需求:攜帶了哪個字段查詢條件就整個這個字段的值--><select id="getEmpsByConditionIf" resultType="com.meituan.mybatis.dynamic.bean.Employee">SELECT * FROM employee WHERE<!--test:判斷表達式(OGNL)c: if test從參數中取值進行判斷遇見特殊符號應該去寫轉義字符&&需要寫為&amp;"需要寫為&quot;--><if test="id != null">id=#{id}</if><if test="lastName != null and lastName!=''">AND last_name LIKE #{lastName}</if><if test="email!=null and email.trim()!=&quot;&quot;">AND email=#{email}</if><if test="gender==0 or gender == 1">AND gender=#{gender}</if></select>

    查詢時,某些條件缺失(如id),則可能導致sql拼裝出現問題

    解決方案:

    1、WHERE 1=1

    WHERE 1=1 <if test = "">AND *** </if>

    2、mybatis推薦的的方案:采用<where>標簽,將所有的查詢條件包括在內,mybatis就會將where標簽中拼裝的sql,多出來的and或者or去掉;where只會去掉前面多出來的and或者or

    <where><!--test:判斷表達式(OGNL)c: if test從參數中取值進行判斷遇見特殊符號應該去寫轉義字符&&需要寫為&amp;"需要寫為&quot;--><if test="id != null">id=#{id}</if><if test="lastName != null and lastName!=''">AND last_name LIKE #{lastName}</if><if test="email!=null and email.trim()!=&quot;&quot;">AND email=#{email}</if><if test="gender==0 or gender == 1">AND gender=#{gender}</if> </where>

    3、trim標簽的使用

    <select id="getEmpsByConditionTrim" resultType="com.meituan.mybatis.dynamic.bean.Employee">SELECT * FROM employee<!---prefix="" 前綴:trim標簽體中是整個字符串拼串后的結果,prefix會給拼串后的整個字符串加一個前綴prefixOverrides="" 前綴覆蓋:去掉整個字符串前面多余的字符suffix="" 后綴:整個串加后綴suffixOverrides="" 去掉整個串后面的字符--><trim prefix="where" suffixOverrides="and"><if test="id != null">id=#{id} AND</if><if test="lastName != null and lastName!=''">last_name LIKE #{lastName} AND</if><if test="email!=null and email.trim()!=&quot;&quot;">email=#{email} AND</if><if test="gender==0 or gender == 1">gender=#{gender}</if></trim></select>

    4.2 choose set標簽

    choose 分支選擇,相當于帶了break的switch-case

    <!-- 如果帶了id就用id查,如果帶了lastName就用lastName查--><select id="getEmpsByConditionChoose" resultType="com.meituan.mybatis.dynamic.bean.Employee">SELECT * FROM employee<where> <!-- 如果帶了id就用id查,如果帶了lastName就用lastName查--><choose><when test="id!=null">id=#{id}</when><when test="lastName!=null">last_name LIKE #{lastName}</when><when test="email!=null">email=#{email}</when><otherwise>1=1</otherwise></choose></where></select>

    set標簽用于update,可以去掉多掉多余的“,”

    4.3 foreach

    <select id="getEmpsByConditionForeach" resultType="com.meituan.mybatis.dynamic.bean.Employee">SELECT * FROM employee WHERE id IN<!--collection:指定要遍歷的集合list類型的參數會特殊處理封裝在map中,map的key就叫listitem:將遍歷出的元素賦值給指定的變量#{變量名}就能取出變量的值也就是當前遍歷出的元素separator:每個元素之間的分隔符open:遍歷出的所有結果拼接一個開始的字符close:遍歷出的所有結果拼接一個結束的字符index:索引。遍歷list的時候是索引遍歷map的時候index表示的就是map的key,item就是map的值--><foreach collection="ids" item="item_id" separator="," open="(" close=")">#{item_id}</foreach></select>

    批量插入:

    <insert id="addEmpsByConditionForeach">INSERT INTO employee (last_name, email, gender, d_id) VALUES<foreach collection="list" item="emp" separator=",">(#{emp.lastName}, #{emp.email}, #{emp.gender}, #{emp.dept.id})</foreach></insert>

    注意:list類型的參數會特殊處理封裝在map中,map的key就叫list。如果期望此時傳入的參數名由自己定制,可以

    1、@Param("*")

    2、將list傳入自己的map中

    4.4 mybatis內置參數

    mybatis默認有兩個內因參數

    1、 _parameter:代表整個參數

    ? 單個參數:_parameter就是這個參數

    ? 多個參數:參數會被封裝為一個map;_parameter就是代表這個map

    2、 _databaseId: 如果配置了databaseIdProvider標簽,

    ? _databaseId就是代表當前數據庫的別名

    4.5 bind

    bind可以將OGNL表達式的值綁定到一個變量中,方便后來引用,例如:

    <bind name="_lastName" value="'%'+lastName+'%'">

    4.6 sql 抽取可重用的片段

    使用sql標簽定義可重用片段

    <sql id="insertColumn">employee_id, last_name, email </sql>

    使用include標簽引用可重用片段

    <include refid"insertColumn"></include>

    5. 緩存機制

    緩存可以極大的提升查詢效率。mybatis默認定義了兩級緩存:

    • 默認情況下,只有一級緩存(SqlSession級別緩存,也稱為本地緩存)開啟。
    • 二級緩存需要手動開啟和配置,是基于namespace級別的緩存,也稱全局緩存。
    • 為了提高擴展性,mybatis定義了緩存接口Cache。可以通過實現cache接口來自定義二級緩存

    5.1 一級緩存

    與數據庫同一次會話期間查詢到的數據會放在本地緩存中,以后如果需要獲取相同的數據,直接從緩存中拿,沒必要再去查詢數據庫。mybatis默認開啟一級緩存。

    一級緩存失效情況

    • sqlSession不同
    • sqlSession相同,查詢條件不同(當前一級緩存中還沒有這個數據)
    • sqlSession相同,兩次查詢期間執行了增刪改(可能會導致當前數據失效)
    • 手動清空了緩存sqlSession.clearCache();

    5.2 二級緩存

    基于namespace級別的緩存,一個namespace對應一個二級緩存

    工作機制:

    1、一個會話(session),查詢一條ovry,這個數據就會被放在當前會話的一級緩存中

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

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

    4、 查出的數據會默認先放在一級緩存中,只有會話提交或者關閉以后,一級緩存中的數據才會轉移到二級緩存中

    使用:

    1、開啟全局二級緩存配置,<setting name="cacheEnabled" value="true"/>

    2、在某個namespace中進行配置

    <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
    • eviction

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

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

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

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

      默認LRU

    • flushInterval:緩存刷新間隔

      緩存多久清空一次,默認不清空,單位毫秒

    • readOnly:是否只讀

      true:只讀,mybatis認為所有從緩存中獲取數據的操作都是只讀操作,不會修改數據。mybatis為了加快獲取速度,直接會將數據在緩存中的引用交給用戶。特點:不安全,速度快

      false:不只讀。mybatis認為獲取的數據可能會被修改,mybatis會利用序列化&反序列的技術克隆一份新的數據給用戶。特點:安全,速度慢

    • size:緩存多少個元素
    • type:指定自定義緩存的全類名,實現Cache接口即可

    3、 pojo需要實現序列化接口

    5.3 和緩存有關的設置和屬性

    1、<setting name="cacheEnabled" value="true"/>開啟或關閉緩存

    2、 每個select標簽都有useCache屬性,true為使用,false為不使用(一級緩存依然使用,二級緩存不使用)

    3、每個增刪改標簽的flushCache屬性值為true,即增刪改執行完成后應付清除緩存,包括一級、二級緩存。查詢標簽默認flushCache="false",當設置為true時,每次查詢之前都會清空緩存,緩存沒有被使用

    4、sqlSession.clearCache();只是清除一級緩存

    5、localCacheScope:本地緩存作用域(一級緩存),可選擇SESSION、STATEMENT。STATEMENT可以禁用緩存

    5.4 緩存原理

    《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的mybatis学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。