Mybatis(2.2)手写mybatis核心流程3.0版本

面向对象的设计:

面向对象的设计:
		a)类的定义
			能独立描述一个信息,比如说:配置文件信息、映射文件信息、学生、老师
			能独立针对描述的信息,提供对应的功能
		b)类的粒度划分
			根据业务(用户【VIP用户/普通用户/高端用户】)
			根据经验(借鉴别人经验,要有试错精神)
			
		c)类的复用性考虑
			类的拆分的
			
		d)类的隔离性
			当某些功能发生改变的时候,我们是不想将影响范围扩大的。
			
			
注意事项:基本上牵扯到设计层面的东西,都不是一锤子能搞定的事情。
		比如说需求设计、UI设计、面向对象设计等设计是一个不断优化,不断积累经验的过程。
mybatis3.0版本分析
		a)解析流程
			* 全局配置文件		解析类					XMLConfigBuilder(configuration根标签)
				<environments>
				<mappers>
			* 映射配置文件		解析类					XMLMapperBuilder(mapper根标签)
				<select>				Statement解析			XMLStatementBuilder(select标签)
					SQL文本和动态标签						XMLScriptBuilder
				<update>				Statement解析
					SQL文件
					动态标签	
			 * 解析工具类										Dom解析相关的工具类	,专门封装的第三方的API
		b) 执行流程(考虑框架设计的初衷)
			* 对外提供方便程序员调用的执行接口(程序员不想关注JDBC或者mybatis处理细节)			---   设计接口(对外提供CRUD操作)
			* SqlSession内部去执行JDBC处理逻辑
			* 执行JDBC代码的逻辑,可以封装到一个专业的类去处理	----	Executor
			* Executor分为使用二级缓存去处理、使用一级缓存去处理、不使用缓存去处理	--- CachingExecutor、BaseExecutor(抽象类)、SimpleExecutor、BatchExecutor

各类分析

    封装数据的类
		Configuration:封装数据、提供对该数据操作的功能接口
		MappedStatement
		SqlSource:封装数据、提供对该数据操作的功能接口
			...
		SqlNode:封装数据、提供对该数据操作的功能接口
			...
		BoundSql
		ParameterMapping	
	封装业务功能的类
		解析流程
			XMLConfigBuilder:????
			XMLMapperBuilder:????
			XMLStatementBuilder:????
			XMLScriptBuilder:????
			SqlSourceParser:封装#{}解析功能,便于复用
			
		执行流程
			SqlSessionFactoryBuilder类(构建者模式)
			SqlSessionFactoty接口(工厂方法设计模式)
				???
			SqlSession接口
				???
			Executor接口:四大组件之一
				CachingExecutor:缓存执行器,主要针对二级缓存
				BaseExecutor:抽取共性的一级缓存功能(抽象模板方法设计模式)
					SimpleExecutor:简单执行器
					ReuseExecutor:Statement可重用的执行器
					BatchExecutor:可批处理的执行器
					
		Executor--->StatementHandler---->ParameterHandler\ParameterHandler

		StatementHandler接口(策略模式):将statement的相关操作进行抽象并封装
		PreparedStatementHandler:专门去执行statementType为prepared
		SimpleStatementHandler:专门去执行statementType为simple
		CallableStatementHandler:专门去执行statementType为callable
		
		ParameterHandler:专门去处理参数设置的
			DeafultParameterHandler
		
		ResultSetHandler:	
			DefaultResultSetHandler

全局配置文件

<configuration>
	<!-- mybatis 数据源环境配置 -->
	<environments default="dev">
		<environment id="dev">
			<!-- 配置数据源信息 -->
			<dataSource type="DBCP">
				<property name="driver" value="com.mysql.jdbc.Driver"></property>
				<property name="url"
					value="jdbc:mysql://XXX"></property>
				<property name="username" value="XXX"></property>
				<property name="password" value="XXX"></property>
			</dataSource>
		</environment>
	</environments>

	<!-- 映射文件加载 -->
	<mappers>
		<!-- resource指定映射文件的类路径 -->
		<mapper resource="mapper/UserMapper.xml"></mapper>
		<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
		<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
		<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
		<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
	</mappers>
