首先通过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
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