beetlsql各方面都不错,唯独结果集解析是比较坑的。
尽管它提供了RowMapper,但这个依然是传统的一对一,行对行的解析。
尽管它提供了@orm的一些function,但这个仍然需要进一步查询。
而mybatis的结果集解析应该是No.1吧,可以任意自由自定义地封装
所以就想到怎么让mybatis结果集解析放到beetlSql里。
本文的思路和基础在其他博客里,可不看,不影响下面使用。
部分源码解析
mybatis结果集映射工具提取
三个java类,复制粘贴即可,不需要修改。
package com.bai.btsql.mybatis;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.executor.SimpleExecutor;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.MappedStatement.Builder;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
/**
* mybatis的结果集映射做成一个工具
* 本类在真正调用之后不要忘记关闭流
* @author Administrator
*
*/
public class MybatisResultHandler {
public static String configSource = "mybatis-config.xml";
public static Configuration configuration;
static {
init();
}
public static void init() {
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(configSource);
} catch (IOException e) {
throw new RuntimeException(e);
}
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
configuration = sqlSessionFactory.getConfiguration();
}
/**
* 根据resultid对Statement进行处理映射
* @param resultid 格式为"${namespace}.${resultid}"
* @param st
* @return
* @throws SQLException
*/
public static List
package com.bai.btsql.util;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.mapping.BeanProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bai.btsql.mybatis.MybatisResultHandler;
/**
* 自定义BeanProcessor,
* 在进行select-toBeanList的时候使用mybatis的结果集解析
* @author Administrator
*
*/
public class BeetlSqlMybatisBeanProcessor extends BeanProcessor{
private Logger log = LoggerFactory.getLogger(BeetlSqlMybatisFunction.class);
public BeetlSqlMybatisBeanProcessor(SQLManager sm) {
super(sm);
}
@Override
public List toBeanList(String sqlId, ResultSet rs, Class type)
throws SQLException {
String resultId = BeetlSqlMybatisFunction.map.get(sqlId);
boolean autoCheck = sm.getSqlLoader().isAutoCheck();
if (resultId == null){
throw new RuntimeException("缺少resultId : " + sqlId);
}
List list = MybatisResultHandler.handleResult(resultId, rs.getStatement());
/**
* 如果是开发者模式,要清除绑定
* 否则sql模板里先使用function,再不使用,但Processors()却没有清掉。
*/
if (autoCheck){
sm.getProcessors().remove(sqlId);
}
return (List) list;
}
}
package com.bai.btsql.util;
import java.util.HashMap;
import org.beetl.core.Context;
import org.beetl.core.Function;
import org.beetl.sql.core.SQLManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* beetlSql引用mybatis插件的function
* @author Administrator
*
*/
public class BeetlSqlMybatisFunction implements Function{
private Logger log = LoggerFactory.getLogger(BeetlSqlMybatisFunction.class);
/**
* 存储
*/
public static HashMap map = new HashMap<>();
@Override
public Object call(Object[] paras, Context ctx) {
SQLManager manager = (SQLManager) ctx.globalVar.get("_manager");
/**
* 获取是否开发者模式/生产模式
*/
boolean autoCheck = manager.getSqlLoader().isAutoCheck();
String sqlid = (String) ctx.globalVar.get("_id");
/**
* 如果缺少resultId
*/
if (paras == null || paras.length <= 0 ){
throw new RuntimeException("缺少resultId : " + sqlid);
}
String resultId = (String) paras[0];
boolean shouldLoad = isShouldLoadNewBeanProcessor(autoCheck,sqlid);
if (shouldLoad){
map.put(sqlid, resultId);
manager.getProcessors().put(sqlid, new BeetlSqlMybatisBeanProcessor(manager));
}
return null;
}
/**
* 判断是否应该加载新的BeanProcessor
* @param autoCheck
* @param sqlid
* @return
*/
private boolean isShouldLoadNewBeanProcessor(boolean autoCheck, String sqlid) {
/**
* 如果是开发者模式,一直加载
* 如果是生产模式且未加载,则加载
*/
if (autoCheck){
return true;
}
if (!map.containsKey(sqlid)){
return true;
}
return false;
}
}
配置文件如下:前俩都是mybatis的配置文件,后一个是beetlsql的配置文件,将组件注册进去
mybatis-config.xml
ccc.xml
btsql-ext.properties
FN.mybatis=com.bai.btsql.util.BeetlSqlMybatisFunction
新建个te老师类,有id和name
public class Te {
private Integer tid;
private String tname;
。。。
再建个学生类,有id,name和老师
public class Stu {
private Integer sid;
private String sname;
private Te te;
数据建立对应的表
CREATE TABLE `te` (
`tid` int(11) NOT NULL AUTO_INCREMENT,
`tname` varchar(20) DEFAULT NULL,
PRIMARY KEY (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
CREATE TABLE `stu` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`tid` int(11) DEFAULT NULL,
`sname` varchar(11) DEFAULT NULL,
PRIMARY KEY (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
然后新建个stu.md模板,注意写的时候下面加上一个@mybatis("ccc.stuResult");
代表着用mybatis解析,同时里面参数是resultMapid
select
===
SELECT * FROM stu
LEFT JOIN te ON stu.`tid` = te.`tid`
WHERE stu.`sid` = 4
@mybatis("ccc.stuResult");
好了,再在数据库插入一些数据,准备工作完成了。测试一下:
public static void main(String[] args) {
String driver = "com.mysql.jdbc.Driver";
String url ="jdbc:mysql://localhost:3306/test1";
String userName="root";
String password = "123456";
DBStyle dbStyle = new MySqlStyle();
SQLLoader sqlLoader = new ClasspathLoader();
ConnectionSource ds = ConnectionSourceHelper.getSimple(driver, url, userName, password);
NameConversion nc = new UnderlinedNameConversion();
Interceptor[] inters =new Interceptor[]{new DebugInterceptor()};
SQLManager sqlManager = new SQLManager(dbStyle, sqlLoader, ds, nc, inters);
/**
* 查询
*/
List list = sqlManager.select("stu.select", Stu.class);
System.out.println(list);
}
打印结果:
┏━━━━━ Debug [stu.select] ━━━
┣ SQL: SELECT * FROM stu LEFT JOIN te ON stu.`tid` = te.`tid` WHERE stu.`sid` = 4
┣ 参数: []
┣ 位置: com.bai.btsql.util.Sqltest.main(Sqltest.java:38)
┣ 时间: 181ms
┣ 结果: [1]
┗━━━━━ Debug [stu.select] ━━━[Stu [sid=4, sname=ddd, te=Te [tid=2, tname=li]]]
可以看到,sqlid已经映射成功了。
博主已经进行其他的测试:
Mapper查询映射成功;
单个查询映射成功。
这个结合需要注意的是:开发者模式是线程不安全的。但也无妨,毕竟是开发者模式嘛,没什么线程不线程的。