一.第一步创建连接
public static void main(String[] args){ String resource = "nor/mybatis.xml"; InputStream inputStream = null; SqlSessionFactory factory = null; try { inputStream = Resources.getResourceAsStream(resource); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //factory里面有个configuration属性,是Configuration对象的,他里面存了xml解析出来的东西 // factory = builder.build(inputStream); } catch (IOException e) { e.printStackTrace(); } //开启一个事务 SqlSession sqlSession=factory.openSession(); UserBean userBean=new UserBean(); userBean.setUser_name("sbsbsb"); //sqlSession.insert("com.x.nor.UserMapper.insert",userBean); //sqlSession.commit(); //UserBean user=sqlSession.selectOne("com.x.nor.UserMapper.select",new UserBean(1,"ff")); UserBean user=sqlSession.selectOne("com.x.nor.UserMapper.selectDy",new UserBean(1,"ff")); System.out.println(userBean.user_id); System.out.println(user.getUser_name()); //获得代理类,代理类的方法实际上还是调用sqlSession的方法namespace+id User userMapper = sqlSession.getMapper(User.class); UserBean userBean1=userMapper.select(new UserBean(1,"ff")); }
在builder.build(inputStream)中解析了xml生成了一个config,这个var5就是SqlSessionFactory
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); var5 = this.build(parser.parse());
然后进入SqlSession sqlSession=factory.openSession();
这边进入DefaultSqlSessionFactory打开一个sqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; DefaultSqlSession var8; try { //这个是配置文件里面的environment标签里的 Environment environment = this.configuration.getEnvironment(); //打开一个jdbc事务 TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); //默认是caching类型的 Executor executor = this.configuration.newExecutor(tx, execType); //这边吧上面的东西封装进去自动提交设置autoCommit是false的 var8 = new DefaultSqlSession(this.configuration, executor, autoCommit); } catch (Exception var12) { this.closeTransaction(tx); throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12); } finally { ErrorContext.instance().reset(); } return var8; }这边默认生成的Executor是Caching类型的,用了装饰器模式
然后返回main方法执行一条查询
sqlSession.selectOne("com.x.nor.UserMapper.selectDy",new UserBean(1,"ff"));
就是执行selectList然后获取第一条数据
public <T> T selectOne(String statement, Object parameter) { List<T> list = this.selectList(statement, parameter); if (list.size() == 1) { return list.get(0); } else if (list.size() > 1) { throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); } else { return null; } }
到达selectList方法里面configuration这个就是我们之前注入的xml解析之后的放置类
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { List var5; try { //进去获取MappedStatement MappedStatement ms = this.configuration.getMappedStatement(statement); var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); } catch (Exception var9) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + var9, var9); } finally { ErrorContext.instance().reset(); } return var5; }
然后进去,这边进去看看是否需要初始化一下
然后这个我们的idMap<String, MappedStatement> mappedStatements这个是个map,里面的MappedStatement就是我们的namespace+id组成的,保存着一条sql,当然里面分为静态和动态的
返回到上面selectList,查询前判断一下数据如果是集合类或者数组的用StrictMap包装一下
private Object wrapCollection(Object object) { DefaultSqlSession.StrictMap map; if (object instanceof Collection) { map = new DefaultSqlSession.StrictMap(); map.put("collection", object); if (object instanceof List) { map.put("list", object); } return map; } else if (object != null && object.getClass().isArray()) { map = new DefaultSqlSession.StrictMap(); map.put("array", object); return map; } else { return object; } }
然后进入查询
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameterObject); CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql); return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
看一下这个ms.getBoundSql这个sqlSource是xml解析好后放进来的,他里面有个contents里面放着静态和动态的
public BoundSql getBoundSql(Object parameterObject) { //获取sql BoundSql boundSql = this.sqlSource.getBoundSql(parameterObject); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings == null || parameterMappings.isEmpty()) { boundSql = new BoundSql(this.configuration, boundSql.getSql(), this.parameterMap.getParameterMappings(), parameterObject); } Iterator var4 = boundSql.getParameterMappings().iterator(); while(var4.hasNext()) { ParameterMapping pm = (ParameterMapping)var4.next(); String rmId = pm.getResultMapId(); if (rmId != null) { ResultMap rm = this.configuration.getResultMap(rmId); if (rm != null) { this.hasNestedResultMaps |= rm.hasNestedResultMaps(); } } } return boundSql; }
接着进入sqlSource的getBoundSql,这边这个rootSqlNode.apply就是遍历里面的sql加入到context里面的stringbuilder
静态直接加入,动态的比如我的if的xml节点的,就会用Ognl这个引擎来执行下参数和语句是否匹配
public BoundSql getBoundSql(Object parameterObject) { DynamicContext context = new DynamicContext(this.configuration, parameterObject); this.rootSqlNode.apply(context); SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(this.configuration); Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings()); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); Iterator var7 = context.getBindings().entrySet().iterator(); while(var7.hasNext()) { Entry<String, Object> entry = (Entry)var7.next(); boundSql.setAdditionalParameter((String)entry.getKey(), entry.getValue()); } return boundSql; }
在回到query方法里面最后的boundsql就是这个样子的
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameterObject); CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql); return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
然后生成缓存key,进入下一个query方法,这边二级缓存都在每一个MappedStatement,也就是一条sql一个缓存
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { //这边是从MappedStatement 获取缓存 Cache cache = ms.getCache(); if (cache != null) { this.flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { this.ensureNoOutParams(ms, parameterObject, boundSql); //这边缓存在TransactionalCacheManager List<E> list = (List)this.tcm.getObject(cache, key); if (list == null) { list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); this.tcm.putObject(cache, key, list); } return list; } } return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
接着往下到BaseExecutor
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); if (this.closed) { throw new ExecutorException("Executor was closed."); } else { if (this.queryStack == 0 && ms.isFlushCacheRequired()) { this.clearLocalCache(); } List list; try { ++this.queryStack; //这边获取一级缓存 list = resultHandler == null ? (List)this.localCache.getObject(key) : null; if (list != null) { this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else {//这边查数据了 list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { --this.queryStack; } //省略 return list; } }
这边进行正式查询略过
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER); List list; try { list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { this.localCache.removeObject(key); } this.localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { this.localOutputParameterCache.putObject(key, parameter); } return list; }
看看用借口来查询
//获得代理类,代理类的方法实际上还是调用sqlSession的方法namespace+id User userMapper = sqlSession.getMapper(User.class); UserBean userBean1=userMapper.select(new UserBean(1,"ff"));
进入
public <T> T getMapper(Class<T> type) { return this.configuration.getMapper(type, this); }
进入代理
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } else { try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception var5) { throw new BindingException("Error getting mapper instance. Cause: " + var5, var5); } } }
查看代理的生成
protected T newInstance(MapperProxy<T> mapperProxy) { return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); } public T newInstance(SqlSession sqlSession) { MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache); return this.newInstance(mapperProxy); }
jdk动态代理然后看MapperProxy里面的invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //省略 MapperMethod mapperMethod = this.cachedMapperMethod(method); return mapperMethod.execute(this.sqlSession, args); }
看看MapperMethod
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) { this.command = new MapperMethod.SqlCommand(config, mapperInterface, method); this.method = new MapperMethod.MethodSignature(config, mapperInterface, method); }
看下sqlCommand,这边获得MappedStatement是用接口名加上方法名
private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName, Class<?> declaringClass, Configuration configuration) { String statementId = mapperInterface.getName() + "." + methodName; //省略 }
然后回到MapperMethod这边就是最后的执行还是sqlsession的方法,command就是sqlcommand
public Object execute(SqlSession sqlSession, Object[] args) { Object param; Object result; switch(this.command.getType()) { case INSERT: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.insert(this.command.getName(), param)); break; case UPDATE: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.update(this.command.getName(), param)); break; case DELETE: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.delete(this.command.getName(), param)); break; case SELECT: if (this.method.returnsVoid() && this.method.hasResultHandler()) { this.executeWithResultHandler(sqlSession, args); result = null; } else if (this.method.returnsMany()) { result = this.executeForMany(sqlSession, args); } else if (this.method.returnsMap()) { result = this.executeForMap(sqlSession, args); } else if (this.method.returnsCursor()) { result = this.executeForCursor(sqlSession, args); } else { param = this.method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(this.command.getName(), param); } break; case FLUSH: result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + this.command.getName()); } if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) { throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ")."); } else { return result; } }