Mybatis框架的原理介绍
一、什么是MyBatis?
是一款优秀的持久层框架,支持动态Sql相比JDBC,减少很多代码,不需要开关连接,只需要修改sql语句。
mybatis优缺点:
1.简单易学,会点Java基础Mysql就可以使用
2.相比JDBC,减少很多代码,不需要开关连接,只需要修改sql语句.
3.很好的与数据库兼容mysql
一、MyBatis怎么初始化?
SqlSessionFactoryBuilder.build(InputStream inputStream, String environment,Properties properties) 用来创建项目,使用解析器,会话工厂等 源码:
/**
* Builds {@link SqlSession} instances.
*
* @author Clinton Begin
*/
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
XMLConfigBuilder.parseConfiguration(XNode root)解析核心配置,赋值给configuration对象
SqlSourceBuilder类是如何解析获取sql语句的
public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
// 对#{}这样的字符串内容的解析处理类
ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
// 获取真实的可执行性的sql语句
String sql = parser.parse(originalSql);
// 包装成StaticSqlSource返回
return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
}
mybatis源码类型装换
TypeHandler
TypeHandler是类型处理器接口,MyBatis中所有的类型转换器都继承了TypeHandler接口,在TypeHandler接口中定义了如下四个方法,这四个方法分为两类:setParameter()方法负责将数据由JdbeType类型转换成Java类型;getResult()方法及其重载负责将数据由Java类型转换成JdbcType类型。
public interface TypeHandler<T> {
//在通过PreparedStatement为SQL语句绑定参数时,会将数据由JdbcType类型转换成Java类型
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
//从 ResultSet 中获取数据时会调用此方法,会将数据由Java类型转换成JdbcType类型
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
在BaseTypeHandler
中实现TypeHandler.setParameter()
方法和TypeHandler.getResult()
方法, 具体实现如下所示。需要注意的是,这两个方法对于非空数据的处理都交给了子类实现。
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
//参数 类型 异常
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
}
try {
//绑定参数为null的处理
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException e) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
+ "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
+ "Cause: " + e, e);
}
} else {
try {
//绑定非空参数 该方法为抽象方法 由子类实现
setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception e) {
throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
+ "Try setting a different JdbcType for this parameter or a different configuration property. "
+ "Cause: " + e, e);
}
}
}
public T getResult(ResultSet rs, String columnName) throws SQLException {
try {
//抽象方法 由多个重载 由子类实现
return getNullableResult(rs, columnName);
} catch (Exception e) {
throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e);
}
}
BaseTypeHandler
的实现类比较多,如图所示,但大多是直接调用PreparedStatement
和ResultSet
或CallableStatement
的对应方法,实现比较简单。
这里以IntegerTypeHandler
为例简单介绍,其他的实现类请读者参考相关
public class IntegerTypeHandler extends BaseTypeHandler<Integer> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
throws SQLException {
//调用PreparedStatement.setInt()实现参数绑定
ps.setInt(i, parameter);
}
@Override
public Integer getNullableResult(ResultSet rs, String columnName)
throws SQLException {
//调用PreparedStatement.getInt()获取指定列值
int result = rs.getInt(columnName);
return result == 0 && rs.wasNull() ? null : result;
}
@Override
public Integer getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
//调用ResultSet.getInt()获取指定列值
int result = rs.getInt(columnIndex);
return result == 0 && rs.wasNull() ? null : result;
}
@Override
public Integer getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
//调用CallableStatement.getInt()获取指定列值
int result = cs.getInt(columnIndex);
return result == 0 && cs.wasNull() ? null : result;
}
}