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
全局配置文件: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)參數封裝擴展思考:
取值:id==》#{id/param1} lastName===>#{param2}
取值:id===》#{param1} lastName===》#{param2.LastName/e.lastName}
也會特殊處理,也是把傳入的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
- 返回Map,key就是列名,值是對應的值
- 多條紀錄封裝成一個map,Map<Integer, Employee> 鍵是這條紀錄的主鍵,值是記錄封裝的JavaBean
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的寫法:
- 第二種resultMap的寫法
- 使用association進行分步查詢
其中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定義關聯集合封裝規則
- 嵌套結果集的方式
- 分步方式
-
擴展:
多列傳值
? 封裝成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從參數中取值進行判斷遇見特殊符號應該去寫轉義字符&&需要寫為&"需要寫為"--><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()!=""">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從參數中取值進行判斷遇見特殊符號應該去寫轉義字符&&需要寫為&"需要寫為"--><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()!=""">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()!=""">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学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 类选择器选择非唯一属性无法精确取值的问题
- 下一篇: ipvsadm+keepalived安装