一、MyBatis初次使用
2.1 環境搭建步驟
MyBatis 的 API : https://mybatis.org/mybatis-3/zh/getting-started.html
1.引入依賴包
2.準備核心配置件
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://123.57.206.19:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username=root
password=123456
mybatis.xml
在resources下定義MyBatis的配置文件,無固定名,但大部分人使用 resources/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">
<configuration><properties resource="db.properties"></properties>
<!-- <settings>-->
<!-- <setting name="logImpl" value="LOG4J"/>-->
<!-- </settings>--><typeAliases><!--給單個類起別名。 type:類型 alias:別名--><typeAlias type="com.test.pojo.Student" alias="student"></typeAlias><!--給指定包下所有類起別名。 別名=類名(不區分大小寫)--><package name="com.test.pojo"/></typeAliases><!-- 配置mybaits中數據庫連接環境--><environments default="mysql"><environment id="mysql"><!--配置myabtis中事務 和 JDBC 保持一致--><transactionManager type="JDBC"></transactionManager><!-- 配置連接數據庫的4個元素, 底層采用的是數據庫連接池的方式--><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><!--掃描mapper文件--><mappers><mapper resource="mapper/student.xml"></mapper></mappers>
</configuration>
3.書寫mapper文件
resources/**.xml
<?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: 代表xml的名稱,類似java包名-->
<mapper namespace="com.beiyou.dao.StudentDao"><!-- 查詢所有學生 List<Student> selectAll()--><!--select: 代表進行查詢操作。id: 之前的方法名稱,具有唯一性。resultType: 返回值類型。如果返回的是對象,直接書寫對象類型的的完整名。如果是集合,書寫的是集合的泛型parameterType: 參數類型,可以省略。--><select id="selectAll" resultType="com.beiyou.entity.Student" >select * from student</select></mapper>
非必需
<build><resources><resource><directory>src/main/java</directory><!--所在的目錄--><includes><!--.xml 文件都會掃描到,包括子目錄--><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources>
</build>
4.構建SqlSessionFactory。
從xml中創建SqlSessionFactory.
// 1. 解析掃碼 mybatis.xml 文件
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
// 2. 獲取sqlsession工廠對象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3. 獲得 sqlsession 對象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4. 執行sql語句
List<Student> students = sqlSession.selectList("com.beiyou.dao.StudentDao.selectAll");
// 打印結果
System.out.println(students);
是否彌補了JDBC的不足?
二、MyBatis 配置細節
2.1 log4j的使用
-
加入依賴
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
-
配置文件 log4j.properties
#定義全局日志級別調試階段推薦debug
log4j.rootLogger = error,stdout
#包級別日志
log4j.logger.test.a = debug### 輸出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.SimpleLayout### 輸出日志到文件=/logs/log.log ###
log4j.appender.logfile = org.apache.log4j.DailyRollingFileAppender
log4j.appender.logfile.File = /logs/log.log
log4j.appender.logfile.layout = org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
2.2 事務配置
transactionManager.type
?JDBC : 這個配置直接使用了 JDBC 的提交和回滾設施,它依賴從數據源獲得的連接來管理事務作用域。
MANAGED : 這個配置幾乎沒做什么。它從不提交或回滾一個連接,而是讓容器來管理事務的整個生命周期。
2.3 連接池配置
dataSource.type
? UNPOOLED : 這個數據源的實現會每次請求時打開和關閉連接.
? POOLED : 這種數據源的實現利用“池”的概念將 JDBC 連接對象組織起來,避免了創建新的連接實例時所必需的初始化和認證時間。 這種處理方式很流行,能使并發 Web 應用快速響應請求。
? JNDI : 這個數據源實現是為了能在如 EJB 或應用服務器這類容器中使用,容器可以集中或在外部配置數據源,然后放置一個 JNDI 上下文的數據源引用。
2.4 映射文件的加載方式
1.resource: 使用相對于類路徑的資源引用。
<mapper resource="AuthorMapper.xml"/>
2.url: 使用完全限定資源定位符(URL)
<mapper url="file:///D:/207/mybatis/src/main/resources/mapper/BlogMapper.xml"/>
3.class : 使用映射器接口實現類的完全限定類名
<mapper class="org.mybatis.builder.BlogMapper"/>
4.name : 將包內的映射器接口實現全部注冊為映射器
<mappers><package name="com.beuyou.dao"/>
</mappers>
2.5 實體類別名處理
<typeAliases><!--給單個類起別名。 type:類型 alias:別名--><typeAlias type="com.beiyou.entity.Student" alias="student"></typeAlias><!--給指定包下所有類起別名。 別名=類名(不區分大小寫)--><package name="com.beuyou.entity"/>
</typeAliases>
常見的 Java 類型內建的類型別名。它們都是不區分大小寫的
別名 | 映射的類型 |
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
2.6?外部屬性配置文件存儲數據庫信息
-
配置db.properties數據庫信息
driver=com.mysql.cj.jdbc.Driver
url=mysql://rm-bp169j3q9n43kxauzco.mysql.rds.aliyuncs.com:3306?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username=root123
password=Root_123
<properties resource="db.properties"></properties><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource>
三、Mapper文件配置
3.1 常用屬性
3.2 SQL 定義標簽
1. select
用于數據查詢操作,例:
<select id="selectUserInfo" parameterType="int" resultType="map">select * from user_info where id=#{keyId}
</select>
2. insert
用于數據保存操作,例:
<insert id="insertUserInfo" parameterType="map" useGeneratedKeys="true" keyProperty="keyId">insert into user_info (userName,userSex)values(#{userName},#{userSex})
</insert>
PS:keyProperty屬性可返回此條插入數據的主鍵值
3. update
用于數據更新操作,例:
<update id="updateUserInfo" parameterType="map">update user_infoset userName=#{userName}where id=#{keyId}
</update>
4. delete
用于數據刪除操作,例:
<delete id="selectUserInfo" parameterType="int">delete from user_info where id=#{keyId}
</delete>
5. resultMap
SQL返回與實體類映射關系信息,例
<resultMap id="userInfoMap" type="User"><result property="user_name" column="userName"/><result property="user_sex" column="userSex"/>
</resultMap>
<select id="selectUserInfo" parameterType="int" resultType="userInfoMap">selectuserName,userSexfrom user_info where id=#{keyId}
</select>
將數據表字段userName、userSex映射到實體類User的user_name、user_sex
6. sql
用于定義可重用的 SQL 代碼片段,以便在多個SQL語句中使用。 參數可以靜態地(在加載的時候)確定下來,并且可以在不同的 include 元素中定義不同的參數值。例:
<!-- 定義 -->
<sql id="userColumns"> ${alias}.userName,${alias}.userSex</sql>
<!-- 運用 -->
<select id="selectUserInfo" resultType="map">select<include refid="userColumns"><property name="alias" value="t1"/></include>,<include refid="userColumns"><property name="alias" value="t2"/></include>from user_info t1left join user_info_copy t2
</select>
3.3、SQL動態標簽
1. if
單個條件判斷,用以實現條件篩選,例:
<select id="selectUserInfo" parameterType="map" resultType="map">select * from user_info where 1=1<if test="userSex !=null and userSex !='' ">and userSex=#{userSex}</if><if test="userName !=null and userName !='' ">and userName like CONCAT('%',#{userName},'%')</if>
</select>
2. foreach
用于更新或保存數據時的批量操作,例:
<!-- userList為List<HashMap<String,Object>>類型數據 -->
insert into user_info(
userName,
userSex
)values
<foreach item="item" index="index" collection="userList" separator="," >
(
#{item.userName},
#{item.userSex}
)
</foreach>
<!-- userList為List<String>類型數據 -->
insert into user_info(
userName
)values
<foreach item="item" index="index" collection="userList" separator="," >
(
#{userName}
)
</foreach>
update user_info
set userAge=#{userAge}
where id in
<foreach collection="keyIds" index="index" item="item" separator="," open="(" close=")">
#{item}
</foreach>
3. choose/when/otherwise
用以實現條件的多種判斷,類似與if else,例:
<select id="selectUserInfo" parameterType="map" resultType="map">select * from user_info where 1=1<choose><when test="userFlag!=null and userFlag!='' and userFlag=='Y'">and id<=100</when><when test="userFlag!=null and userFlag!='' and userFlag=='N'">and id <=200</when><otherwise>and id<=300</otherwise></choose>
</select>
4. where
只會在子元素返回任何內容的情況下才插入 “WHERE” 子句,并且可以自動處理判斷條件語句返回的第一個and或or,例:
不使用where標簽時,若userSex為空,語法錯誤會報錯:
<select id="selectUserInfo" parameterType="map" resultType="map">select * from user_info where<if test="userSex !=null and userSex !='' ">userSex=#{userSex}</if><if test="userName !=null and userName !='' ">and userName like CONCAT('%',#{userName},'%')</if>
</select>
修改為:
<select id="selectUserInfo" parameterType="map" resultType="map">select * from user_info<where><if test="userSex !=null and userSex !='' ">userSex=#{userSex}</if><if test="userName !=null and userName !='' ">and userName like CONCAT('%',#{userName},'%')</if></where>
</select>
自動轉換為:select * from user_info where userName like ……
5. set
可以動態更新需要更新的列,忽略其它不更新的列,例:
<update id="updateUserInfo" parameterType="map">update user_info<set><if test="userName!= null and userName!=''">userName=#{userName},</if>userSex=#{userSex}</set>where id=#{keyId}
</update>
四、基于MyBatis的CURD操作
使用單元測試驗證
<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.6.0</version><scope>test</scope></dependency>
4.1 MyBatis查詢的三種方式
-
返回單個對象 selectOne
-
返回對象List集合 selectList
-
返回對象Map集合 selectMap
<select id="selectOne" resultType="student">select * from student where id=1
</select>
<select id="selectAll" resultType="student" >select * from student
</select>
<select id="selectMap" resultType="map">select * from student
</select>
4.2 MyBatis參數傳遞的三種方式
4.2.1 三種傳參
-
傳遞的是基本類型+String ,使用 param1
-
傳遞類型是對象,接受使用對象的 屬性名
-
傳遞的是map集合,接受時候使用map中的 key
<!-- 方法 Student selectOne(int id)-->
<!--param1:-->
<select id="selectOne" resultType="student" parameterType="int">select * from student where id = #{id}
</select>
<!-- 方法 Student selectOne(StudentQuery query)-->
<!--#{} 里面放的是對象屬性-->
<select id="selectOne2" resultType="student">select * from student where id = #{id} and name = #{name}
</select>
<!-- 方法 Student selectOne(Map map)-->
<!--#{} 里面放的是map的key-->
<select id="selectOne3" resultType="student">select * from student where id = #{a} and name = #{b}
</select>
// 【A】. 傳遞基本類型Student student = sqlSession.selectOne("test.c.selectOne", 2);// 打印System.out.println(student);// 【B】. 傳遞對象StudentQuery query = new StudentQuery();query.setId(2);query.setName("周星星");Student student = sqlSession.selectOne("test.c.selectOne2", query);//打印System.out.println(student);//【C】. 傳遞Map集合//id,name 一塊封裝到map集合Map<String,Object> map = new HashMap<>();map.put("a",2);map.put("b","周星星");Student student = sqlSession.selectOne("test.c.selectOne3", map);//打印System.out.println(student);
4.2.2 #和$區別:面試題
#:底層相當于占位符?
$:底層相當于字符串拼接
-
兩者相比,占位符的方式更加方便,可以有效的防止SQL注入。
-
預編譯
4.2.3 模糊查詢
<!-- 模糊查詢 -->
<select id="selectOne4" resultType="student">Student student = sqlSession.selectOne("test.c.selectOne4", "%敏%");select * from student where name like #{param1}Student student = sqlSession.selectOne("test.c.selectOne4", "敏");select * from student where name like concat('%',#{param1},'%')
</select>
4.2.4 Model對象字段名稱與數據庫不一致,使用resultMap指定
<select id="selectlike2" resultMap="usermap" >select * from user where email like concat('%',#{param1},'%')</select><resultMap id="usermap" type="User"><!--主鍵映射 使用id標簽propetry java中的類型名稱column 數據庫中的字段名--><id property="pwd" column="password"/></resultMap>
XML
4.2.5 include標簽
1、首先定義一個sql標簽,一定要定義唯一id。 <sql id="columns">id, title ,brief</sql>
2、然后通過id引用 <select id="selectOne" resultMap="productResultMap1" >select<include refid="columns"/>from product where id = 8</select>
XML
4.3 MyBatis完整DML全部操作
DML與DDL的含義:
1、DML(Data Manipulation Language)數據操作語言-數據庫的基本操作,SQL中處理數據等操作統稱為數據操縱語言,簡而言之就是實現了基本的“增刪改查”操作。包括的關鍵字有:select、update、delete、insert、merge
2、DDL(Data Definition Language)數據定義語言-用于定義和管理 SQL 數據庫中的所有對象的語言,對數據庫中的某些對象(例如,database,table)進行管理。包括的關鍵字有:
create、alter、drop、truncate、comment、grant、revoke
4.3.1 CUD
【1】新增
<!-- 方法 int insert(Student student)-->
<insert id="insert">insert into student (name,age) values (#{name},#{age})
</insert>
Student student = new Student();
student.setName("鄧超");
student.setAge(38);
int rowNum = sqlSession.insert("com.beiyou.dao.StudentMapper.insert", student);
//MyBatis 默認不自動提交事務,所以 增刪改功能 需要我們手動提交事務
sqlSession.commit();
【2】修改
<!-- 傳統方法 int update(Student student)-->
<update id="update">update student set name = #{name},age = #{age} where id = #{id}
</update>
Student student = new Student();
student.setName("鄧超111");
student.setAge(380);
student.setId(6);
int rowNum = sqlSession.update("com.beiyou.dao.StudentMapper.update", student);
//MyBatis 默認不自動提交事務,所以 增刪改功能 需要我們手動提交事務
sqlSession.commit();
【3】刪除
<!-- 傳統方法 int delete(int id)-->
<delete id="delete">delete from student where id = #{param1}
</delete>
int rowNum = sqlSession.delete("test.d.delete", 6);
//MyBatis 默認不自動提交事務,所以 增刪改功能 需要我們手動提交事務
sqlSession.commit();
4.3.2 設置SqlSession提交
MyBatis 默認不自動提交事務,所以 增刪改功能 需要我們手動提交事
【1】SqlSession sqlSession = factory.openSession(true);
【2】sqlSession.commit();
4.4 擴展
4.4.1 接口編程
package com.beiyou.dao;public interface UserDao {List<User> selectAll();
}
<mapper namespace="com.beiyou.dao.UserDao"><select id="selectAll" resultType="user" >select * from 202_user</select></mapper>
UserDao mapper = sqlSession.getMapper(UserDao.class);mapper.selectAll();
4.4.2通過表達式,實現多場景多條件組合查詢
<select id="select" resultMap="productResultMap1">select id, categoryId,title ,brief from 202_product<where><if test="id != null">and id = #{id}</if><if test="ids != null">and id in<foreach collection="ids" item="item" open="(" close=")" separator=",">#{item}</foreach></if><if test="categoryId != null">and categoryId= #{categoryId}</if><if test="categoryIds != null">and categoryId in<foreach collection="categoryIds" item="item" open="(" close=")" separator=",">#{item}</foreach></if><if test="name != null">and title like concat('%',#{name},'%')</if></where></select>
@Testpublic void selectQuery() throws IOException {ProductDao productDao = sqlSession.getMapper(ProductDao.class);ProductQuery query = new ProductQuery();//query.setId(40);//query.setCategoryId(1);//query.setName("梨38");//query.setIds(new Integer[]{38,42,50,51,52});query.setCategoryIds(new Integer[]{3});List<Product> products = productDao.select(query);System.out.println(products);}
4.4.3 注解
<mapper class="com.beiyou.dao.UserDao"/>
public interface UserDao {@Select("select * from 202_user limit 1")User select(); //insert into order_item (productId,productName,productImg,price,qty,orderId) values (1,2,3),(2,3,4).....@Insert("<script> " +"insert into " +" order_item (productId,productName,productImg,price,qty,orderId) " +"values " +"<foreach collection='items' item='item' separator=','> "+"(#{item.productId},#{item.productName},#{item.productImg},#{item.price},#{item.qty},#{item.orderId})"+"</foreach> </script>" )int insertAll(List<OrderItemEntity> items);@Select("<script> " +"select * from order_item where 1 = 1 " +"<if test='id != null'>" +" and id = #{id} "+"</if> "+"<if test='orderId != null'>" +" and orderId = #{orderId} "+"</if> "+"<if test='orderIds != null'>" +" and orderId in "+"<foreach collection='orderIds' open='(' close=')' item='item' separator=','> "+"#{item}"+"</foreach> "+"</if> "+"</script>" )@Results(id="studentMap",value={ @Result(column=“id”, property=“id”, jdbcType=JdbcType.INTEGER, id=true), @Result(column=“name”, property=“name”, jdbcType=JdbcType.VARCHAR), @Result(column=“class_id”, property=“classId”, jdbcType=JdbcType.INTEGER)})List<OrderItemEntity> select(OrderItemQueryDto queryDto);}
4.4.4 SelecKey標簽使用
Mybatis之useGeneratedKeys和selectKey的基本用法與區別_mybatis selectkey usegeneratedkeys_poppyCL的博客-CSDN博客
一、useGeneratedKeys數據庫本身具備主鍵自動增長的功能,才能使用useGeneratedKeysoracle不支持true<insert id="insert" useGeneratedKeys="true" keyProperty="idColName"> insert into tableName (colName) values (#{colVal,jdbc..._mybatis selectkey usegeneratedkeys
https://blog.csdn.net/poppyCL/article/details/103347385
<insert id="insert" parameterType="UserEntity">insert user (email,password) values (#{email},#{pwd})<selectKey keyProperty="id" resultType="integer" keyColumn="newId" order="AFTER">SELECT LAST_INSERT_ID() as newId</selectKey></insert><selectKey resultType="integer" keyColumn="newId" keyProperty="id" order="BEFORE">SELECT (max(id)+1) as newId from 205_category
</selectKey>
注解版
@SelectKey(statement="SELECT last_insert_id", keyProperty="id", before=false, resultType=Long.class)
五 MyBatis 高級關系查詢
-
一個會員只屬于一個詳情 ==> 會員對詳情表是一對一關系
-
不管是一對一還是多對多,都要使用<resultMap> ,屬性有id 和type
-
一對一中,<resultMap>內要用<association>來映射復雜對象,屬性有 :
-
(property和javaType) ==> 嵌套結果
-
(property, column, select) ==> 嵌套查詢
-
一對多中,<resultMap>內要用<collection>來映射復雜對象,屬性有property和ofType
-
注意防范<resultMap>和<association>或<collection>中字段名沖突的問題!
5.1 一對一
<resultMap> <association>
<association> 元素,通常可以配置一下屬性
- propery:指定映射到實體類對象屬性,與表字段一一對應
- column:指定表中對應的字段
- javaType:指定映射到實體對象屬性的類型
- select:指定引入嵌套查詢的子SQL語句,該屬性用于關聯映射中的嵌套查詢
- fetchType:指定在關聯查詢時是否啟用延遲加載。FetchType屬性有lazy和eager(實時)兩個屬性值,默認值為lazy
默認為lazy(默認關聯映射延遲加載)
create table 202_user( id int unsigned auto_increment, tel varchar(50) not null, password varchar(32) not null, primary key(id));
CREATE TABLE `202_userinfo` (`id` int NOT NULL AUTO_INCREMENT COMMENT '唯一標識',`name` varchar(100) NOT NULL COMMENT '姓名',`sex` varchar(100) DEFAULT NULL COMMENT '性別',PRIMARY KEY (`id`)
)
實體對象
@Data public class User { private Integer id; private String tel; private String password; private UserInfo userinfo;}public class UserInfo { private Integer id; private String name; private String sex; private Integer age;
}
UserMapper.xml
<?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.beiyou.dao.UserDao2"><resultMap id="usermap" type="com.beiyou.model.User"><id property="id" column="id"/><result property="tel" column="tel"/><result column="password" property="password"/><association property="userInfo" javaType="com.beiyou.model.UserInfo"><id property="id" column="id"/><result property="name" column="name"/><result property="sex" column="sex"/></association></resultMap><select id="one2one" resultMap="usermap" >select *from `202_user` uleft join `202_userinfo` uion u.id = ui.userId</select><resultMap id="userMap" type="com.beiyou.model.User"><id column="id" property="id"/><result column="tel" property="tel"/><result column="password" property="password"/><association property="userInfo" column="Id" fetchType="lazy" javaType="com.beiyou.model.UserInfo"select="selectUserinfo"><id property="id" column="id"/> bug 必須書寫<result property="name" column="name"/><result property="sex" column="sex"/></association></resultMap><select id="lazyone2one" resultMap="usermap2">select * from 202_user</select><select id="selectName" resultType="com.beiyou.model.UserInfo">select * from 202_userinfo where userId = #{id}</select>
</mapper>
UserDao.java
public interface UserDao {User one2one(String name);User lazyone2one(String name);
}
5.2 一對多
<resultMap> <collection>
CREATE TABLE `202_address` (`id` int NOT NULL AUTO_INCREMENT COMMENT '唯一id',`userId` int NOT NULL COMMENT '用戶編號',`province` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '省',`city` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '市',`address` varchar(100) DEFAULT NULL COMMENT '詳細地址',PRIMARY KEY (`id`)
)
<resultMap id="userMap" type="com.beiyou.model.User"><id column="id" property="id"/><result column="tel" property="tel"/><result column="password" property="password"/><association property="userInfo" column="Id" fetchType="lazy" javaType="com.beiyou.model.UserInfo"select="selectUserinfo"><id property="id" column="id"/><result property="name" column="name"/><result property="sex" column="sex"/></association><collection property="addresses" column="id" fetchType="lazy" javaType="java.util.ArrayList"ofType="com.beiyou.model.Address" select="selectAddress" ><id property="id" column="id"/><result property="province" column="province"/><result property="city" column="city"/><result property="county" column="county"/><result property="address" column="address"/></collection>
</resultMap><select id="selectAddr" resultType="com.beiyou.model.Address">select * from 202_address where userId = #{userId}</select>
使用Mapper注解,實現一對一和一對多關系查詢
@Results(id="userMap", value = {@Result(column = "id", property = "id", id = true),@Result(column = "tel", property = "tel"),@Result(column = "password", property = "password"),@Result(property = "userInfo", column = "id",one = @One(select = "selectUserinfo",fetchType = FetchType.LAZY)), 可以不用寫具體映射,但是用xml的時候,必須寫@Result(column = "id", property = "addresses" ,many = @Many(select = "selectAddress",fetchType = FetchType.LAZY))})}@Select("select * from 202_user u where u.id = #{id}")List<User> layeOne2One(int id);@Select("select * from 202_address where userId = #{id}")List<Address> selectAddress(Integer id);
測試代碼
@Testpublic void test(){UserMapper2 dao = sqlSession.getMapper(UserMapper2.class);List<User> users = dao.queryUserAll();}
Java
六 MyBatis緩存機制
mybatis.xml
<settings><setting name="cacheEnabled" value="true"/> //開啟全局的二級緩存</settings>
//清空緩存數據@Options(flushCache = Options.FlushCachePolicy.TRUE)@Select(" select * from 202_user where id= 46")User one();
6.1 一級緩存
一級緩存作用域是sqlsession級別的,同一個sqlsession中執行相同的sql查詢(相同的sql和參數),第一次會去查詢數據庫并寫到緩存中,第二次從一級緩存中取。
一級緩存是基于 PerpetualCache 的 HashMap 本地緩存,默認打開一級緩存。
6.1.1何時清空一級緩存
如果中間sqlSession去執行commit操作(執行插入、更新、刪除),則會清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。
一級緩存時執行commit,close,增刪改等操作,就會清空當前的一級緩存;當對SqlSession執行更新操作(update、delete、insert)后并執行commit時,不僅清空其自身的一級緩存(執行更新操作的效果),也清空二級緩存(執行commit()的效果)。
6.1.2一級緩存無過期時間,只有生命周期
MyBatis在開啟一個數據庫會話時,會創建一個新的SqlSession對象,SqlSession對象中會有一個Executor對象,Executor對象中持有一個PerpetualCache對象。當會話結束時,SqlSession對象及其內部的Executor對象還有PerpetualCache對象也一并釋放掉。
6.2 二級緩存
它指的是Mybatis中SqlSessionFactory對象的緩存。由同一個SqlSessionFactory對象創建的SqlSession共享其緩存。
同一個工廠生產的sqlsession,批次號相同.
二級緩存是 mapper 映射級別的緩存,多個 SqlSession 去操作同一個 Mapper 映射的 sql 語句,多個SqlSession 可以共用二級緩存,二級緩存是跨 SqlSession 的。
6.2.1 二級緩存何時存入
在關閉sqlsession后(close或commit),才會把該sqlsession一級緩存中的數據添加到namespace的二級緩存中。
開啟了二級緩存后,還需要將要緩存的pojo實現Serializable接口,為了將緩存數據取出執行反序列化操作,因為二級緩存數據存儲介質多種多樣,不一定只存在內存中,有可能存在硬盤中
6.2.2二級緩存有過期時間
每當存取數據的時候,都有檢測一下cache的生命時間,默認是1小時,如果這個cache存活了一個小時,那么將整個清空一下.
6.2.3 執行流程
當 Mybatis 調用 Dao 層查詢數據庫時,先查詢二級緩存,二級緩存中無對應數據,再去查詢一級緩存,一級緩存中也沒有,最后去數據庫查找。
SqlSessionFactory級別緩存,會話工廠級別SqlSession s1 = sf.openSession();SqlSession s2 = sf.openSession();SqlSession s3 = sf.openSession();System.out.println(s1);System.out.println(s2);System.out.println(s3);開發者必須自己配置二級緩存二級緩存是人工開啟的,需要在XxxxMapper.xml 文件中加入如下開啟方法一<cache eviction="FIFO" flushInterval="60000" size="5120" readOnly="true" /><select id="queryAll" resultType="book" useCache="false"> 默認使用緩存,填寫false此操作不讓緩存select * from book</select>方法二@CacheNamespace(eviction = FifoCache.class, flushInterval = 60000, size = 1024, readWrite = true)public interface BookMapper {@Select("select * from book") @Options(useCache = true)public List<Book> queryAll();@Select("select * from book where id = #{id}")public Book queryById(int id);} 注意:使用緩存時,最好給實體類序列化。
Java
Student.java
@Data
public class Student implements Serializable {private int id;private String name;private int age;private double money;private String info;
}
Plain Text
StudentMapper.java
@CacheNamespace
public interface StudentMapper {@Select("select * from t_student")@Options(useCache = true) //開啟或關閉二級緩存public List<Student> page();@Select("select * from t_student where id = #{id}")@Options(useCache = true)public Student queryById(int id);
}
Java
@Test
public void t5() {var session = sf.openSession();var sm = session.getMapper(StudentMapper.class);System.out.println(sm.page());System.out.println(sm.page());System.out.println(sm.page());System.out.println(sm.page());System.out.println("---------------------------");System.out.println(sm.queryById(5));session.commit();//將當前會話的查詢,保存到二級緩存中,System.out.println(sm.queryById(5));System.out.println(sm.queryById(5));System.out.println(sm.queryById(5));System.out.println("----------------------");var s2 = sf.openSession();var sm2 = s2.getMapper(StudentMapper.class);System.out.println(sm2.queryById(5));
}
Plain Text
六 常見問題
1.MySQL連接數據庫時,添加語句:“allowMultiQueries=true”的作用:
-
可以在sql語句后攜帶分號,實現多語句執行。
-
可以執行批處理,同時發出多個SQL語句。