beetlsql结合mybatis的结果集解析

说明:

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 handleResult(String resultMapid, Statement st) throws SQLException  {
		List maps = new ArrayList<>();
		ResultMap map = configuration.getResultMap(resultMapid);
		maps.add(map);
		
		MappedStatement.Builder builder = new Builder(configuration, "", null,
				null).resultMaps(maps);
		
		DefaultResultSetHandler handler = new DefaultResultSetHandler(
				new SimpleExecutor(configuration, null), builder.build(), null,
				null, null, new RowBounds());
		
		return handler.handleResultSets(st);
	}
	/**
	 * 测试
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		String JDBC_DRIVER = "com.mysql.jdbc.Driver";
		String DB_URL = "jdbc:mysql://localhost/test1";
		String USER = "root";
		String PASS = "123456";

		Connection conn = null;
		Statement stmt = null;
		
		Class.forName(JDBC_DRIVER);
		
		conn = DriverManager.getConnection(DB_URL, USER, PASS);

		stmt = conn.createStatement();
		String sql;
		sql = " select id iiid from user where id = 20";
		stmt.executeQuery(sql);
		
		List list = handleResult("ccc.user", stmt);
	}

	
}
 
  
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查询映射成功;

单个查询映射成功。

这个结合需要注意的是:开发者模式是线程不安全的。但也无妨,毕竟是开发者模式嘛,没什么线程不线程的。

你可能感兴趣的:(模板)