认识MyBatis、Mybatis笔记.MyBatis的核心配置,动态Mapper,动态SQL,表的关联及分页操作和缓存理解
Mybatis入門:
? Mybatis是一個非常優秀的持久層掛架(類似于Spring Data JPA).它內部封裝了通過JDBC訪問數據庫的操作,支持定制化SQL,存儲過程,高級映射
? 在IDEA中搭建MyBatis環境:
? 1.創建項目
? 2.在maven中導入mybatis所依賴的jar包
<!--Mybatis依賴--> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version> </dependency>? 3.創建MyBatis的核心配置XML文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--在Mybatis的核心配置文件中是有先后順序的--> <configuration><!--指定數據庫鏈接信息的位置--><properties resource="jdbc.properties" /><!--自定義別名--><typeAliases><!--typeAlias:定義單個別名package:自定義掃描包里面的pojo實體類,定義別名,默認別名(首字母小寫)--><!--<typeAlias alias="Book" type="com.mybatis.pojo.Book" />--><package name="com.mybatis.pojo" /></typeAliases><!--應用環境們 default默認--><environments default="development"><!--應用環境--><environment id="development"><!--事務管理器--><transactionManager type="JDBC"/><!--數據庫連接池--><dataSource type="POOLED"><property name="driver" value="${mysql.driverClass}"/><property name="url" value="${mysql.url}"/><property name="username" value="${mysql.username}"/><property name="password" value="${mysql.password}"/></dataSource></environment></environments><!--引入映射文件--><mappers><!--包掃描映射規則要求:要求接口文件名和映射文件名相同在包掃描中,需要在resources目錄中創建同名同目錄結構的文件,這樣才能掃描映射--><package name="com.mybatis.mapper"/></mappers> </configuration>? 4.創建數據庫配置properties文件,實體類,mapper接口和接口SQL映射的XML文件
###連接的驅動 mysql.driverClass=com.mysql.cj.jdbc.Driver ###連接的數據庫 mysql.url=jdbc:mysql://localhost:3306/servlet_zhenai?useSSL=true&serverTimezone=UTC ###用戶名 mysql.username=root ###密碼 mysql.password=root package com.mybatis.pojo;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;/*** @program: vip03SSM* @description: 實體類* @author: 高天樂* @create: 2020-08-15 19:43**/ @Data @NoArgsConstructor @AllArgsConstructor public class Book {private Integer id;private String author;private String name;private String createTime;private Double price;private Integer sales;private Integer stock; } package com.mybatis.mapper;import org.apache.ibatis.annotations.Param;import java.util.HashMap; import java.util.List;/*** @program: vip03SSM* @description: Book接口* @author: 高天樂* @create: 2020-08-15 19:52**/ public interface BookMapper {//查詢全部List findAll(); } <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mybatis.mapper.BookMapper"><select id="findAll" resultType="book">select * from web_book</select> </mapper>? 5.進行單元測試
MyBatis核心配置參數的設置、參數綁定
在Mybatis的核心配置文件中是有先后順序的
<properties resource="jdbc.properties" /> 指定數據庫連接信息的位置 resource:寫數據庫properties的配置文件 自定義別名 <typeAliases><!-- typeAlias:定義單個別名type:里對應實體類的全限定名alias:自定義別名不區分大小寫--><!--<typeAlias alias="Book" type="com.mybatis.pojo.Book" />--><!--package:定義多個別名.自定義掃描包里面的pojo實體類,定義別名,默認別名(首字母小寫)name:寫實體類包所在的地址--><package name="com.mybatis.pojo" /> </typeAliases> <environments default="development"> 應用環境們 default為默認環境 包含environment <environment id="development"> 應用環境 id為唯一標識 <transactionManager type="JDBC"/> 事務管理器 <dataSource type="POOLED"> 數據庫連接池 type里面可寫其他的數據源 如Druid <!--引入映射文件--><mappers><!--mapper 映射單個文件--><!--<mapper resource="" /> resource里寫SQL映射文件的地址 --><!--映射過個文件需要 package標簽包掃描映射規則要求:要求接口文件名和映射文件名相同在包掃描中,需要在resources目錄中創建同名同目錄結構的文件,這樣才能掃描映射--><package name="com.mybatis.mapper"/></mappers>動態mapper
<mapper namespace="com.mybatis.mapper.BookMapper"> namespace:傳遞接口的映射(命名空間,對應接口類的全限定名)| select標簽 | 對應SQL語句的查找 |
| update標簽 | 對應SQL語句的更新 |
| delete標簽 | 對應SQL語句的刪除 |
| insert標簽 | 對應SQL語句的添加 |
上面四種標簽里的屬性的作用
| id | 唯一表示.要和接口方法名對應 |
| parameterType | 方法中參數的傳遞類型(多個不同類型的參數,可以不寫) |
| resultType | 方法返回值的類型(沒有返回值可以不寫) |
| useCache | false:禁用二級緩存(對于變化頻率較高的SQL可以使用)…默認開啟 |
| flushCache | true:刷新緩存,默認就是true |
| resultMap | 下列單獨介紹 |
resultMap屬性
指定字段與屬性的對應映射關系 (當數據庫中的字段和實體類中的屬性映射不上時,通過resultMap來進行一一映射)
<resultMap id="baseResultMap" type="book"> id:自定義唯一標識,此id值用于對select元素resultMap屬性的引用 type:表示該resultMap的映射結果類型(實體類,如果沒有定義別名就寫類全限定名)resultMap里的子節點標簽:
? id標簽:id標簽只定義數據庫表里的主鍵字段
? result標簽:對應數據庫表里的字段
? association標簽:主要用于一對一的關聯映射操作 映射到實體類的某個 "復雜類型"屬性
? collection標簽:用來進行一對多的映射
總結一句話: resultMap標簽中的子標記有先后順序(將關聯查詢到的多條記錄映射到集合中)
| id標簽 | column屬性:對應數據庫表字段 property屬性:指定數據表字段名相對應的實體類屬性名 |
| result標簽 | column屬性:對應數據庫表字段 property屬性:指定數據表字段名相對應的實體類屬性名 |
| association標簽 | column屬性:對應數據庫表字段 property屬性:指定數據表字段名相對應的實體類屬性名 javaType屬性:屬性的類型 對應類的全限定名或別名 (association標簽里的子節點result標簽和上列一樣) |
| collection | property屬性:指定數據表字段名相對應的實體類屬性名 ofType:指定映射的集合屬性中pojo的類型 |
insert操作時主鍵自增:
| keyColumn | 指定數據庫表主鍵的字段 |
| keyProperty | 指定數據庫表字段對應的實體類屬性名 |
| userGeneratedKeys | true開啟主鍵回寫(自增) |
oracle不支持主鍵自增需要手動實現
<selectKey keyProperty="id" resultType="integer" order="AFTER">select last_insert_id() </selectKey>selectKey:返回主鍵值
keyProperty:pojo類中主鍵的屬性名
resultType:pojo類中主鍵屬性的類型
order:生成策略,指selectKey什么時候生成,AFTER表示之后生成
MySQL的自增原理:執行完SQL語句之后才生成
多參數查詢:
? 方法一: 根據作者和價格來進行查詢默認實現
? 接口方法
List<T> findByAuthorAndPrice(String author ,Double price);? 映射文件:
根據作者和價格來進行查詢根據默認實現 <select id="findByAuthorAndPrice" resultType="book">select * from web_book where author=#{param1} and price=#{param2} </select>? 方法一:
? 接口方法:根據作者和價格來進行查詢注解實現
List<T> findByAuthorAndPrice(@Param("author") String author , @Param("price") Double price);? 映射文件: 要注意–#{author}里的參數要和@Param(“author”)注解定義的參數寫的一樣
<!--根據作者和價格來進行查詢根據注解實現--> <select id="findByAuthorAndPrice" resultType="book">select * from web_book where author=#{author} and price=#{price} </select>模糊查詢的兩種方式
? 方式一: 使用${}拼接SQL語句
<select id="findByLikeName" parameterType="string" resultType="student" >select * from student where user_name like '%${username}%' </select>? 方式二:使用concat()
<select id="findByLikeName" parameterType="string" resultType="student" >select * from student where user_name like concat('%',#{username},'%') </select>SQL語句里的兩種傳值方式
| #{} | 表示占位符,會以?號的形式顯示,防止SQL注入 |
| ${} | 表示SQL拼接語句,會直接顯示出內容.(不安全) |
| 提議 | #{}可以防止SQL注入,盡量少用${} |
區間查詢:
在查詢時有需求進行區間查詢或在查詢價格時查詢比指定價格低或高的數據.在這里是不能直接是用 > < 號的.可以按以下進行書寫
| > | > |
| < | < |
| >= 或 <= | <![CDATA[>=]]> and <![CDATA[<=]]> |
動態SQL
1.標簽 判斷語句
<!--if標簽的應用--> <select id="findByStu" parameterType="string" resultType="student"><!--select * from Student where user_name=#{arg0} and password=#{arg1}-->select * from Student where 1=1<if test="userName != null and userName != ''">and user_name=#{userName}</if><if test="password != null and password != ''">and password=#{password}</if> </select>2. 輔助標簽,主要用于SQL的拼接
? where標簽作用: 解決where 1=1 的問題
? 如果where標簽后面的字符串是以and和or開頭的就移除它
<select id="findByStu1" parameterType="string" resultType="student"><!--select * from Student where user_name=#{arg0} and password=#{arg1}-->select * from Student<where><if test="userName != null and userName != ''">and user_name=#{userName}</if><if test="password != null and password != ''">and password=#{password}</if></where> </select>? set標簽: update student set user_name=?,password=?, where id=? 去除update拼接語句后面的最后一個逗號
<update id="updateByStu" parameterType="student">update Student<set><if test="user_name != null and user_name != ''">user_name=#{user_name},</if><if test="password != null and password != ''">password=#{password},</if></set>where id = #{id} </update>? trim標簽: where標簽和set標簽的功能都可以使用trim標簽替代
? trim里的屬性:
? prefix: 添加前綴
? suffix: 添加后綴
? prefixOverrides:去除前綴
? suffixOverrides:去出后綴
<update id="updateByStu1" parameterType="student">update Student<trim prefix="set" suffixOverrides=","><if test="user_name != null and user_name != ''">user_name=#{user_name},</if><if test="password != null and password != ''">password=#{password},</if></trim>where id=#{id} </update>3.類似java中的switch語句,用于多條件分支判斷
? 多條件匹配的邏輯就要使用多分支判斷標記
? 特征:
? choose標簽包裹when,otherwise標簽
? 注意:choose標簽中至少要有一個when標簽,0個或1個otherwise標簽 (當所有的when都不滿足條件時,執行otherwise)
? 需求: 查詢操作
? 1.當id有值時進行id查詢
? 2.當id沒有值是進行用戶名查詢
? 3.當id和用戶名都沒有值是,查詢無結果
4. 循環語句(重點掌握)
? collection:必填屬性,值為迭代循環的屬性名,傳遞的參數類型首字母小寫
? 傳遞參數為Map時,collection里填 _parameter,或者使用注解@Param()指定別名
? 列表和數組有默認的別名(list/array)
? item:變量名,值為迭代對象中取出的每一個值
? index:索引,如果是Map類型時,這個值為Map的key值
? open:循環開始的字符串
? close:循環結束的字符串
? separator:循環的分割符
5.用于構建變量
? 其主要用于模糊查詢當中
?
關聯操作
(resultMap里的屬性和子節點的屬性查看上文)
一對一:
理解:在任意一方添加對方的主鍵作為外鍵
<resultMap id="baseResult" type="orders"><result column="id" property="id" /><result column="number" property="number" /><result column="createtime" property="createtime" /><result column="note" property="note" /><!--一對一--><association property="user" column="user_id" javaType="user"><result column="username" property="username" /><result column="address" property="address" /></association> </resultMap><!--一對一查詢--><select id="selectFindByIdOrder" parameterType="integer" resultMap="baseResult"><!--select * from orders where id = #{id}-->select o.*,u.username,u.address from orders oinner join t_user uon o.user_id = u.idand o.id = #{id} </select>一對多:
理解:在"多"的一方添加"一"的一方的主鍵作為外鍵
<resultMap id="baseResult" type="orders"><result column="id" property="id" /><result column="number" property="number" /><result column="createtime" property="createtime" /><result column="note" property="note" /><!--一對一--><association property="user" column="user_id" javaType="user"><result column="username" property="username" /><result column="address" property="address" /></association><!--一對多--><collection property="orderDetails" ofType="orderDetail"><result property="items_num" column="items_num" /><result property="items_id" column="items_id" /></collection> </resultMap><!--多對多查詢--><select id="selectOrdersAndOrderDetail" parameterType="integer" resultMap="baseResult"><!--select o.*,d.items_id,d.items_num,u.username,u.addressfrom orders as o, orderdetail as d, t_user as uwhere o.id=d.orders_idand o.user_id = u.idand o.id = #{id}-->select o.*,d.items_id,d.items_num,u.username,u.addressfrom (orders o inner join orderdetail d on o.id = d.orders_id)inner join t_user uon u.id = o.user_idand o.id = #{id} </select>多對多:
1:n ---- user:orders
1:n ---- orders: orderDetail
1:1 ---- orderDetail:items
n:n ---- user:items
<resultMap id="userResult" type="user"><id property="id" column="id" /><result property="username" column="username" /><result property="address" column="address" /><collection property="orders" ofType="orders" ><result property="number" column="number" /><result property="createtime" column="createtime" /><collection property="orderDetails" ofType="orderDetail"><result property="items_id" column="items_id"/><result property="items_num" column="items_num" /><association property="items" javaType="items" ><result property="itemsName" column="itemsname" /></association></collection></collection></resultMap><select id="selectByIdOrdersAndTimes" parameterType="integer" resultMap="userResult" ><!--select o.*,d.items_id,d.items_num,d.orders_id,u.username,u.address,i.itemsnamefrom orders as o, orderdetail as d, t_user as u,items as iwhere o.id=d.orders_idand o.user_id = u.idand d.items_id = i.idand u.id = #{id}-->select o.*,d.items_id,d.items_num,d.orders_id,u.username,u.address,i.itemsnamefrom ((orders as o inner join orderdetail as d on o.id=d.orders_id)inner join t_user as u on o.user_id = u.id)inner join items as ion d.items_id = i.idand u.id = #{id}</select>Mybatis的緩存
sqlSession.clearCahe(); //強制清除緩存
緩存中的數據(內存中)
緩存的作用:
? 從緩存中查詢,減少了服務器的請求次數,提高了查詢的效率,解決了高并發系統的性能問題.
? Mybatis的緩存:一級緩存/二級緩存
一級緩存:
? 會話技術:cookie(客戶端) / session(服務端)
? mybatis的一級緩存的作用域是session(會話),
? myBatis默認開啟了一級緩存操作,并且是無法關閉的
? 執行過程:
? Mybatis執行查詢時,首先去緩存去查找,如果能找到數據則直接返回,如果沒有則執行SQL語句從數據庫中查詢
二級緩存:
? Mybatis的二級緩存是Mapper級別的緩存,不同的Mapper都有一個二級緩存,不同的Mapper之間的二級緩存是互不影響的
問題:
? Mybatis是如何區分不同的Mapper的二級緩存區域?
? namespace(命名空間),兩個Mapper相同的話存在相同的二級緩存區域里面
開啟二級緩存:在MyBatis核心配置中開啟 <settings><!--開啟二級緩存,全局開關,這里如果是關閉狀態,則在Mapper中開啟也沒用--><setting name="cacheEnabled" value="true"/> </settings>注意:
? Mybatis二級緩存需要將查詢結果映射的pojo實現序列化(Serializable)
實例類序列化的目的???
序列化就是對實例對象的狀態(State 對象屬性而不包括對象方法)進行通用編碼(如格式化的字節碼)并保存,以保證對象的完整性和可傳遞性。
簡而言之:序列化,就是為了在不同時間或不同平臺的JVM之間共享實例對象
在開發過程中推薦:
? Redis / Ehcache
Mybatis的分頁插件(pageHelper)
在核心配置中配置
<plugins><!--Mybatis的分頁配置--><plugin interceptor="com.github.pagehelper.PageInterceptor" /></plugins> /*** 分頁測試*/@Testpublic void findPageTest(){BookMapper mapper = sqlSession.getMapper(BookMapper.class);//PageHelper.startPage()配置分頁 注意:需要先指定分頁的條件,在執行查詢PageHelper.startPage(2, 10);//查詢數據List<Book> bookList = mapper.findPage();PageInfo<Book> pageInfo = new PageInfo(bookList,10);System.out.println("總記錄數:" + pageInfo.getTotal());System.out.println("總頁數:" + pageInfo.getPages());System.out.println("當前頁:" + pageInfo.getPageNum());System.out.println("當前導航頁碼數:" + pageInfo.getNavigatePages()); // ==10,自定義了10,默認為8List<Book> pageList = pageInfo.getList();for (Book book : pageList){System.out.println(book);}}以上為個人筆記總結,有錯誤或有待添加的地方請多多點評
總結
以上是生活随笔為你收集整理的认识MyBatis、Mybatis笔记.MyBatis的核心配置,动态Mapper,动态SQL,表的关联及分页操作和缓存理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P3369 (Splay树模板)
- 下一篇: 多目标优化——帕累托最优