mybatis單元測試過程(無需啟動容器)
一、淺析相關(guān)類
1 Configuration
MyBatis在啟動時會取讀取所有配置文件,然后加載到內(nèi)存中,Configuration類就是承載整個配置的類。
SqlSessionFactoryBuilder調(diào)用build方法創(chuàng)建SqlSessionFactory,而SqlSessionFactory需要Configuration配置中心提供創(chuàng)建的條件,在build方法中XMLConfigBuilder 將xml文件流進行初始化并parse返回Configuration,返回之前需要通過parseConfiguration來真正為Configuration設(shè)置信息,XPathParser負責(zé)將節(jié)點下的信息轉(zhuǎn)換成XNode對象方便訪問。
2 Executor
Executor是跟SqlSession綁定在一起的,每一個SqlSession都擁有一個新的Executor對象,由Configuration創(chuàng)建。
Mybatis中所有的Mapper語句的執(zhí)行都是通過Executor進行的,Executor是Mybatis的一個核心接口。
從其定義的接口方法我們可以看出,對應(yīng)的增刪改語句是通過Executor接口的update方法進行的,查詢是通過query方法進行的。
雖然Executor接口的實現(xiàn)類有BaseExecutor和CachingExecutor,而BaseExecutor的子類又有SimpleExecutor、ReuseExecutor和BatchExecutor,但BaseExecutor是一個抽象類,其只實現(xiàn)了一些公共的封裝,而把真正的核心實現(xiàn)都通過方法抽象出來給子類實現(xiàn),如doUpdate()、doQuery();CachingExecutor只是在Executor的基礎(chǔ)上加入了緩存的功能,底層還是通過Executor調(diào)用的,所以真正有作用的Executor只有SimpleExecutor、ReuseExecutor和BatchExecutor。
它們都是自己實現(xiàn)的Executor核心功能,沒有借助任何其它的Executor實現(xiàn),它們是實現(xiàn)不同也就注定了它們的功能也是不一樣的。
3 XMLMapperBuilder
mapper文件的解析依賴于XMLConfigBuilder的mapperElement方法來解析mapper文件。
解析過程中實質(zhì)是實例化一個XMLMapperBuilder對象,然后調(diào)用其parse方法,parse方法調(diào)用的configurationElement方法是真正mapper節(jié)點解析入口,包括sql解析,緩存,等。
二、單元測試
1 生成mapper實例
運用以上相關(guān)類的功能,可以直接生成mapper的類實例。
基于Java的編程思想,設(shè)計一個基類:
BaseMapperTest:
import org.apache.ibatis.binding.MapperProxyFactory;
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.session.defaults.DefaultSqlSession;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.jdbc.JdbcTransaction;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePropertySource;
import java.lang.reflect.ParameterizedType;
/**
* @author: lyx
*/
public class BaseMapperTest<T> {
/**
* mapper接口類(持久層接口)
*/
private T mapper;
/**
* 數(shù)據(jù)庫連接
*/
private SqlSession sqlSession;
/**
* 執(zhí)行
*/
private static Executor executor;
/**
* 配置
*/
private static Configuration configuration;
static {
try {
//定義一個配置
configuration = new Configuration();
configuration.setCacheEnabled(false);
configuration.setLazyLoadingEnabled(false);
configuration.setAggressiveLazyLoading(true);
configuration.setDefaultStatementTimeout(20);
//讀取測試環(huán)境數(shù)據(jù)庫配置
PropertySource propertySource = new ResourcePropertySource(new ClassPathResource("testdb.properties"));
//設(shè)置數(shù)據(jù)庫鏈接
UnpooledDataSource dataSource = new UnpooledDataSource();
dataSource.setDriver(propertySource.getProperty("driverClassName").toString());
dataSource.setUrl(propertySource.getProperty("url").toString());
dataSource.setUsername(propertySource.getProperty("username").toString());
dataSource.setPassword(propertySource.getProperty("password").toString());
//設(shè)置事務(wù)(測試設(shè)置事務(wù)不提交false)
Transaction transaction = new JdbcTransaction(dataSource, TransactionIsolationLevel.READ_UNCOMMITTED, false);
//設(shè)置執(zhí)行
executor = configuration.newExecutor(transaction);
} catch (Exception e) {
e.printStackTrace();
}
}
public BaseMapperTest(String mapperName) {
try {
//解析mapper文件
Resource mapperResource = new ClassPathResource(mapperName);
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperResource.getInputStream(), configuration, mapperResource.toString(), configuration.getSqlFragments());
xmlMapperBuilder.parse();
//直接實例化一個默認(rèn)的sqlSession
//是做單元測試,那么沒必要通過SqlSessionFactoryBuilder構(gòu)造SqlSessionFactory,再來獲取SqlSession
sqlSession = new DefaultSqlSession(configuration, executor, false);
//將接口實例化成對象
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
MapperProxyFactory<T> mapperProxyFactory = new MapperProxyFactory<>((Class<T>) pt.getActualTypeArguments()[0]);
mapper = mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 返回mapper實例對象
*/
public T getMapper() {
return mapper;
}
}配置文件:testdb.properties
driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT&characterEncoding=utf8&useSSL=false&allowMultiQueries=true username=root password=root
2 demo
junit或者Testng單元測試都可以實現(xiàn),下面給出一個junit測試的例子
/**
* @author lyx
* 直接繼承BaseMapperTest,并指定待持久層測試的接口即可
*/
@RunWith(SpringRunner.class)
public class BaseConfigDaoTest extends BaseMapperTest<BaseConfigDao> {
public BaseConfigDaoTest() {
super("mapper/BaseCodeConfigMapper.xml");
}
@Test
public void selectListByCodeTest() {
String code = "lyx";
List<BaseConfigDTO> baseConfigList = super.getMapper().selectListByCode(code);
Assert.assertTrue(baseConfigList.size() > 0);
}
}???????總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java集合類之HashTable,Properties篇
這篇文章主要為大家詳細介紹一下Java集合類中HashTable和Properties的用法,文中的示例代碼講解詳細,對我們學(xué)習(xí)Java有一定幫助,感興趣的可以了解一下2022-07-07
java8中定時任務(wù)最佳實現(xiàn)方式(實現(xiàn)原理)
這篇文章主要介紹了java8中定時任務(wù)最佳實現(xiàn)方式,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2024-12-12
基于logback實現(xiàn)純java版本的SDK組件
這篇文章主要介紹了基于logback實現(xiàn)純java版本的SDK組件,在項目開發(fā)過程中通常會使用logback作為日志記錄的依賴工具,使用方式是引入logback相關(guān)jar包,然后配置logback.xml配置文件的方式來實現(xiàn),需要的朋友可以參考下2023-11-11
Mac M1 Java 開發(fā)環(huán)境配置詳解
這篇文章主要介紹了Mac M1 Java 開發(fā)環(huán)境配置詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03

