springboot之通用mapper擴充套件通用介面和Example 用法
例如 selectAll 方法。
首先定義介面:
@RegisterMapper
public interface SelectAllMapper<T> {
/**
* 查詢全部結果
*
* @return
*/
@SelectProvider(type = MySelectProvider.class, method = "dynamicSQL")
List<T> selectAll();
}
其中 MySelectProvider 是你要實現的一個類,該類需要繼承 MapperTemplate。
@RegisterMapper 註解可以避免 mappers 引數配置,通用 Mapper 檢測到該介面被繼承時,會自動註冊。
import org.apache.ibatis.mapping.MappedStatement;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.MapperTemplate;
import tk.mybatis.mapper.mapperhelper.SqlHelper;
public class MySelectProvider extends MapperTemplate {
public BaseSelectProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
super(mapperClass, mapperHelper);
}
/**
* 查詢全部結果
*
* @param ms
* @return
*/
public String selectAll(MappedStatement ms) {
final Class<?> entityClass = getEntityClass(ms);
//修改返回值型別為實體型別
setResultType(ms, entityClass);
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.selectAllColumns(entityClass));
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
sql.append(SqlHelper.orderByDefault(entityClass));
return sql.toString();
}
}
其中 selectAll 方法名要和介面中定義的方法名一致。其次就是該方法的引數為 MappedStatement 型別。
在 selectAll 方法中,首先是獲取了當前介面的實體型別:
final Class<?> entityClass = getEntityClass(ms);
因為介面返回值型別為 List<T>,MyBatis 會認為返回值型別為 List<Object>,這和我們想要的實體型別不一樣,所以下一行程式碼就是設定返回值型別:
setResultType(ms, entityClass);
注意,只有返回 T 或者 List 時需要設定,返回 int 型別時不需要設定。
接下來就是純粹的拼接 XML 形式的 SQL 了。
//select col1,col2...
sql.append(SqlHelper.selectAllColumns(entityClass));
//from tablename - 支援動態表名
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
//order by xxx
sql.append(SqlHelper.orderByDefault(entityClass));
這是其中最簡單的一個方法實現。當你想要實現某種方法時,可以從已有的例子中找一個最接近的方法,在此基礎上進行修改。
Example 用法:
通用 Mapper 中的 Example 方法有兩大類定義,一個引數和兩個引數的,例如下面兩個:
List<T> selectByExample(Object example);
int updateByExampleSelective(@Param("record") T record, @Param("example") Object example);
所有 Example 方法中的 example 型別都是 Object 型別,這是因為通用 Mapper 支援所有符合 Example 結構的引數,例如通過 MBG 生成的 CountryExample、UserExample 類。還有通用 Mapper 中提供的通用 Example,以及支援 Java8 方法引用的 Weekend 型別。
通用 Mapper 中的 Example 方法有兩大類定義,一個引數和兩個引數的,例如下面兩個:
List<T> selectByExample(Object example);
int updateByExampleSelective(@Param("record") T record, @Param("example") Object example);
所有 Example 方法中的 example 型別都是 Object 型別,這是因為通用 Mapper 支援所有符合 Example 結構的引數,例如通過 MBG 生成的 CountryExample、UserExample 類。還有通用 Mapper 中提供的通用 Example,以及支援 Java8 方法引用的 Weekend 型別。
通用 Mapper 中的 Example 方法有兩大類定義,一個引數和兩個引數的,例如下面兩個:
List<T> selectByExample(Object example);
int updateByExampleSelective(@Param("record") T record, @Param("example") Object example);
所有 Example 方法中的 example 型別都是 Object 型別,這是因為通用 Mapper 支援所有符合 Example 結構的引數,例如通過 MBG 生成的 CountryExample、UserExample 類。還有通用 Mapper 中提供的通用 Example,以及支援 Java8 方法引用的 Weekend 型別。
配置中有一個和 Example 有關的 引數詳情參照通用mapper配置中有一個和 Example 有關的引數
MBG 生成的 Example
用法如下:
CountryExample example = new CountryExample();
example.createCriteria().andCountrynameLike("A%");
example.or().andIdGreaterThan(100);
example.setDistinct(true);
int count = mapper.deleteByExample(example);
對於的 SQL 日誌如下:
DEBUG [main] - ==> Preparing: DELETE FROM country WHERE ( countryname like ? ) or ( Id > ? )
DEBUG [main] - ==> Parameters: A%(String), 100(Integer)
DEBUG [main] - <== Updates: 95
生成的 CountryExample 中包含了和欄位相關的多種方法,根據自己的需要設定相應的條件即可。
通用 Example
這是由通用 Mapper 提供的一個類,這個類和 MBG 生成的相比,需要自己設定屬性名。這個類還額外提供了更多的方法。
6.2.1 查詢
示例:
Example example = new Example(Country.class);
example.setForUpdate(true);
example.createCriteria().andGreaterThan("id", 100).andLessThan("id",151);
example.or().andLessThan("id", 41);
List<Country> countries = mapper.selectByExample(example);
日誌:
DEBUG [main] - ==> Preparing: SELECT id,countryname,countrycode FROM country WHERE ( id > ? and id < ? ) or ( id < ? ) ORDER BY id desc FOR UPDATE
DEBUG [main] - ==> Parameters: 100(Integer), 151(Integer), 41(Integer)
DEBUG [main] - <== Total: 90
6.2.2 動態 SQL
示例:
Example example = new Example(Country.class);
Example.Criteria criteria = example.createCriteria();
if(query.getCountryname() != null){
criteria.andLike("countryname", query.getCountryname() + "%");
}
if(query.getId() != null){
criteria.andGreaterThan("id", query.getId());
}
List<Country> countries = mapper.selectByExample(example);
日誌:
DEBUG [main] - ==> Preparing: SELECT id,countryname,countrycode FROM country WHERE ( countryname like ? ) ORDER BY id desc
DEBUG [main] - ==> Parameters: China%(String)
DEBUG [main] - <== Total: 1
6.2.3 排序
示例:
Example example = new Example(Country.class);
example.orderBy("id").desc().orderBy("countryname").orderBy("countrycode").asc();
List<Country> countries = mapper.selectByExample(example);
日誌:
DEBUG [main] - ==> Preparing: SELECT id,countryname,countrycode FROM country order by id DESC,countryname,countrycode ASC
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 183
6.2.4 去重
示例:
CountryExample example = new CountryExample();
//設定 distinct
example.setDistinct(true);
example.createCriteria().andCountrynameLike("A%");
example.or().andIdGreaterThan(100);
List<Country> countries = mapper.selectByExample(example);
日誌:
DEBUG [main] - ==> Preparing: SELECT distinct id,countryname,countrycode FROM country WHERE ( countryname like ? ) or ( Id > ? ) ORDER BY id desc
DEBUG [main] - ==> Parameters: A%(String), 100(Integer)
DEBUG [main] - <== Total: 95
6.2.5 設定查詢列
示例:
Example example = new Example(Country.class);
example.selectProperties("id", "countryname");
List<Country> countries = mapper.selectByExample(example);
日誌:
DEBUG [main] - ==> Preparing: SELECT id , countryname FROM country ORDER BY id desc
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 183
除了這裡提到的方法外,還有很多其他的方法,可以檢視 Example 原始碼進行了解。
6.3 Example.builder 方式
示例:
Example example = Example.builder(Country.class)
.select("countryname")
.where(Sqls.custom().andGreaterThan("id", 100))
.orderByAsc("countrycode")
.forUpdate()
.build();
List<Country> countries = mapper.selectByExample(example);
日誌:
DEBUG [main] - ==> Preparing: SELECT countryname FROM country WHERE ( id > ? ) order by countrycode Asc FOR UPDATE
DEBUG [main] - ==> Parameters: 100(Integer)
DEBUG [main] - <== Total: 83
6.4 Weekend
使用 6.2 和 6.3 中的 Example 時,需要自己輸入屬性名,例如 "countryname",假設輸入錯誤,或者資料庫有變化,這裡很可能就會出錯,因此基於 Java 8 的方法引用是一種更安全的用法,如果你使用 Java 8,你可以試試 Weekend。
示例:
List<Country> selectByWeekendSql = mapper.selectByExample(new Example.Builder(Country.class)
.where(WeekendSqls.<Country>custom().andLike(Country::getCountryname, "%a%")
.andGreaterThan(Country::getCountrycode, "123"))
.build());
日誌:
DEBUG [main] - ==> Preparing: SELECT id,countryname,countrycode FROM country WHERE ( countryname like ? and countrycode > ? )
DEBUG [main] - ==> Parameters: %a%(String), 123(String)
DEBUG [main] - <== Total: 151