MyBatis學習(二)
一、MyBatis執行SQL的兩種方式:SqlSession和Mapper介面
1. 用 Mapper 介面傳送 SQL
PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
personMapper.insertPerson(person);
通過 SqlSession 的 getMapper 方法來獲取一個 Mapper 介面,就可以呼叫它的方法了。因為 SQL對映 檔案或者介面註解定義的 SQL 都可以通過“類的全限定名+方法名”查詢,所以 MyBatis 會啟用對應的 SQL 進行執行,並返回結果。
例項:
package com.wangxing.mybatis.test;
import com.wangxing.mybatis.bean.Person;
import com.wangxing.mybatis.mapper.PersonMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.util.List;
public class TestMain {
public static void testInsertPerson(){
//定義SqlSession物件
SqlSession sqlSession=null;
try {
//通過SqlSessionFactoryBuilder類建立出SqlSessionFactory物件
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
//從SqlSessionFactory中取得一個SqlSession物件
sqlSession=sqlSessionFactory.openSession();
//通過得到資料訪問介面物件呼叫insertPerson方法
PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
Person person=new Person();
person.setPername("zhangsan");
person.setPerage(23);
person.setPeraddress("西安");
personMapper.insertPerson(person);
//提交sqlsession
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
}finally{
sqlSession.close();
}
}
public static void testUpdatePerson(){
//定義SqlSession物件
SqlSession sqlSession=null;
try {
//通過SqlSessionFactoryBuilder類建立出SqlSessionFactory物件
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
//從SqlSessionFactory中取得一個SqlSession物件
sqlSession=sqlSessionFactory.openSession();
//通過得到資料訪問介面物件呼叫insertPerson方法
PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
Person person=new Person();
person.setPerid(1);
person.setPername("lisi");
person.setPerage(24);
person.setPeraddress("beijing");
personMapper.updatePerson(person);
//提交sqlsession
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
}finally{
sqlSession.close();
}
}
public static void testSelectPersonById(){
//定義SqlSession物件
SqlSession sqlSession=null;
try {
//通過SqlSessionFactoryBuilder類建立出SqlSessionFactory物件
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
//從SqlSessionFactory中取得一個SqlSession物件
sqlSession=sqlSessionFactory.openSession();
//通過得到資料訪問介面物件呼叫insertPerson方法
PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
Person person=personMapper.selectPersonById(1);
//提交sqlsession
sqlSession.commit();
System.out.println(person.getPerid()+"\t"+person.getPername());
}catch (Exception e){
e.printStackTrace();
}finally{
sqlSession.close();
}
}
public static void testSelectPerson(){
//定義SqlSession物件
SqlSession sqlSession=null;
try {
//通過SqlSessionFactoryBuilder類建立出SqlSessionFactory物件
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
//從SqlSessionFactory中取得一個SqlSession物件
sqlSession=sqlSessionFactory.openSession();
//通過得到資料訪問介面物件呼叫insertPerson方法
PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
List<Person> personlist=personMapper.selectPerson();
//提交sqlsession
sqlSession.commit();
System.out.println("personlist.size----"+personlist.size());
}catch (Exception e){
e.printStackTrace();
}finally{
sqlSession.close();
}
}
public static void testDeletePerson(){
//定義SqlSession物件
SqlSession sqlSession=null;
try {
//通過SqlSessionFactoryBuilder類建立出SqlSessionFactory物件
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
//從SqlSessionFactory中取得一個SqlSession物件
sqlSession=sqlSessionFactory.openSession();
//通過得到資料訪問介面物件呼叫insertPerson方法
PersonMapper personMapper=sqlSession.getMapper(PersonMapper.class);
personMapper.deletePersonById(1);
//提交sqlsession
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
}finally{
sqlSession.close();
}
}
public static void main(String[] args) {
//測試新增使用者資訊
//testInsertPerson();
//測試修改使用者資訊
//testUpdatePerson();
//測試根據id查詢使用者資訊
//testSelectPersonById();
//測試查詢所有使用者資訊
//testSelectPerson();
//測試根據id刪除使用者資訊
testDeletePerson();
}
}
2.SqlSession 傳送 SQL
通過SqlSession物件的
int insert(“資料訪問介面的包名+介面名+方法名” , 資料訪問介面的方法的引數);
int update(“資料訪問介面的包名+介面名+方法名” , 資料訪問介面的方法的引數);
int delete(“資料訪問介面的包名+介面名+方法名” , 資料訪問介面的方法的引數);
<T> selectOne(“資料訪問介面的包名+介面名+方法名” , 資料訪問介面的方法的引數);
List<T> selectList(“資料訪問介面的包名+介面名+方法名” , 資料訪問介面的方法的引數);
.......
例項:
package com.wangxing.mybatis.test;
import com.wangxing.mybatis.bean.Person;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.util.List;
public class TestMain {
public static void testInsertPerson(){
SqlSession sqlSession=null;
try{
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
sqlSession=sqlSessionFactory.openSession();
Person person=new Person();
person.setPername("zhangsan");
person.setPerage(23);
person.setPeraddress("xian");
sqlSession.insert("com.wangxing.mybatis.mapper.PersonMapper.insertPerson",person);
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
public static void testUpdatePerson(){
SqlSession sqlSession=null;
try{
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
sqlSession=sqlSessionFactory.openSession();
Person person=new Person();
person.setPerid(1);
person.setPername("zhangsanfeng");
person.setPerage(123);
person.setPeraddress("wudang");
sqlSession.update("com.wangxing.mybatis.mapper.PersonMapper.updatePerson",person);
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
public static void testSelectPersonById(){
SqlSession sqlSession=null;
try{
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
sqlSession=sqlSessionFactory.openSession();
Person person=(Person)sqlSession.selectOne("com.wangxing.mybatis.mapper.PersonMapper.selectPersonById",1);
sqlSession.commit();
System.out.println(person.getPerid()+"\t"+person.getPername());
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
public static void testSelectPerson(){
SqlSession sqlSession=null;
try{
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
sqlSession=sqlSessionFactory.openSession();
List<Person> perlist=sqlSession.selectList("com.wangxing.mybatis.mapper.PersonMapper.selectPerson");
sqlSession.commit();
System.out.println("perlist.size=="+perlist.size());
Person person=perlist.get(0);
System.out.println(person.getPerid()+"\t"+person.getPername());
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
public static void testDeletePerson(){
SqlSession sqlSession=null;
try{
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
sqlSession=sqlSessionFactory.openSession();
sqlSession.delete("com.wangxing.mybatis.mapper.PersonMapper.deletePersonById",1);
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
public static void main(String[] args) {
//測試新增使用者資訊
//testInsertPerson();
//測試修改使用者資訊
//testUpdatePerson();
//測試根據id查詢使用者資訊
//testSelectPersonById();
//測試查詢所有使用者資訊
//testSelectPerson();
//測試根據id刪除使用者資訊
testDeletePerson();
}
}
3.對比兩種傳送 SQL 方式
上面分別展示了 MyBatis 存在的兩種傳送 SQL 的方式,一種用 SqlSession 直接傳送,另外一種通過 SqlSession 獲取 Mapper 介面再傳送。建議採用 SqlSession 獲取 Mapper 的方式,理由如下:
(1) 使用 Mapper 介面程式設計可以消除 SqlSession 帶來的功能性程式碼,提高可讀性,而 SqlSession 傳送 SQL,需要一個 SQL id 去匹配 SQL,比較晦澀難懂。
(2) 使用Mapper.selectPersonById(1)方式,IDE會提示錯誤和校驗,而使用 sqlSession.selectOne(“com.wangxing.mybatis.mapper.PersonMapper.selectPersonById”,1)語法,只有在執行中才能知道是否會產生錯誤。
目前使用Mapper介面程式設計已成為主流,尤其在Spring 中運用MyBatis 時,Mapper 介面的使用就更為簡單,所以本教程使用Mapper 介面傳送SQL語句並執行的方式。
二、MyBatis 的工作原理
下面對圖中的每步流程進行說明。
1)讀取 MyBatis 配置檔案:mybatis-config.xml 為 MyBatis 的全域性配置檔案,配置了 MyBatis 的執行環境等資訊,例如資料庫連線資訊。
2)載入SQL對映檔案。對映檔案即 SQL 對映檔案,該檔案中配置了運算元據庫的 SQL 語句,需要在 MyBatis 配置檔案 mybatis-config.xml 中載入。mybatis-config.xml 檔案可以載入多個對映檔案,每個檔案對應資料庫中的一張表。
3)構造會話工廠:通過 MyBatis 的環境等配置資訊構建會話工廠 SqlSessionFactory。
4)建立會話物件:由會話工廠建立 SqlSession 物件,該物件中包含了執行 SQL 語句的所有方法。
5)Executor 執行器:MyBatis 底層定義了一個 Executor 介面來運算元據庫,它將根據 SqlSession 傳遞的引數動態地生成需要執行的 SQL 語句,同時負責查詢快取的維護。
6)MappedStatement 物件:在 Executor 介面的執行方法中有一個 MappedStatement 型別的引數,該引數是對對映資訊的封裝,用於儲存要對映的 SQL 語句的 id、引數等資訊。
7)輸入引數對映:輸入引數型別可以是 Map、List 等集合型別,也可以是基本資料型別和 POJO 型別。輸入引數對映過程類似於 JDBC 對 preparedStatement 物件設定引數的過程。
8)輸出結果對映:輸出結果型別可以是 Map、 List 等集合型別,也可以是基本資料型別和 POJO 型別。輸出結果對映過程類似於 JDBC 對結果集的解析過程。
注意:Executor 執行器執行SQL語句時,是根據SQL對映檔案中對應元素的<insert><update><delete><select>
的id屬性值去選擇對應的sql語句,由於SQL對映檔案中對應元素的<insert><update><delete><select>
的id屬性值是資料訪問介面的方法名,所以資料訪問介面中的方法是不能過載的。
三、MyBatis的核心元件:SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession和SQL Mapper
(1)SqlSessionFactoryBuilder(構造器)
SqlSessionFactoryBuilder(構造器):它會根據MyBati核心配置或者程式碼來生成 SqlSessionFactory,採用的是分步構建的 Builder 模式。
1.1.SqlSessionFactoryBuilder通過根據MyBati核心配置【mybatis-config.xml】建立SqlSessionFactory
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置引入資料庫連結字串的資原始檔 -->
<properties resource="mydate.properties"></properties>
<!-- 配置mybatis預設的連線資料庫的環境 -->
<environments default="development">
<environment id="development">
<!-- 配置事務管理器 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置資料來源 -->
<dataSource type="POOLED">
<property name="driver" value="${mydriver}"/>
<property name="url" value="${myurl}"/>
<property name="username" value="${myusername}"/>
<property name="password" value="${mypassword}"/>
</dataSource>
</environment>
</environments>
<!-- 配置MyBatis資料訪問介面的SQL對映檔案路徑 -->
<mappers>
<mapper resource="PersonMapper.xml"></mapper>
</mappers>
</configuration>
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(“mybatis-config.xml”));
1.2.SqlSessionFactoryBuilder通過使用程式碼建立 SqlSessionFactory
程式碼如下所示。
public SqlSessionFactory getSqlSessionFactory (){
// 資料庫連線池資訊
PooledDataSource dataSource = new PooledDataSource();
dataSource.setDriver("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword ("123456");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setDefeultAutoCommit(false);
// 採用 MyBatis 的 JDBC 事務方式
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment ("development", transactionFactory, dataSource);
// 建立 Configuration 物件
Configuration configuration = new Configuration(environment);
// 加入一個對映器
configuration.addMapper(RoleMapper.class);
//使用 SqlSessionFactoryBuilder 構建 SqlSessionFactory
SqlSessionFactory SqlSessionFactory =
new SqlSessionFactoryBuilder().build(configuration);
return SqlSessionFactory;
}
注意程式碼中的註釋,它和 XML 方式實現的功能是一致的,只是方式不太一樣而已。但是程式碼冗長,如果發生系統修改,那麼有可能需要重新編譯程式碼才能繼續,所以這不是一個很好的方式,一般不推薦大家使用。除非有特殊的需要,比如在配置檔案中,需要配置加密過的資料庫使用者名稱和密碼,需要我們在生成 SqlSessionFactory 前解密為明文的時候,才會考慮使用這樣的方式。
(2)SqlSessionFactory(工廠介面)
SqlSessionFactory(工廠介面):依靠它來生成 SqlSession,使用的是工廠模式。
SqlSession sqlSession=SqlSessionFactory物件.openSession();
(3)SqlSession(會話)
SqlSession(會話):一個既可以傳送 SQL 執行返回結果,也可以獲取 Mapper 的介面。在現有的技術中,一般我們會讓其在業務邏輯程式碼中“消失”,而使用的是 MyBatis 提供的 SQL Mapper 介面程式設計技術,它能提高程式碼的可讀性和可維護性。
在 MyBatis 中有兩個實現類,DefaultSqlSession 和 SqlSessionManager。
DefaultSqlSession 是單執行緒使用的,而 SqlSessionManager 在多執行緒環境下使用。
傳送 SQL 執行返回結果
int insert(“資料訪問介面的包名+介面名+方法名” , 資料訪問介面的方法的引數);
int update(“資料訪問介面的包名+介面名+方法名” , 資料訪問介面的方法的引數);
int delete(“資料訪問介面的包名+介面名+方法名” , 資料訪問介面的方法的引數);
<T> selectOne(“資料訪問介面的包名+介面名+方法名” , 資料訪問介面的方法的引數);
List<T> selectList(“資料訪問介面的包名+介面名+方法名” , 資料訪問介面的方法的引數);
.......
獲取 Mapper 的介面
資料訪問介面物件=SqlSession物件.getMapper(資料訪問介面的反射物件);
(4)SQL Mapper(對映器)
SQL Mapper(對映器):MyBatis 新設計存在的元件,它由一個 Java 介面和 XML 檔案(或註解)構成,需要給出對應的 SQL 和對映規則。它負責傳送 SQL 去執行,並返回結果。
SQL Mapper(對映器)=資料訪問介面+SQL對映檔案/註解,負責傳送 SQL 去執行,並返回結果。
4.1.資料訪問介面+SQL對映檔案
資料訪問介面
package com.wangxing.mybatis.mapper;
import com.wangxing.mybatis.bean.Person;
import java.util.List;
public interface PersonMapper {
/**
* 新增資料
* @param person
* @return
*/
boolean insertPerson(Person person);
/**
* 修改資料
* @param person
* @return
*/
boolean updatePerson(Person person);
/**
* 刪除資料
* @return
*/
boolean deletePersonById(int perid);
/**
* 根據id查詢資料
* @return
*/
Person selectPersonById(int perid);
/**
* 查詢所有資料
* @return
*/
List<Person> selectPerson();
}
SQL對映檔案
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wangxing.mybatis.mapper.PersonMapper">
<insert id="insertPerson" parameterType="com.wangxing.mybatis.bean.Person">
insert into t_person values (null,#{pername},#{perage},#{peraddress});
</insert>
<update id="updatePerson" parameterType="com.wangxing.mybatis.bean.Person">
update t_person set per_name=#{pername},per_age=#{perage},per_address=#{peraddress} where per_id=#{perid};
</update>
<resultMap id="personMap" type="com.wangxing.mybatis.bean.Person">
<id column="per_id" property="perid"></id>
<result column="per_name" property="pername"></result>
<result column="per_age" property="perage"></result>
<result column="per_address" property="peraddress"></result>
</resultMap>
<select id="selectPersonById" parameterType="int" resultMap="personMap">
select * from t_person where per_id=#{perid};
</select>
<select id="selectPerson" resultMap="personMap">
select * from t_person;
</select>
<delete id="deletePersonById" parameterType="java.lang.Integer">
delete from t_person where per_id=#{perid};
</delete>
</mapper>
4.2.資料訪問介面+註解
PersonMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wangxing.mybatis.mapper.PersonMapper">
<resultMap id="perMap" type="com.wangxing.mybatis.bean.Person">
<id column="per_id" property="perid"></id>
<result column="per_name" property="pername"></result>
<result column="per_age" property="perage"></result>
<result column="per_address" property="peraddress"></result>
</resultMap>
</mapper>
資料訪問介面帶註解
package com.wangxing.mybatis.mapper;
import com.wangxing.mybatis.bean.Person;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface PersonMapper {
/**
* 新增資料
* @param person
* @return
*/
@Insert("insert into t_person values (null,#{pername},#{perage},#{peraddress});")
boolean insertPerson(Person person);
/**
* 修改資料
* @param person
* @return
*/
@Update("update t_person set per_name=#{pername},per_age=#{perage},per_address=#{peraddress} where per_id=#{perid};")
boolean updatePerson(Person person);
/**
* 刪除資料
* @return
*/
@Delete("delete from t_person where per_id=#{perid};")
boolean deletePersonById(int perid);
/**
* 根據id查詢資料
* @return
*/
@Results(id = "personMap" , value = {
@Result(column = "per_id",property = "perid"),
@Result(column = "per_name",property = "pername"),
@Result(column = "per_age",property = "perage"),
@Result(column = "per_address",property = "peraddress"),
})
@Select("select * from t_person where per_id=#{perid};")
Person selectPersonById(int perid);
/**
* 查詢所有資料
* @return
*/
@Select("select * from t_person;")
@ResultMap("perMap")
List<Person> selectPerson();
}
注意:
org.apache.ibatis.binding.BindingException: Type interface com.wangxing.mybatis.mapper.PersonMapper is not known to the MapperRegistry.
因為沒有在MyBatis的核心配置檔案中註冊資料訪問介面,
解決方法:在MyBatis的核心配置檔案中註冊資料訪問介面
<mappers>
<!--註冊資料訪問介面-->
<mapper resource="PersonMapper.xml"></mapper>
</mappers>
MyBatis 官方推薦使用的是 sql對映檔案的方式配置sql語句,因為在工作中,SQL 的複雜度遠遠超過我們現在看到的 SQL,比如下面這條 SQL。
select * from t_user u
left join t_user_role ur on u.id = ur.user_id
left join t_role r on ur.role_id = r.id
left join t_user_info ui on u.id = ui.user_id
left join t_female_health fh on u.id = fh.user_id
left join t_male_health mh on u.id = mh.user_id
where u.user_name like concat('%', ${userName},'%')
and r.role_name like concat('%', ${roleName},'%')
and u.sex = 1
and ui.head_image is not null;
顯然這條 SQL 比較複雜,如果放入 @Select 中會明顯增加註解的內容。如果把大量的SQL 放入 java 程式碼中,顯然程式碼的可讀性也會下降。如果同時還要考慮使用動態 SQL,比如當引數 userName 為空,則不使用 u.user_name like concat('%',${userName},'%')
作為查詢條件;當 roleName 為空,則不使用 r.role_name like concat('%',${roleName},'%')
作為查詢條件,但是還需要加入其他的邏輯,這樣就使得這個註解更加複雜了,不利於日後的維護和修改。
用一張圖來展示 MyBatis 核心元件之間的關係。
相關文章
- Mybatis 原始碼學習(二)MyBatis原始碼
- mybatis學習MyBatis
- Mybatis學習-GetMybatisInMyHeadMyBatis
- MyBatis學習02MyBatis
- Mybatis學習記錄MyBatis
- MyBatis 學習總結MyBatis
- MyBatis-Plus學習MyBatis
- mybatis入門學習MyBatis
- Mybatis學習總結MyBatis
- SpringBoot學習之整合MybatisSpring BootMyBatis
- Mybatis框架 入門學習MyBatis框架
- Mybatis-基本學習(下)MyBatis
- JAVA學習Spring整合MybatisJavaSpringMyBatis
- mybatis原始碼學習:一級快取和二級快取分析MyBatis原始碼快取
- 2020-11-30 Mybatis 學習筆記 (二)建立java相關類MyBatis筆記Java
- Mybatis學習筆記 2:Mybatis 基本的CURD操作MyBatis筆記
- Mybatis學習筆記 1:一個Mybatis使用例子MyBatis筆記
- Mybatis學習01:利用mybatis查詢資料庫MyBatis資料庫
- Mybatis執行流程學習之手寫mybatis雛形MyBatis
- mybatis plus的學習記錄MyBatis
- Mybatis 學習筆記(二)——原生DAO實現資料增刪改查MyBatis筆記
- MyBatis(二)MyBatis入門程式(MyBatis demo)MyBatis
- 假裝是小白之重學MyBatis(二)MyBatis
- 學習MyBatis必知必會(2)~MyBatis基本介紹和MyBatis基本使用MyBatis
- netty學習(三)springboot+netty+mybatisNettySpring BootMyBatis
- Spring Boot 學習筆記(3):MyBatisSpring Boot筆記MyBatis
- mybatis學習與踩坑記錄MyBatis
- MyBatis-Plus日常工作學習MyBatis
- Mybatis學習-日誌與分頁MyBatis
- [轉載] 快速學習-Mybatis框架概述MyBatis框架
- Mybatis學習-初步認知與使用MyBatis
- Mybatis學習筆記 3:Mybatis 多種條件查詢MyBatis筆記
- MyBatis學習總結(24)——Mybatis常見問題彙總MyBatis
- Go學習【二】學習資料Go
- Golang 學習——interface 介面學習(二)Golang
- TypeScript 學習(二)TypeScript
- Kaldi學習(二)
- hdfs學習(二)