</configuration>

映射文件

<mapper namespace="test">
	<!-- select标签,封装了SQL语句信息、入参类型、结果映射类型 -->
	<select id="findUserById"
		parameterType="com.kkb.mybatis.po.User"
		resultType="com.kkb.mybatis.po.User" statementType="prepared">

		SELECT * FROM user WHERE id = #{id}
		<!-- SELECT * FROM user WHERE id = #{id} AND username like '%${username}' -->

		<!-- and sex = #{sex} AND username like '%${username}' -->
		<if test="username != null and username !='' ">
			AND username like '%${username}'
			<if test="username != null and username !=''">
				AND 1=1
			</if>
		</if>
	</select>
</mapper>

测试代码

根据测试代码,debug模式一步步按照调用顺序贴出来

@Test
	public void testQueryUserById() {
		// 1.指定全局配置文件路径
		String location = "mybatis-config.xml";
		// 2.加载配置文件成InputStream
		// 思考:到底想根据路径获取的是字节流还是字符流
		InputStream inputStream = Resources.getResourceAsStream(location);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

		// SqlSession表示一个SQL会话,每次都new,如果对于SqlSession的创建细节,程序员不想关注
		// 此时可以将SqlSession交给专业的Factory去生产

		SqlSession sqlSession = sqlSessionFactory.openSqlSession();
		String statementId = "test" + "." + "findUserById";
		User user = new User();
		user.setId(1);
		// user.setUsername("王五");

		List<User> users = sqlSession.selectList(statementId, user);

		System.out.println(users);
	}

mybatis.io包下

Resources 类

public class Resources {

	public static InputStream getResourceAsStream(String location) {
		return Resources.class.getClassLoader().getResourceAsStream(location);
	}
	public static Reader getResourceAsReader(String location) {
		// TODO
		return null;
	}
}

mybatis.sqlsession 包

SqlSessionFactoryBuilder 类

  • 使用构建者模式
public class SqlSessionFactoryBuilder {

	// 构建者通过这个public的api去接收外部的建造条件
	public SqlSessionFactory build(InputStream inputStream) {
		Document document = DocumentUtils.loadDocument(inputStream);

		XMLConfigBuilder configBuilder = new XMLConfigBuilder();
		Configuration configuration = configBuilder.parse(document.getRootElement());
		return build(configuration);
	}

	public SqlSessionFactory build(Reader reader) {
		return null;
	}

	private SqlSessionFactory build(Configuration configuration) {
		return new DefaultSqlSessionFactory(configuration);
	}
}

SqlSessionFactory 接口

public interface SqlSessionFactory {

	SqlSession openSqlSession();
}

SqlSessionFactory 类,实现DefaultSqlSessionFactory 接口

  • 职责只是创建SqlSession对象,不负责配置文件的解析工作
public class DefaultSqlSessionFactory implements SqlSessionFactory {

	// 我既然不负责Configuration的解析,那么我就需要被外部注入一个configuration
	private Configuration configuration;

	public DefaultSqlSessionFactory(Configuration configuration) {
		this.configuration = configuration;
	}

	@Override
	public SqlSession openSqlSession() {
		return new DefaultSqlSession(configuration);
	}
}

SqlSession 接口

public interface SqlSession {

	<T> T selectOne(String statementId, Object param);

	<T> List<T> selectList(String statementId, Object param);

	int insert(String statementId, Object param);
}

DefaultSqlSession 实现 Sqlsession接口

public class DefaultSqlSession implements SqlSession {

	private Configuration configuration;

