mybatis初始化流程

传统开发方式

首先通过Resources获取sqlMapConfig.xml和mapper.xml中的文件流

InputStream resourceAsStream = Resources.class.getClassLoader.getResourceAsStream(path);

之后通过SqlSessionFactoryBuilder的builder方法将字节输入流解析为Configuration,Configuration中主要包括dataSource和sql语句,封装到SqlSessionFactory中并返回

//数据源
private DataSource dataSource;
//map集合: key:statementId value:MappedStatement
private Map mappedStatementMap = new HashMap(); 

 SqlSessionFactory接口有openSession方法,DefaultSqlSessionFactory实现该方法返回

SqlSession,这样就能获取到一个数据库连接
 
public interface SqlSessionFactory {
  public SqlSession openSession();
}
public class DefaultSqlSessionFactory implements SqlSessionFactory {
  private Configuration configuration;
  public DefaultSqlSessionFactory(Configuration configuration) { this.configuration =
configuration;
}
  public SqlSession openSession(){
    return new DefaultSqlSession(configuration);
} }

 SqlSession接口有增删改查等方法的声明,DefaultSqlSession实现后调用Executor接口来完成具体的查询

 
public class DefaultSqlSession implements SqlSession {
  private Configuration configuration;
public DefaultSqlSession(Configuration configuration) {
this.configuration = configuration;
//处理器对象
private Executor simpleExcutor = new SimpleExecutor();
public  List < E > selectList(String statementId, Object...param) throws
Exception {
            MappedStatement mappedStatement =
configuration.getMappedStatementMap().get(statementId);
List query = simpleExcutor.query(configuration, mappedStatement, param);
    return query;
}
//selectOne 中调用 selectList
public  T selectOne(String statementId, Object...params) throws Exception {
    List objects = selectList(statementId, params);
    if (objects.size() == 1) {
        return (T) objects.get(0);
    } else {
throw new RuntimeException("返回结果过多"); }
}
public void close () throws SQLException {
    simpleExcutor.close();
}
} 
  

 SimpleExecutor实现Executor,通过getBoundSql方法将存在参数的#{}替换为?,${}直接替换为值(${}没有经过预编译有sql注入风险,但是${}在传数字时不会有单引号)

 
public class SimpleExecutor implements Executor {  
    private Connection connection = null;
    public  List query(Configuration configuration, MappedStatement
mappedStatement, Object[] param) throws SQLException, NoSuchFieldException,
IllegalAccessException, InstantiationException, IntrospectionException,
InvocationTargetException {
//获取连接
connection = configuration.getDataSource().getConnection();
// select * from user where id = #{id} and username = #{username} String sql =
mappedStatement.getSql(); //对sql进行处理
BoundSql boundsql = getBoundSql(sql);
// select * from where id = ? and username = ?
String finalSql = boundsql.getSqlText();
//获取传入参数类型
Class paramterType = mappedStatement.getParamterType(); //获取预编译preparedStatement对象
PreparedStatement preparedStatement = connection.prepareStatement(finalSql); List parameterMappingList =
boundsql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
ParameterMapping parameterMapping = parameterMappingList.get(i); String name = parameterMapping.getName();
//反射
Field declaredField = paramterType.getDeclaredField(name); declaredField.setAccessible(true);
//参数的值
Object o = declaredField.get(param[0]); //给占位符赋值 preparedStatement.setObject(i + 1, o);
        }
        ResultSet resultSet = preparedStatement.executeQuery();
        Class resultType = mappedStatement.getResultType();
        ArrayList results = new ArrayList();
        while (resultSet.next()) {
            ResultSetMetaData metaData = resultSet.getMetaData();
            (E) resultType.newInstance();
            int columnCount = metaData.getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
//属性名
String columnName = metaData.getColumnName(i); //属性值
Object value = resultSet.getObject(columnName); //创建属性描述器,为属性生成读写方法 PropertyDescriptor propertyDescriptor = new
PropertyDescriptor(columnName, resultType); //获取写方法
Method writeMethod = propertyDescriptor.getWriteMethod();
 
//向类中写入值
                writeMethod.invoke(o, value);
            }
            results.add(o);
        }
        return results;
    }
@Override
    public void close() throws SQLException {
        connection.close();
}
private BoundSql getBoundSql(String sql) { //标记处理类:主要是配合通用标记解析器GenericTokenParser类完成对配置文件等的解 析工作,其中
TokenHandler主要完成处理
ParameterMappingTokenHandler parameterMappingTokenHandler = new
ParameterMappingTokenHandler();
//GenericTokenParser :通用的标记解析器,完成了代码片段中的占位符的解析,然后再根 据给定的
标记处理器(TokenHandler)来进行表达式的处理
//三个参数:分别为openToken (开始标记)、closeToken (结束标记)、handler (标记处 理器) GenericTokenParser genericTokenParser = new GenericTokenParser("# {", "}",
parameterMappingTokenHandler);
        String parse = genericTokenParser.parse(sql);
        List parameterMappings =
parameterMappingTokenHandler.getParameterMappings();
        BoundSql boundSql = new BoundSql(parse, parameterMappings);
        return boundSql;
} }

通过反射将?的sql赋值,获取返回结果集

ResultSet resultSet = preparedStatement.executeQuery();

将结果集进行封装,返回结果,最后释放连接

增删改需要进行commit

代理开发方式

通过配置文件中的包路径进行扫描

利用反射获取对象实例,通过代理模式获取代理对象,执行invoke方法,进行增删改查

设计模式

构建者模式:

在构建SqlSessionFactoryBuilder、Environment时用到了构建者模式,

讲一个复杂对象拆分成多个简单对象,一步一步构建成复杂对象

工厂模式:SqlSessionFactory

代理模式:MapperProxy

你可能感兴趣的:(mybatis-面试题,mysql,mariadb,数据库)