MyBatis中l其属性resultSets的作⽤及研究
在完成⼀个需求的时候,意外发现了resultSets这⼀属性,以前都没有接触过,现在在学习经历写下了做⼀次总结与分享
除了resultType,resultMap做映射外,Mybatis还提供了开放的API来做映射的处理。
resultType和resultMap
⾸先来说说MyBatis的resultType和resultMp,这个两个实际上就是对数据库中的列名和我们的Java实体中做了⼀对⼀的映射处理,使得数据库中的字段可以被赋值到我们的Java实体对象中,熟悉JDBC的童鞋肯定知道JDBC的结果集映射是多么烦,只不过这些繁琐的操作由Mybatis这个半⾃动ORM框架帮我们做了。
resultSets
这个属性其实更像我们的JDBC,使⽤JDBC定制地去操作实体的映射
话不多讲,先看代码
-- 表名做了处理
<select id="selectItemExportByQueryInfo" resultSets="financeInvoiceItemResultMapper">
SELECT bii.item_id id, bli.ln_std_name stdName, bli.id_card idCard, bli.std_no stdNo, bu.unvs_name unvsName, ade, bup.pfsn_level pfsnLevel, bup.pfsn_name pfsnName, ach_method teachMethod, bli.std_stage stdStage, bli.inclusion_status inclusionStatus, bile, CONCAT(bia.province, bia.city, bia.district, bia.street, ive_address) address,
oc.campus_name campusName, bii.item_code itemCode, bia.apply_time applyTime, bso.fee_amount feeAmount, _scale zmScale, upon_sc ale couponScale,
(bso.pay_amount+bso.demurrage_scale)AS actualAmount, bii.status,w_learn_id,1,0)AS hasChange, port_status exportStatus
FROM
bms.m bii
LEFT JOIN bms.a bia ON bia.apply_id = bii.apply_id
LEFT JOIN bms.i bli ON bli.learn_id = bii.sub_learn_id
LEFT JOIN bms.u bu ON bu.unvs_id = bli.unvs_id
LEFT JOIN bms.p bup ON bup.pfsn_id = bli.pfsn_id
LEFT JOIN bms.s oc ON oc.campus_id = recruit_campus_id
LEFT JOIN pay.r bso ON bso.sub_order_no = bii.sub_order_no
LEFT JOIN bms.e bsc w_learn_id = bli.learn_id
</select>
客制版resultSets
上⾯说到,⽼⼤⾃⼰写了⼀套对resultSets处理的插件,基于学习的⾓度,知道⼤家都懒得看⽂字,也是⼀样,直接上代码
@Intercepts(@Signature(method ="handleResultSets", type = ResultSetHandler.class, args ={ java.sql.Statement.class})) /**
* @desc 对结果集处理
*/
public class ResultHandlerInterceptor implements Interceptor {
private static Logger logger = Logger(ResultHandlerInterceptor.class);
@Override
public Object intercept(Invocation invocation)throws Throwable {//获取参数值,调⽤execHandlerResult⽅法进⾏处理
ResultSetHandler resultSetHandler =(ResultSetHandler) Target();
MappedStatement mappedStatement =(MappedStatement) FieldValue(resultSetHandler, "mappedStatement");
SqlCommandType sqlCommandType = SqlCommandType();
if(sqlCommandType == SqlCommandType.SELECT){
String mapper = StringUtil.ResultSets());
logger.info("ResultHandlerInterceptor.intercept,mapperRow:{}", mapper);
if(!StringUtil.isEmpty(mapper)){
Statement statement =(Statement) Args()[0];
return execHandlerResult(mapper, ResultSet());
}
}
return invocation.proceed();
}
/**
* @dsec 客制化处理resultSet结果集
* @param rs
*/
private Object execHandlerResult(String mapper, ResultSet rs)throws SQLException {
try{
ResultMapper resultMapper = BeanIgnoreEx(mapper);
if(resultMapper != null){
return resultMapper.handler(rs);
}
}finally{
if(rs != null){
rs.close();
}
}
return null;
}
@Override
public Object plugin(Object target){
return Plugin.wrap(target,this);
}
@Override
public void setProperties(Properties properties){
}
}
在execHandlerResult⽅法中,获取了ResultMapper这个类,这个也是我们⾃⼰的定义的⼀个接⼝
/**
*
* @desc RowMapper 基类处理
* @author lingdian
*
* @param <T>
*/
@FunctionalInterface
public interface ResultMapper {
/**
* @desc 处理整个ResultSet
* @param rs
* @returnresultset 遍历
* @throws SQLException
*/
@SuppressWarnings({"rawtypes","unchecked"})
default Object handler(ResultSet rs)throws SQLException {
List result = wArrayList();
int row =1;
while(rs != null && rs.next()){
result.add(handlerRow(rs, row));
row++;
}
return result;
}
/**
* @desc 处理当条ResultSet
* @param rs
* @return
* @throws SQLException
*/
Object handlerRow(ResultSet rs,int rowNum)throws SQLException;
}
通过这个抽象出来的ResultMapper接⼝,我们可以⾃⼰定义我们的handler⽅法。
好了,下⾯到了我要写这篇博客的⽬的了,就是我在其中感受到了代码的智慧哈哈哈
⾸先看看我实现ResultMapper的FinanceInvoiceItemResultMapper类
@Component("financeInvoiceItemResultMapper")
public class FinanceInvoiceItemResultMapper implements ResultMapper {
@Override
public Object handler(ResultSet rs)throws SQLException {
BaseExportList<BdInvoiceExport> list =new BaseExportList<>();
int row =1;
while(rs != null && rs.next()){
list.Long(1)+"",(BdInvoiceExport)handlerRow(rs,row));
row++;
}
return list;
}
@Override
public Object handlerRow(ResultSet resultSet,int i)throws SQLException {
BdInvoiceExport bdInvoiceExport =new BdInvoiceExport();
bdInvoiceExport.Long(1));
bdInvoiceExport.String(2));
...// 这⾥省去了其他的⼦段,实际上有很多
return bdInvoiceExport;
}
}
这⾥着重看handler⽅法,重写的这个⽅法,我们主要是改变原来的List,将实际类型替换为BaseExportList,这个list是继承了ArrayList的
public class BaseExportList<T>extends ArrayList<T>{
private Map<String, T> data = wHashMap();
public boolean add(String id, T e){
data.put(id, e);
return super.add(e);
}
public T get(String id){
(id);
}
public Map<String, T>getData(){
return data;
}
public Set<String>getKeys(){
return data.keySet();
}
}
通过观察这个List,我们可以很快的感受,⽤这个List我可以不通过循环,直接拿到我查询到的结果的id集合!
接着看回handler⽅法,剩下的也没什么了,就是调⽤BaseExportList的add⽅法,在add的时候就将id分好了。
p.s. 这⾥有个细节,就是BaseExportList的get⽅法是⾥⾯的参数是String类型的,并不是int类型。
⽽下⾯的handlerRow⽅法只是⼀个个取出来映射进去⽽已。
意义
在我这个场景中,利⽤resultSets的意义就在于我在导出数据时,我需要将这些数据改变导出的状态,⼀般做法是循环遍历导出的数据,然后获取这些id再批量修改状态,⽽利⽤的这个resultSets,则不再需要循环遍历了。
/*运⽤场景*/
BaseExportList<BdInvoiceExport> list = bdInvoiceMapper.selectItemExportByQueryInfo(bdInvoiceQuery);
// ......
Set<String> keys = Keys();
bdInvoiceMapper.updateExportStatus(keys);//修改状态
// ......
画外话
实际上,在看到以前同事⽤BaseExportList这个类的时候,我并不知道这个是和我们resultSets属性体系绑定使⽤了,我还是像原来⼀样写resultType,我认为是MyBatis在后⾯进⾏了转换类型,并调⽤了BaseExportList的add⽅法来插值,后⾯发现,在调⽤⽤Keys()时拿不到值,于是开始debug MyBatis,这⼀过程也学习到了很多,以后有机会另写⼀篇博客来总结,这次debug最后得出的结论
是,MyBatis⼀开始是将数据保存在ArrayList中,后⾯确实会转换list类型,但是它是通过反射,来创建⼀个⽤户声明的类型,这⾥
是BaseExportList,然后再调⽤这个对象addAll()⽅法将原来ArrayList的数据保存在BaseExportList中。
后⾯和同事讨论了⼀下,因为BaseExportList是直接继承ArrayList的,⽽ArrayList的addAll⽅法是通过System.arraycopy来实现的,那么如果我们重写了BaseExportList的addAll⽅法,在⾥⾯使⽤add来设值,是不是也可以达到相同的效果嘞,嘿嘿,以后有机会试下

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。