手寫mybatis框架


前言

很久沒有更新mybatis的源碼解析了,因為最近在將自己所理解的mybatis思想轉為實踐。 在學習mybatis的源碼過程中,根據mybatis的思想自己構建了一個ORM框架 。整個代碼都是自己手動構造,沒有一句代碼是Copy,肯定不如谷歌大神那樣的代碼,但已基本實現了SQL語句的實現和對象關系映射功能。若對源碼感興趣,可加入我一起寫這個項目。后文會附帶地址,若覺得不錯,希望手動star下哦!

項目地址:https://github.com/xbcrh/simple-ibatis

框架介紹

simple-batis是自己編寫的一個簡單ORM框架。在學習mybatis源碼時,有感而發。耗時3周左右,基本滿足了一些常用的SQL操作本項目所涉及的代碼都是個人所寫,沒有一句copy,肯定不是很完善,大家理解下,后續有時間會一直更新。如果你對源碼感興趣,也可以加入一起,將自己的理解轉為代碼真的會加深印象。

框架代碼簡單梳理

注釋 com.simple.ibatis.annotation

@Dao
標注在mapper類上。標志着該類是一個mapper類,在解析時會進行解析

@Dao
public interface App1 {
}

@Select

標注在mapper類中的方法上。標志着該方法是一個Select方法,並在Select方法內部寫具體的sql語句。對於有參數注入的情況,參數使用{}進行代替

@Select("SELECT name from sys_user where name = {user.name} and id = {id}")
List<String> test1(User user, int id);

@Param

標注在mapper類中的方法參數上。對參數名進行一次重命名。若不使用此注釋,會默認按照參數名當做注入的元素

@Select("SELECT name from sys_user where id = {userId}")
List<String> test2(@Param("userId") int id);

@Update

標注在mapper類中的方法上。標志着該方法是一個Update方法

@Update("update sys_user set name = {user.name} where id = {user.id}")
void update3(User user);

@Insert

標注在mapper類中的方法上。標注着該方法是一個Insert方法

@Insert("insert into sys_user(id,name) values ({user.id},{user.name})")
int insert4(@Param("user") User user);

@Delete

標注在mapper類中的方法上。標注着該方法是一個Delete方法

@Delete("delete from sys_user where id = {user.id}")
int delete5(@Param("user") User user);

數據庫注冊 com.simple.ibatis.driver

DriverRegister 提供數據庫注冊功能。未避免重復注冊,內部使用了一個緩存

數據源 com.simple.ibatis.datasource

NormalDataSource 普通數據源,沒有池化的功能,提供獲取數據庫連接的功能
PoolDataSource 池化數據源,存放着活躍連接列表和空閑連接列表。並對獲取連接和釋放連接做了一系列操作
PoolConnection 連接的包裝類,除了存放真實連接外,還存放此連接被獲取時間,用於判斷連接是否超時

核心類 com.simple.ibatis.core

Config 全局核心類,存放數據源,mapper包地址,mapper類解析文件
MapperCore mapper類解析文件
SqlSource 具體的sql語句封裝

代理類 com.simple.ibatis.mapping

MapperProxy mapper接口代理類。使用動態代理技術

執行器類 com.simple.ibatis.execute

Executor 執行器接口
SimpleExecutor 具體執行器,執行具體的sql方法。生成結果
ExecutorFactory 生成Executor的工廠類

反射類 com.simple.ibatis.reflect

ClassWrapper 類加強器,封裝了Object的get和set方法。
ObjectWrapper 對象包裝類。調用ObjectWrapper.setVal和getVal就可以設置和獲得屬性。不需要顯示的調用對象的getxxx和setxxx方法。
ObjectWrapperFactory 對象包裝類生成器

處理器類 com.simple.ibatis.statement

PreparedStatementHandle PreparedStatement生成器。將java屬性轉為jdbc屬性並注入。
ResultSetHandle 對查詢結構ResultSet進行解析,轉換為Java類型

工具類 com.simple.ibatis.util

PackageUti 解析包的工具類
TypeUtil 類型判斷的工具類

緩存類 com.simple.ibatis.cache

Cache 緩存接口類

SimpleCache 簡單緩存類

 

具體代碼實踐

1.  代碼運行默認在java8上,因為用到了參數反射,所以在idea中記得開啟parameters;

File->Settings->Build,Execution,Deployment->Compiler->Java Compiler
在 Additional command line parameters: 后面填上 -parameters

 

2. 構建pojo文件(記得在數據庫也建立一張sys_user表)

public class User {
private int id;

private String name;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

2. 構建mapper文件

在mapper文件上加@Dao注解,並為每個方法編寫Sql語句,如下所示。目前僅支持注解方式配置SQL,后續會繼續完善使其支持.xml文件。

@Dao
public interface App1 {

@Select("SELECT * from sys_user")
List<User> select2();

@Select("SELECT name from sys_user where name = {user.name} and id = {id}")
List<String> select3(User user, @Param("id") int id);

@Update("update sys_user set name = {user.name} where id = {user.id}")
void update4(User user);

@Insert("insert into sys_user(id,name) values ({user.id},{user.name}) ")
int insert5(@Param("user") User user);
}

3. 編寫測試類

public class ExecutorTest {

    @Test
    public void shouldConnect(){
        /**構建數據源,使用時下面代碼可設置為全局變量,只加載一次*/
        PoolDataSource poolDataSource = new PoolDataSource("com.mysql.jdbc.Driver","jdbc:mysql://101.132.150.75:3306/our-auth","root","root");
Config config = new Config("com/simple/ibatis/mapper",poolDataSource);
/**拿到具體的mapper代理類*/ SimpleExecutor executor = config.getExecutor(); App1 app1 = executor.getMapper(App1.class); /**構建查詢條件*/ User user = new User(); user.setName("xiabing"); user.setId(1); /**調用插入方法*/ int count = app1.insert5(user); /**調用更新方法*/ user.setName("root"); app1.update4(user); /**查詢用戶名,返回字符*/ List<String> users = app1. select3(user,3); System.out.println(users.get(0)); /**查詢用戶,返回對象*/ List<User> userLists = app1.select2(); System.out.println(userLists.get(0).getName()); } }

最終結果

 

 框架待完善

1.  目前該框架僅支持注解注入SQL語句,不支持XML注入SQL語句

2. 目前對象屬性不支持集合類,對象中也不支持嵌套非基本數據類型

3. 框架中沒有加入緩存

4. 解析mapper文件僅支持一個包下的mapper文件

結語

正如自己所說,將自己思路變為實踐。該框架代碼不完善地方很多,但在寫的過程中,對mybatis的原理也熟悉了。此框架是我學習的路上的產物。希望小伙伴可以支持下,對源碼感興趣的或想學習mybatis源碼的伙伴可以評論下,和我一起寫好這個框架,一起開源(學習路上一起加油)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM