Mybatis?Plus使用XML編寫動態(tài)sql的超簡易方法
使用xml編寫動態(tài)sql
在Resources文件夾下創(chuàng)建一個Mapper文件夾
比如我們需要在User表中使用增刪改查,創(chuàng)建UserMapper.xml,對應MybatisPlus中的UserMapper接口

之后我們在application.yml中配置mapper文件夾的路徑
mybatis-plus: ? mapper-locations: classpath:mapper/*.xml
之后在UserMapper中創(chuàng)建函數
@Repository
public interface UserMapper extends BaseMapper<User> {
?? ??? ?// 使函數參數對應xml中的參數wxNickName
? ? List<User> selectByName(@Param("wxNickName") String name);
}就可以在UserMapper.xml中寫sql語句了
寫法和Mybatis一樣滴
<?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.zhou.usercenter.dao.user.UserMapper">
? ? <select id="selectByName" resultType="com.zhou.usercenter.domain.entity.user.User">
? ? ? ? select * from user
? ? ? ? <where>
? ? ? ? ? ? <if test="wxNickName != null and wxNickName != ''">
? ? ? ? ? ? ? ? wx_nickname like CONCAT('%',#{wxNickName},'%');
? ? ? ? ? ? </if>
? ? ? ? </where>
? ? </select>
</mapper>之后調用即可
@SpringBootTest
class UserCenterApplicationTests {
? ? @Autowired
? ? UserMapper userMapper;
? ? @Test
? ? void contextLoads() {
? ? ? ? List<User> users = userMapper.selectByName("杰倫");
? ? ? ? System.out.println(users);
? ? }
}即可看到正確的輸出結果

動態(tài)SQL語句的原理
Mybatis-Plus(簡稱MP)是一個 Mybatis 的增強工具,那么它是怎么增強的呢?其實就是它已經封裝好了一些crud方法,開發(fā)就不需要再寫xml了,直接調用這些方法就行,就類似于JPA。那么這篇文章就來閱讀以下MP的具體實現(xiàn),看看是怎樣實現(xiàn)這些增強的。

入口類:MybatisSqlSessionFactoryBuilder
通過在入口類 MybatisSqlSessionFactoryBuilder#build方法中, 在應用啟動時, 將mybatis plus(簡稱MP)自定義的動態(tài)配置xml文件注入到Mybatis中。
public class MybatisSqlSessionFactoryBuilder extends SqlSessionFactoryBuilder {
public SqlSessionFactory build(Configuration configuration) {
// ... 省略若干行
if (globalConfig.isEnableSqlRunner()) {
new SqlRunnerInjector().inject(configuration);
}
// ... 省略若干行
return sqlSessionFactory;
}
}這里涉及到2個MP2個功能類
擴展繼承自Mybatis的MybatisConfiguration類: MP動態(tài)腳本構建,注冊,及其它邏輯判斷。
SqlRunnerInjector: MP默認插入一些動態(tài)方法的xml 腳本方法。
MybatisConfiguration類
這里我們重點剖析MybatisConfiguration類,在MybatisConfiguration中,MP初始化了其自身的MybatisMapperRegistry,而MybatisMapperRegistry是MP加載自定義的SQL方法的注冊器。
MybatisConfiguration中很多方法是使用MybatisMapperRegistry進行重寫實現(xiàn)
其中有3個重載方法addMapper實現(xiàn)了注冊MP動態(tài)腳本的功能。
public class MybatisConfiguration extends Configuration {
/**
* Mapper 注冊
*/
protected final MybatisMapperRegistry mybatisMapperRegistry = new MybatisMapperRegistry(this);
// ....
/**
* 初始化調用
*/
public MybatisConfiguration() {
super();
this.mapUnderscoreToCamelCase = true;
languageRegistry.setDefaultDriverClass(MybatisXMLLanguageDriver.class);
}
/**
* MybatisPlus 加載 SQL 順序:
* <p> 1、加載 XML中的 SQL </p>
* <p> 2、加載 SqlProvider 中的 SQL </p>
* <p> 3、XmlSql 與 SqlProvider不能包含相同的 SQL </p>
* <p>調整后的 SQL優(yōu)先級:XmlSql > sqlProvider > CurdSql </p>
*/
@Override
public void addMappedStatement(MappedStatement ms) {
// ...
}
// ... 省略若干行
/**
* 使用自己的 MybatisMapperRegistry
*/
@Override
public <T> void addMapper(Class<T> type) {
mybatisMapperRegistry.addMapper(type);
}
// .... 省略若干行
}在MybatisMapperRegistry中,MP將mybatis的MapperAnnotationBuilder替換為MP自己的MybatisMapperAnnotationBuilder
public class MybatisMapperRegistry extends MapperRegistry {
@Override
public <T> void addMapper(Class<T> type) {
// ... 省略若干行
MybatisMapperAnnotationBuilder parser = new MybatisMapperAnnotationBuilder(config, type);
parser.parse();
// ... 省略若干行
}
}在MybatisMapperRegistry類的addMapper方法中,真正進入到MP的核心類MybatisMapperAnnotationBuilder,MybatisMapperAnnotationBuilder這個類是MP實現(xiàn)動態(tài)腳本的關鍵類。
MybatisMapperAnnotationBuilder動態(tài)構造
在MP的核心類MybatisMapperAnnotationBuilder的parser方法中,MP逐一遍歷要加載的Mapper類,加載的方法包括下面幾個
public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
@Override
public void parse() {
//... 省略若干行
for (Method method : type.getMethods()) {
/** for循環(huán)代碼, MP判斷method方法是否是@Select @Insert等mybatis注解方法**/
parseStatement(method);
InterceptorIgnoreHelper.initSqlParserInfoCache(cache, mapperName, method);
SqlParserHelper.initSqlParserInfoCache(mapperName, method);
}
/** 這2行代碼, MP注入默認的方法列表**/
if (GlobalConfigUtils.isSupperMapperChildren(configuration, type)) {
GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant, type);
}
//... 省略若干行
}
@Override
public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
Class<?> modelClass = extractModelClass(mapperClass);
//... 省略若干行
List<AbstractMethod> methodList = this.getMethodList(mapperClass);
TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
// 循環(huán)注入自定義方法
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
mapperRegistryCache.add(className);
}
}
public class DefaultSqlInjector extends AbstractSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
return Stream.of(
new Insert(),
//... 省略若干行
new SelectPage()
).collect(toList());
}
}在MybatisMapperAnnotationBuilder中,MP真正將框架自定義的動態(tài)SQL語句注冊到Mybatis引擎中。而AbstractMethod則履行了具體方法的SQL語句構造。
具體的AbstractMethod實例類,構造具體的方法SQL語句
以 SelectById 這個類為例說明下
/**
* 根據ID 查詢一條數據
*/
public class SelectById extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
/** 定義 mybatis xml method id, 對應 <id="xyz"> **/
SqlMethod sqlMethod = SqlMethod.SELECT_BY_ID;
/** 構造id對應的具體xml片段 **/
SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlMethod.getSql(),
sqlSelectColumns(tableInfo, false),
tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty(),
tableInfo.getLogicDeleteSql(true, true)), Object.class);
/** 將xml method方法添加到mybatis的MappedStatement中 **/
return this.addSelectMappedStatementForTable(mapperClass, getMethod(sqlMethod), sqlSource, tableInfo);
}
}至此,MP完成了在啟動時加載自定義的方法xml配置的過程,后面的就是mybatis ${變量} #{變量}的動態(tài)替換和預編譯,已經進入mybatis自有功能。
小結一下
MP總共改寫和替換了mybatis的十多個類,主要如下圖所示:

