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<Object> handleResult(String resultMapid, Statement st) throws SQLException  {
		List<ResultMap> 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<Object> 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 <T> List<T> toBeanList(String sqlId, ResultSet rs, Class<T> type)
			throws SQLException {
		String resultId = BeetlSqlMybatisFunction.map.get(sqlId);
		boolean autoCheck = sm.getSqlLoader().isAutoCheck();
		if (resultId == null){
			throw new RuntimeException("缺少resultId : " + sqlId);
		}
		List<Object> list = MybatisResultHandler.handleResult(resultId, rs.getStatement());
		/**
		 * 如果是開發者模式,要清除綁定
		 * 否則sql模板裏先使用function,再不使用,但Processors()卻沒有清掉。
		 */
		if (autoCheck){
			sm.getProcessors().remove(sqlId);
		}
		return (List<T>) 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);
	/**
	 * 存儲<sqlid,resultid>
	 */
	public static HashMap<String,String> 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

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <mappers>
    <mapper resource="ccc.xml"/>
    <!-- <mapper resource="ddd.xml"/> -->
  </mappers>
</configuration>

ccc.xml

<?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="ccc">
	 <resultMap type="com.bai.btsql.domin.Stu" id="stuResult">
		<id column="sid" property="sid" jdbcType="INTEGER"/>
		<result column="sname" property="sname" jdbcType="VARCHAR"/>
		<association property="te" javaType="com.bai.btsql.domin.Te">
			<id column="tid" property="tid" jdbcType="INTEGER"/>
			<result column="tname" property="tname" jdbcType="VARCHAR"/>
		</association>
	</resultMap> 
	
	
</mapper>

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<Stu> 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查詢映射成功;

單個查詢映射成功。

這個結合需要注意的是:開發者模式是線程不安全的。但也無妨,畢竟是開發者模式嘛,沒什麼線程不線程的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章