??前言
本篇博文是學習過程中的筆記和對于MyBatis底層機制的分析思路,希望能夠給您帶來幫助??
??個人主頁:晨犀主頁
??個人簡介:大家好,我是晨犀,希望我的文章可以幫助到大家,您的滿意是我的動力????
??歡迎大家:這里是CSDN,我總結(jié)知識的地方,歡迎來到我的博客,感謝大家的觀看??
如果文章有什么需要改進的地方還請大佬不吝賜教 先在次感謝啦??
自己實現(xiàn)MyBatis 底層機制[上]
MyBatis 整體架構(gòu)分析
Mybatis 核心框架示意圖
核心框架示意圖的解讀
- mybatis 的核心配置文件
mybatis-config.xml: 進行全局配置,全局只能有一個這樣的配置文件
XxxMapper.xml 配置多個SQL,可以有多個XxxMappe.xml 配置文件 - 通過mybatis-config.xml 配置文件得到SqlSessionFactory
- 通過SqlSessionFactory 得到SqlSession,用SqlSession 就可以操作數(shù)據(jù)了
- SqlSession 底層是Executor(執(zhí)行器), 有兩個重要的實現(xiàn)類基本執(zhí)行器和帶緩存功能的執(zhí)行器, 有很多方法
- MappedStatement 是通過XxxMapper.xml 中定義, 生成的statement 對象
- 參數(shù)輸入執(zhí)行并輸出結(jié)果集, 無需手動判斷參數(shù)類型和參數(shù)下標位置, 且自動將結(jié)果集映射為Java 對象
搭建MyBatis 底層機制開發(fā)環(huán)境
1、創(chuàng)建Maven 項目nlc-mybatis
前面快速入門有創(chuàng)建步驟,這里不在描述。
2、修改nlc-mybatis\pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nlc</groupId>
<artifactId>nlc-mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<!--定義編譯器 / source / target 版本即可-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
</properties>
<!--引入必要的依賴-->
<dependencies>
<!--引入dom4j-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!--引入mysql依賴-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<!--lombok-簡化entity/javabean/pojo開發(fā) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
<!--junit依賴-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
3、創(chuàng)建數(shù)據(jù)庫和表
CREATE DATABASE `nlc_mybatis`;
USE `nlc_mybatis`;
CREATE TABLE `monster` (
`id` INT NOT NULL AUTO_INCREMENT,
`age` INT NOT NULL,
`birthday` DATE DEFAULT NULL,
`email` VARCHAR(255) NOT NULL,
`gender` TINYINT NOT NULL,
`name` VARCHAR(255) NOT NULL,
`salary` DOUBLE NOT NULL,
PRIMARY KEY (`id`)
) CHARSET=utf8
INSERT INTO `monster` VALUES(NULL, 200, '2000-11-11', 'nmw@sohu.com', 1,'牛魔王', 8888.88)
4、到此: 項目開發(fā)環(huán)境搭建完成
Nlc-Mybatis 的設計思路
Mybatis 的底層實現(xiàn)設計
1. 傳統(tǒng)方式操作數(shù)據(jù)庫
-
得到Session對象
-
調(diào)用Executor的方法完成操作
-
Executor的連接是從Configuration獲取的
2.MyBatis操作數(shù)據(jù)庫的方式分析
- 得到Session
- 不用直接調(diào)用Executor的方法完成操作
- 通過MapperProxy獲取Mapper對象
- 調(diào)用Mapper的方法,完成數(shù)據(jù)庫的操作
- Mapper最終還是動態(tài)代理方式,使用Executor的方法完成操作
- MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數(shù)和獲取結(jié)果集的工作。
自己實現(xiàn)MyBatis 底層機制
實現(xiàn)任務階段1- 完成讀取配置文件,得到數(shù)據(jù)庫連接
通過配置文件,獲取數(shù)據(jù)庫連接。
分析示意圖
代碼實現(xiàn)
- 創(chuàng)建nlc-mybatis\src\main\resources\nlc_config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<database>
<!--配置連接數(shù)據(jù)庫的信息-->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!--配置連接mysql-url
1. jdbc:mysql 協(xié)議
2. 127.0.0.1:3306 : 指定連接mysql的ip+port
3. mybatis: 連接的DB
4. useSSL=true 表示使用安全連接
5. & 表示 & 防止解析錯誤
6. useUnicode=true : 使用unicode 作用是防止編碼錯誤
7. characterEncoding=UTF-8 指定使用utf-8, 防止中文亂碼
8. 不要背,直接使用即可
-->
<property name="url" value="jdbc:mysql://localhost:3306/nlc_mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</database>
- 創(chuàng)建nlc-mybatis\sqlsession\NlcConfiguration.java
public class NlcConfiguration {
//屬性-類的加載器
private static ClassLoader loader =
ClassLoader.getSystemClassLoader();
//讀取xml文件信息,并處理
public Connection build(String resource) {
Connection connection = null;
try {
//加載配置nlc_mybatis.xml 獲取到對應的InputStream
InputStream stream = loader.getResourceAsStream(resource);
SAXReader reader = new SAXReader();
Document document = reader.read(stream);
//獲取到nlc_mybatis.xml 的根元素 <database>
Element root = document.getRootElement();
System.out.println("root=" + root);
//解析root元素,返回Connection
connection = evalDataSource(root);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
//方法會解析nlc_config.xml 信息,并返回Connection
//eval: 評估/解析
private Connection evalDataSource(Element node) {
if (!"database".equals(node.getName())) {
throw new RuntimeException("root 節(jié)點應該是<database>");
}
//連接DB的必要參數(shù)
String driverClassName = null;
String url = null;
String username = null;
String password = null;
//遍歷node下的子節(jié)點,獲取屬性值
for (Object item : node.elements("property")) {
Element i = (Element) item;//i 就是 對應property節(jié)點
String name = i.attributeValue("name");
String value = i.attributeValue("value");
//判斷是否得到name 和 value
if (name == null || value == null) {
throw new RuntimeException("property 節(jié)點沒有設置name或者value屬性");
}
switch (name) {
case "url":
url = value;
break;
case "username":
username = value;
break;
case "driverClassName":
driverClassName = value;
break;
case "password":
password = value;
break;
default:
throw new RuntimeException("屬性名沒有匹配到...");
}
}
Connection connection = null;
try {
//要求JVM查找并加載指定的類到內(nèi)存中,此時將"com.mysql.jdbc.Driver" 當做參數(shù)傳入,
// 就是告訴JVM,去"com.mysql.jdbc"這個路徑下找Driver類,將其加載到內(nèi)存中。
Class.forName(driverClassName);
connection = DriverManager.getConnection(url,username,password);
} catch (Exception e) {
e.printStackTrace();
}
return connection; //返回Connection
}
}
完成測試
- 編寫nlc-mybatis\src\test\java\com\nlc\test\NlcMybatisTest.java
public class NlcMyBatisTest {
@Test
public void build() {
NlcConfiguration nlcConfiguration = new NlcConfiguration();
Connection connection = nlcConfiguration.build("nlc_mybatis.xml");
System.out.println("connection--" + connection);
}
}
測試效果
實現(xiàn)任務階段2- 編寫執(zhí)行器,輸入SQL 語句,完成操作
說明:通過實現(xiàn)執(zhí)行器機制,對數(shù)據(jù)表操作。
分析示意圖
說明:我們把對數(shù)據(jù)庫的操作,會封裝到一套Executor 機制中,程序具有更好的擴展性,結(jié)構(gòu)更加清晰.
代碼實現(xiàn)
- 創(chuàng)建nlc-mybatis\src\main\java\com\nlc\entity\Monster.java
如果使用@Data注解需要全參構(gòu)造器可以添加@AllArgsConstructor,但是無參構(gòu)造器必須要顯示調(diào)用,否則會被全參構(gòu)造器覆蓋。
/**
* Monster 和 monster表有映射關系
* @Getter 就會給所有屬性 生成對應的getter
* @Setter 就會給所有屬性 生成對應的setter
* @ToString 生成 toString...
* @NoArgsConstructor 生成無參構(gòu)造器
* @AllArgsConstructor 生成要給全參構(gòu)造器
* @Data 會生成上面除全參構(gòu)造器的所有注解
* 如何選擇主要還是看自己需要
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Monster {
private Integer id;
private Integer age;
private String name;
private String email;
private Date birthday;
private double salary;
private Integer gender;
}
- 創(chuàng)建nlc-mybatis\src\main\java\com\nlc\nlcmybatis\sqlsession\Executor.java
public interface Executor {
//泛型方法
public <T> T query(String statement, Object parameter);
}
- 創(chuàng)建nlc-mybatis\src\main\java\com\nlc\nlcmybatis\sqlsession\NlcExecutor.java
public class NlcExecutor implements Executor {
//屬性
private NlcConfiguration nlcConfiguration =
new NlcConfiguration();
// 根據(jù) sql 查找結(jié)果
@Override
public <T> T query(String sql, Object parameter) {
//得到連接Connection
Connection connection = getConnection();
//查詢返回的結(jié)果集
ResultSet set = null;
PreparedStatement pre = null;
try {
pre = connection.prepareStatement(sql);
//設置參數(shù), 如果參數(shù)多, 可以使用數(shù)組處理.
pre.setString(1, parameter.toString());
set = pre.executeQuery();
//把set數(shù)據(jù)封裝到對象-monster
//說明: 這里做了簡化處理
//認為返回的結(jié)果就是一個monster記錄
//完善的寫法是一套反射機制.
Monster monster = new Monster();
//遍歷結(jié)果集, 把數(shù)據(jù)封裝到monster對象
while (set.next()) {
monster.setId(set.getInt("id"));
monster.setName(set.getString("name"));
monster.setEmail(set.getString("email"));
monster.setAge(set.getInt("age"));
monster.setGender(set.getInt("gender"));
monster.setBirthday(set.getDate("birthday"));
monster.setSalary(set.getDouble("salary"));
}
return (T) monster;
} catch (Exception throwables) {
throwables.printStackTrace();
} finally {
try {
if (set != null) {
set.close();
}
if (pre != null) {
pre.close();
}
if (connection != null) {
connection.close();
}
} catch (Exception throwables) {
throwables.printStackTrace();
}
}
return null;
}
//編寫方法,通過NlcConfiguration對象,返回連接
private Connection getConnection() {
Connection connection = nlcConfiguration.build("nlc_mybatis.xml");
return connection;
}
}
完成測試
- 修改nlc-mybatis\src\test\java\com\nlc\test\NlcMybatisTest.java , 增加測試方法
@Test
public void query() {
Executor executor = new NlcExecutor();
Monster monster =
executor.query("select * from monster where id=?", 1);
System.out.println("monster-- " + monster);
}
- 測試效果
文章來源:http://www.zghlxwxcb.cn/news/detail-615484.html
??總結(jié)
- 了解底層的機制可以幫助我們更好的學習,閱讀優(yōu)秀的源碼可以增長我們的功力。
- 適當?shù)膁ebug可以解決我們的疑惑,底層是一個非常龐大的集成,把握主干就可以了。
- 過于追根究底只會影響自己的心緒,會耗費大量時間精力。
- 如果自己感興趣的話,可以多研究一下,會發(fā)現(xiàn)其中的樂趣,點到即止。
文章到這里就結(jié)束了,如果有什么疑問的地方請指出,諸大佬們一起來評論區(qū)一起討論??
希望能和諸大佬們一起努力,今后我們一起觀看感謝您的閱讀??
如果幫助到您不妨3連支持一下,創(chuàng)造不易您們的支持是我的動力??文章來源地址http://www.zghlxwxcb.cn/news/detail-615484.html
到了這里,關于自己實現(xiàn)MyBatis 底層機制--抽絲剝繭(上)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!