總體上來說,MP實現(xiàn)mybatis的增強,手段略顯繁瑣和不夠直觀,其實根據MybatisMapperAnnotationBuilder構造出自定義方法的xml文件,將其轉換為mybatis的Resource資源,可以只繼承重寫一個Mybatis類:SqlSessionFactoryBean 比如如下:
public class YourSqlSessionFactoryBean extends SqlSessionFactoryBean implements ApplicationContextAware {
private Resource[] mapperLocations;
@Override
public void setMapperLocations(Resource... mapperLocations) {
super.setMapperLocations(mapperLocations);
/** 暫存使用mybatis原生定義的mapper xml文件路徑**/
this.mapperLocations = mapperLocations;
}
/**
* {@inheritDoc}
*/
@Override
public void afterPropertiesSet() throws Exception {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
/** 只需要通過將自定義的方法構造成xml resource和原生定義的Resource一起注入到mybatis中即可, 這樣就可以實現(xiàn)MP的自定義動態(tài)SQL和原生SQL的共生關系**/
this.setMapperLocations(InjectMapper.getMapperResource(this.dbType, beanFactory, this.mapperLocations));
super.afterPropertiesSet();
}
}以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
程序包org.springframework不存在的解決辦法
這篇文章主要介紹了程序包org.springframework不存在的解決辦法,在使用IDEA創(chuàng)建SpringBoot項目時,剛打開無法正常運行,本文通過圖文結合的方式給大家介紹的非常詳細,具有一定參考價值,需要的朋友可以參考下2024-07-07
Maven配置文件settings.xml的實現(xiàn)
Maven是一個用于構建和管理Java項目的強大工具,它依賴于設置文件來配置和管理其行為,其中最重要的之一便是settings.xml文件,本文主要介紹了Maven配置文件settings.xml的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2024-01-01