	public DefaultSqlSession(Configuration configuration) {
		this.configuration = configuration;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T selectOne(String statementId, Object param) {
		List<Object> list = this.selectList(statementId, param);
		if (list != null && list.size() == 1) {
			return (T) list.get(0);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> selectList(String statementId, Object param) {
		MappedStatement mappedStatement = configuration.getMappedStatementById(statementId);
		if (mappedStatement == null) {
			return null;
		}
		try {
			// TODO Executor executor = new CachingExecutor();
			Executor executor = configuration.newExecutor();
			return (List<T>) executor.query(configuration, mappedStatement, param, null);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public int insert(String statementId, Object param) {
		// TODO Auto-generated method stub
		return 0;
	}
}

mybatis.mapping 包

Configuration 类

  • 封装XML配置文件中的信息 封装mybatis-config.xml和*mapper.xml中存储的数据
public class Configuration {

	private boolean useCache = true;

	// 封装MappedStatement对象集合
	private Map<String, MappedStatement> mappedStatements = new HashMap<String, MappedStatement>();

	// 封装数据源对象
	private DataSource dataSource;

	public MappedStatement getMappedStatementById(String statementId) {
		return this.mappedStatements.get(statementId);
	}

	public void addMappedStatement(String statementId, MappedStatement mappedStatement) {
		this.mappedStatements.put(statementId, mappedStatement);
	}

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public Executor newExecutor() {
		Executor executor = null;
		// 可以通过配置文件,去指定使用哪种Executor
		// 默认创建的是SimpleExecutor
		executor = new SimpleExecutor();
		// 默认优先使用二级缓存执行器CachingExecutor
		if (useCache) {
			executor = new CachingExecutor(executor);
		}
		return executor;
	}

	public StatementHandler newStatementHandler(Configuration configuration, MappedStatement mappedStatement,
			BoundSql boundSql) {
		StatementHandler statementHandler = null;
		switch (mappedStatement.getStatementType()) {
		case "prepared":
			statementHandler = new PreparedStatementHandler(configuration, mappedStatement, boundSql);
			break;
		case "simple":

			// statementHandler = new SimpleStatementHandler(mappedStatement, boundSql);
			break;

		default:
			break;
		}
		return statementHandler;
	}

	public ParameterHandler newParameterHandler(MappedStatement mappedStatement, BoundSql boundSql) {
		return new DefaultParameterHandler(mappedStatement, boundSql);
	}

	public ResultSetHandler newResultSetHandler(MappedStatement mappedStatement) {
		return new DefaultResultSetHandler(mappedStatement);
	}
}

MappedStatement 类

  • 用来封装映射文件中的CRUD标签脚本内容,比如select标签
public class MappedStatement {

	private String statementId;
	private SqlSource sqlSource;

	private String statementType;

	private Class<?> parameterTypeClass;
	private Class<?> resultTypeClass;

	public MappedStatement(String statementId, Class<?> parameterTypeClass, Class<?> resultTypeClass,
			String statementType, SqlSource sqlSource) {
		this.statementId = statementId;
		this.parameterTypeClass = parameterTypeClass;
		this.resultTypeClass = resultTypeClass;
		this.statementType = statementType;
		this.sqlSource = sqlSource;
	}

	public SqlSource getSqlSource() {
		return sqlSource;
	}

	public void setSqlSource(SqlSource sqlSource) {
		this.sqlSource = sqlSource;
	}

	public String getStatementType() {
		return statementType;
	}

	public void setStatementType(String statementType) {
		this.statementType = statementType;
	}

	public String getStatementId() {
		return statementId;
	}

	public void setStatementId(String statementId) {
		this.statementId = statementId;
	}

	public Class<?> getParameterTypeClass() {
		return parameterTypeClass;
	}

	public void setParameterTypeClass(Class<?> parameterTypeClass) {
		this.parameterTypeClass = parameterTypeClass;
	}

	public Class<?> getResultTypeClass() {
		return resultTypeClass;
	}

	public void setResultTypeClass(Class<?> resultTypeClass) {
		this.resultTypeClass = resultTypeClass;
	}
}

DynamicContext 类

  • 动态上下文,就是封装的入参信息,解析过程中的SQL信息
public class DynamicContext {

	private StringBuffer sb = new StringBuffer();

	private HashMap<String, Object> bindings = new HashMap<>();
	
	public DynamicContext(Object param) {
		bindings.put("_parameter", param);
	}

	public String getSql() {
		return sb.toString();
	}

	public void appendSql(String sqlText) {
		this.sb.append(sqlText);
		this.sb.append(" ");
	}

	public HashMap<String, Object> getBindings() {
		return bindings;
	}

	public void addBinding(String name, Object param) {
		this.bindings.put(name, param);
	}
}

ParameterMapping 类

  • 从#{}中解析出来的参数信息,包括参数名称和类型
public class ParameterMapping {

	private String name;
	private Class<?> type;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Class<?> getType() {
		return type;
	}
	public void setType(Class<?> type) {
		this.type = type;
	}
	public ParameterMapping(String name) {
		super();
		this.name = name;
	}	
}

BoundSql 类

  • 封装解析之后的SQL信息,以及解析占位符?时产生的参数信息
public class BoundSql {

	// 解析之后的SQL语句
	private String sql;

	// 解析过程中产生的SQL参数信息
	private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();

	public BoundSql(String sql, List<ParameterMapping> parameterMappings) {
		this.sql = sql;
		this.parameterMappings = parameterMappings;
	}

	public String getSql() {
		return sql;
	}

	public void setSql(String sql) {
		this.sql = sql;
	}

	public List<ParameterMapping> getParameterMappings() {
		return parameterMappings;
	}

	public void addParameterMappings(ParameterMapping parameterMapping) {
		this.parameterMappings.add(parameterMapping);
	}
}

mybatis.builder 包

XMLConfigBuilder 类

  • 解析全局配置文件
public class XMLConfigBuilder {
	private Configuration configuration;

	public XMLConfigBuilder() {
		configuration = new Configuration();
	}

	public Configuration parse(Element rootElement) {
		Element environments = rootElement.element("environments");
		parseEnvironments(environments);

		Element mappers = rootElement.element("mappers");
		parseMappers(mappers);

		return configuration;
	}

	@SuppressWarnings("unchecked")
	private void parseMappers(Element mappers) {
		List<Element> mapperElements = mappers.elements("mapper");
		for (Element mapperElement : mapperElements) {
			parseMapper(mapperElement);
		}
	}

	private void parseMapper(Element mapperElement) {
		String resource = mapperElement.attributeValue("resource");

		InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resource);
		Document document = DocumentUtils.loadDocument(inputStream);

		// 解析映射文件XMLMapperBuilder
		XMLMapperBuilder mapperBuilder = new XMLMapperBuilder(configuration);
		mapperBuilder.parse(document.getRootElement());
	}

	@SuppressWarnings("unchecked")
	private void parseEnvironments(Element environments) {
		String def = environments.attributeValue("default");
		List<Element> elements = environments.elements("environment");
		for (Element envElement : elements) {
			String id = envElement.attributeValue("id");
			if (id.equals(def)) {
				parseEnvironment(envElement);
			}
		}
	}

	private void parseEnvironment(Element envElement) {
		Element dataSource = envElement.element("dataSource");
		parseDataSource(dataSource);
	}

	@SuppressWarnings("unchecked")
	private void parseDataSource(Element dataSourceElement) {
		String type = dataSourceElement.attributeValue("type");
		if ("DBCP".equals(type)) {
			BasicDataSource dataSource = new BasicDataSource();

			Properties properties = new Properties();

			List<Element> propertyElements = dataSourceElement.elements();
			for (Element prop : propertyElements) {
				String name = prop.attributeValue("name");
				String value = prop.attributeValue("value");
				properties.put(name, value);
			}

			dataSource.setDriverClassName(properties.getProperty("driver"));
			dataSource.setUrl(properties.getProperty("url"));
			dataSource.setUsername(properties.getProperty("username"));
			dataSource.setPassword(properties.getProperty("password"));

			configuration.setDataSource(dataSource);
		}
	}
}

XMLMapperBuilder 类

  • 解析映射文件
public class XMLMapperBuilder {

	private Configuration configuration;

	private String namespace;

	public XMLMapperBuilder(Configuration configuration) {
		this.configuration = configuration;
	}

	@SuppressWarnings("unchecked")
	public void parse(Element rootElement) {
		// 为了方便管理statement,需要使用statement唯一标识
		namespace = rootElement.attributeValue("namespace");
		//其他mapper映射文件中的标签		
		//select标签的处理
		List<Element> selectElements = rootElement.elements("select");
		for (Element selectElement : selectElements) {
			XMLStatementBuilder builder = new XMLStatementBuilder(configuration);
			builder.parseStatementElement(selectElement,namespace);
		}
	}
}

XMLStatementBuilder 类

  • 解析crud标签
public class XMLStatementBuilder {
	private Configuration configuration;

	public XMLStatementBuilder(Configuration configuration) {
		this.configuration = configuration;
	}

	public void parseStatementElement(Element selectElement, String namespace) {
		String statementId = selectElement.attributeValue("id");

		if (statementId == null || selectElement.equals("")) {
			return;
		}
		// 一个CURD标签对应一个MappedStatement对象
		// 一个MappedStatement对象由一个statementId来标识,所以保证唯一性
		// statementId = namespace + "." + CRUD标签的id属性
		statementId = namespace + "." + statementId;

		String parameterType = selectElement.attributeValue("parameterType");
		Class<?> parameterClass = resolveType(parameterType);

		String resultType = selectElement.attributeValue("resultType");
		Class<?> resultClass = resolveType(resultType);

		String statementType = selectElement.attributeValue("statementType");
		statementType = statementType == null || statementType == "" ? "prepared" : statementType;

		// 解析SQL信息
		SqlSource sqlSource = createSqlSource(selectElement);

		// TODO 建议使用构建者模式去优化
		MappedStatement mappedStatement = new MappedStatement(statementId, parameterClass, resultClass, statementType,
				sqlSource);
		configuration.addMappedStatement(statementId, mappedStatement);

	}

	private SqlSource createSqlSource(Element selectElement) {
		// 去解析select等CURD标签中的SQL脚本信息
		XMLScriptBuilder builder = new XMLScriptBuilder();
		SqlSource sqlSource = builder.parseScriptNode(selectElement);
		return sqlSource;
	}

	private Class<?> resolveType(String parameterType) {
		try {
			Class<?> clazz = Class.forName(parameterType);
			return clazz;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
}

XMLScriptBuilder 类

  • 解析sql脚本信息
public class XMLScriptBuilder {

	private boolean isDynamic;

	public SqlSource parseScriptNode(Element selectElement) {
		// 1.解析出来所有的SqlNode信息
		MixedSqlNode rootSqlNode = parseDynamicTags(selectElement);
		// isDynamic是parseDynamicTags过程中,得到的值
		// 如果包含${}或者包含动态标签,则isDynamic为true
		SqlSource sqlSource;
		// 2.将SqlNode信息封装到SqlSource中,并且要根据是否动态节点去选择不同的SqlSource
		// 如果isDynamic为true,则说明SqlNode集合信息里面包含${}SqlNode节点信息或者动态标签的节点信息
		if (isDynamic) {
			sqlSource = new DynamicSqlSource(rootSqlNode);
		} else {
			sqlSource = new RawSqlSource(rootSqlNode);
		}

		return sqlSource;
	}

	private MixedSqlNode parseDynamicTags(Element selectElement) {
		List<SqlNode> sqlNodes = new ArrayList<>();
		int nodeCount = selectElement.nodeCount();
		// 获取select标签的子标签
		for (int i = 0; i < nodeCount; i++) {
			Node node = selectElement.node(i);
			// 区分是文本标签还是元素标签
			if (node instanceof Text) {
				String sqlText = node.getText().trim();
				if (sqlText == null || "".equals(sqlText)) {
					continue;
				}
				TextSqlNode textSqlNode = new TextSqlNode(sqlText);
				if (textSqlNode.isDynamic()) {
					// 设置是否动态为true
					isDynamic = true;
					sqlNodes.add(textSqlNode);
				} else {
					sqlNodes.add(new StaticTextSqlNode(sqlText));
				}
			} else if (node instanceof Element) {
				// 获取动态标签的标签名称
				String nodeName = node.getName();
				// TODO 设计模式优化
				if ("if".equals(nodeName)) {
					// 封装成IfSqlNode(test信息、子标签信息)
					Element element = (Element) node;
					// if标签的test属性信息
					String test = element.attributeValue("test");
					// if标签的子标签信息
					MixedSqlNode rootSqlNode = parseDynamicTags(element);

					// IfSqlNode就是封装if标签信息的
					IfSqlNode ifSqlNode = new IfSqlNode(test, rootSqlNode);
					sqlNodes.add(ifSqlNode);
				}
				isDynamic = true;
			}
		}
		return new MixedSqlNode(sqlNodes);
	}
}

mybatis.executor 包

Executor 接口

  • 执行JDBC代码
public interface Executor {

	Object query(Configuration configuration, MappedStatement mappedStatement, Object param, BoundSql boundSql)
			throws Exception;
}

BaseExecutor 实现 Executor 接口

  • 只处理一级缓存的逻辑
public abstract class BaseExecutor implements Executor {

	@Override
	public Object query(Configuration configuration, MappedStatement mappedStatement, Object param, BoundSql boundSql)
			throws Exception {
		// 如果一级缓存没有,则直接查询数据库

		// 查询数据库的方式有多种:批量查询、简单查询
		return queryFromDataBase(configuration, mappedStatement, param, boundSql);
	}

	public abstract Object queryFromDataBase(Configuration configuration, MappedStatement mappedStatement, Object param,
			BoundSql boundSql);
}

CachingExecutor 实现 Executor

public class CachingExecutor implements Executor {

	// 一级缓存
	// TODO private Executor delegate = new SimpleExecutor();
	private Executor delegate;

	public CachingExecutor(Executor executor) {
		this.delegate = executor;
	}

	@Override
	public Object query(Configuration configuration, MappedStatement mappedStatement, Object param, BoundSql boundSql)
			throws Exception {
		// 如果没有二级缓存key:BoundSql+其他
		// 获取SqlSource
		SqlSource sqlSource = mappedStatement.getSqlSource();
		// 执行SqlSource去获取Sql信息
		boundSql = sqlSource.getBoundSql(param);
		// 委托一级缓存去处理
		return delegate.query(configuration, mappedStatement, param, boundSql);
	}
}

SimpleExecutor 继承 BaseExecutor

public class SimpleExecutor extends BaseExecutor {

	@Override
	public Object queryFromDataBase(Configuration configuration, MappedStatement mappedStatement, Object param,
			BoundSql boundSql) {

		Connection connection = null;
		Statement statement = null;

		try {
			// 1、获取Connection
			connection = getConnection(configuration);
			// 2、获取可以JDBC执行的SQL语句
			if (mappedStatement == null) {
				return null;
			}
			// 获取JDBC可以直接执行的SQL语句
			// TODO String sql = boundSql.getSql();
			StatementHandler statementHandler = configuration.newStatementHandler(configuration, mappedStatement,
					boundSql);
			// 去创建Statement
			statement = statementHandler.prepare(connection);
			// 参数设置
			statementHandler.parameterize(statement, param);

			// 执行Statement
			return statementHandler.query(statement);

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 释放资源
			/*
			 * if (rs != null) { try { rs.close(); } catch (SQLException e) {
			 * e.printStackTrace(); } } if (preparedStatement != null) { try {
			 * preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); }
			 * } if (connection != null) { try { connection.close(); } catch (SQLException
			 * e) { // TODO Auto-generated catch block e.printStackTrace(); } }
			 */
		}
		return null;
	}

	private Connection getConnection(Configuration configuration) throws Exception {
		DataSource dataSource = configuration.getDataSource();
		Connection connection = dataSource.getConnection();
		return connection;
	}
}

mybatis.handler 包

StatementHandler 接口

  • 处理Statement信息
public interface StatementHandler {

	Statement prepare(Connection connection);

	void parameterize(Statement statement, Object param);

	<E> List<E> query(Statement statement);
}

PreparedStatementHandler 实现 StatementHandler接口

public class PreparedStatementHandler implements StatementHandler {

	private BoundSql boundSql;

	private ParameterHandler parameterHandler;
	private ResultSetHandler resultSetHandler;

	public PreparedStatementHandler(Configuration configuration, MappedStatement mappedStatement, BoundSql boundSql) {
		this.boundSql = boundSql;

		// 初始化一个参数处理器,专门处理预处理的参数
		parameterHandler = configuration.newParameterHandler(mappedStatement, boundSql);
		resultSetHandler = configuration.newResultSetHandler(mappedStatement);
	}

	@Override
	public Statement prepare(Connection connection) {
		PreparedStatement statement = null;
		try {
			statement = connection.prepareStatement(boundSql.getSql());
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return statement;
	}

	@Override
	public void parameterize(Statement statement, Object param) {
		parameterHandler.handleParameter(statement, param);
		// handleParameter(preparedStatement, mappedStatement, boundSql, param);
	}

	@Override
	public <E> List<E> query(Statement statement) {
		try {
			PreparedStatement preparedStatement = (PreparedStatement) statement;
			ResultSet rs = preparedStatement.executeQuery();

			// 6、处理结果集
			// handleResultSet(rs, mappedStatement)
			return resultSetHandler.handleResultSet(rs);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
}

ParameterHandler 接口

  • 设置参数接口
public interface ParameterHandler {

	void handleParameter(Statement statement, Object param);
}

DefaultParameterHandler 实现ParameterHandler接口

public class DefaultParameterHandler implements ParameterHandler {

	private MappedStatement mappedStatement;

	private BoundSql boundSql;

	public DefaultParameterHandler(MappedStatement mappedStatement, BoundSql boundSql) {
		this.mappedStatement = mappedStatement;
		this.boundSql = boundSql;
	}

	@Override
	public void handleParameter(Statement statement, Object param) {
		try {
			PreparedStatement preparedStatement = (PreparedStatement) statement;
			// 从mappedStatement获取入参的类型
			Class<?> parameterTypeClass = mappedStatement.getParameterTypeClass();
			// 如果入参是8种基本类型和String类型
			if (SimpleTypeRegistry.isSimpleType(parameterTypeClass)) {
				preparedStatement.setObject(1, param);
			} else if (parameterTypeClass == Map.class) {
				// 如果入参是Map类型
				// ....
			} else {
				// 如果入参是POJO类型(比如User类型)
				List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
				for (int i = 0; i < parameterMappings.size(); i++) {
					ParameterMapping parameterMapping = parameterMappings.get(i);
					// 封装的#{}里面的属性名称
					String name = parameterMapping.getName();
					// 利用反射去入参对象根据属性名称获取指定的属性值
					Field field = parameterTypeClass.getDeclaredField(name);
					field.setAccessible(true);
					Object value = field.get(param);
					// TODO 可以使用ParameterMapping里面的type对Object类型的value进行类型处理
					// 设置statement占位符中的值
					preparedStatement.setObject(i + 1, value);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

ResultSetHandler 接口

  • 处理结果集
public interface ResultSetHandler {

	<E> List<E> handleResultSet(ResultSet rs);
}

DefaultResultSetHandler 实现 ResultSetHandler接口

public class DefaultResultSetHandler implements ResultSetHandler {

	private MappedStatement mappedStatement;

	public DefaultResultSetHandler(MappedStatement mappedStatement) {
		this.mappedStatement = mappedStatement;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <E> List<E> handleResultSet(ResultSet rs) {
		try {
			List<Object> results = new ArrayList<Object>();
			Class<?> resultTypeClass = mappedStatement.getResultTypeClass();
			while (rs.next()) {
				// 遍历一次是一行,也对应一个对象,利用反射new一个对象
				Object result = resultTypeClass.newInstance();

				// 要获取每一列的值,然后封装到结果对象中对应的属性名称上
				ResultSetMetaData metaData = rs.getMetaData();
				int columnCount = metaData.getColumnCount();
				for (int i = 0; i < columnCount; i++) {
					// 获取每一列的值
					Object value = rs.getObject(i + 1);

					// 列的名称
					String columnName = metaData.getColumnName(i + 1);
					// 列名和属性名称要严格一致
					Field field = resultTypeClass.getDeclaredField(columnName);
					field.setAccessible(true);
					// 给映射的对象赋值
					field.set(result, value);
				}
				results.add(result);
			}
			return (List<E>) results;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}

mybatis.utils 包(工具类)

TokenHandler 接口

public interface TokenHandler {
  String handleToken(String content);
}

ParameterMappingTokenHandler 实现 TokenHandler

public class ParameterMappingTokenHandler implements TokenHandler {
	private List<ParameterMapping> parameterMappings = new ArrayList<>();

	// content是参数名称
	// content 就是#{}中的内容
	@Override
	public String handleToken(String content) {
		parameterMappings.add(buildParameterMapping(content));
		return "?";
	}

	private ParameterMapping buildParameterMapping(String content) {
		ParameterMapping parameterMapping = new ParameterMapping(content);
		return parameterMapping;
	}

	public List<ParameterMapping> getParameterMappings() {
		return parameterMappings;
	}

	public void setParameterMappings(List<ParameterMapping> parameterMappings) {
		this.parameterMappings = parameterMappings;
	}
}

DocumentUtils 类

public class DocumentUtils {
	public static Document loadDocument(InputStream inputStream) {
		try {
			SAXReader saxReader = new SAXReader();
			Document document = saxReader.read(inputStream);
			return document;
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return null;
	}
}

OgnlUtils 类

  • 根据Ongl表达式,获取指定对象的参数值
public class OgnlUtils {
	/**
	 * 根据Ongl表达式,获取指定对象的参数值
	 * @param expression
	 * @param paramObject
	 * @return
	 */
	public static Object getValue(String expression, Object paramObject) {
		try {
			OgnlContext context = new OgnlContext();
			context.setRoot(paramObject);

			//mybatis中的动态标签使用的是ognl表达式
			//mybatis中的${}使用的是ognl表达式
			Object ognlExpression = Ognl.parseExpression(expression);// 构建Ognl表达式
			Object value = Ognl.getValue(ognlExpression, context, context.getRoot());// 解析表达式

			return value;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 通过Ognl表达式,去计算boolean类型的结果
	 * @param expression
	 * @param parameterObject
	 * @return
	 */
	public static boolean evaluateBoolean(String expression, Object parameterObject) {
		Object value = OgnlUtils.getValue(expression, parameterObject);
		if (value instanceof Boolean) {
			return (Boolean) value;
		}
		if (value instanceof Number) {
			return new BigDecimal(String.valueOf(value)).compareTo(BigDecimal.ZERO) != 0;
		}
		return value != null;
	}
}

SimpleTypeRegistry 类

public class SimpleTypeRegistry {

  private static final Set<Class<?>> SIMPLE_TYPE_SET = new HashSet<>();

  static {
    SIMPLE_TYPE_SET.add(String.class);
    SIMPLE_TYPE_SET.add(Byte.class);
    SIMPLE_TYPE_SET.add(Short.class);
    SIMPLE_TYPE_SET.add(Character.class);
    SIMPLE_TYPE_SET.add(Integer.class);
    SIMPLE_TYPE_SET.add(Long.class);
    SIMPLE_TYPE_SET.add(Float.class);
    SIMPLE_TYPE_SET.add(Double.class);
    SIMPLE_TYPE_SET.add(Boolean.class);
    SIMPLE_TYPE_SET.add(Date.class);
    SIMPLE_TYPE_SET.add(Class.class);
    SIMPLE_TYPE_SET.add(BigInteger.class);
    SIMPLE_TYPE_SET.add(BigDecimal.class);
  }

  public static boolean isSimpleType(Class<?> clazz) {
    return SIMPLE_TYPE_SET.contains(clazz);
  }
}

SqlNode 和 SqlSource 类

SqlNode和Sqlsource类在此篇博客中有具体代码

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值