1、mybatis源码搭建
进入mybatis github仓库地址,然后fork到自己的仓库找到自己仓库中fork过来的项目,然后git clone url 到本地,需要和源项目保持同步,需要git remote add upstream fork_url,那么本地会有两个远程地址分别为origin和upstream(可以通过git remote -v查看),origin对应自己的仓库,upstream对应fork源项目的仓库。实现fork的项目和原项目同步的方法是利用本地的项目作为“中转”,为本地的项目添加两个远程信息,拉取原仓库的新代码,push到自己的仓库上,就达到了“同步”。在master分支上新建并切换到自己开发的一个分支,如dev,如果需要和源项目保持同步,可以git fetch upstream master 然后进行合并到dev分支上。改完代码后把dev合并到master分支,然后push到自己的远程仓库在github上点击pull request栏右上角的New pull request然后github会自动对比原仓库分支与自己仓库分支代码,看看是否有冲突。如果它显示Able to merge的话,就可以点击Create pull request 按钮,进行提交。然后进入说明部分,可以跟原作者说明改动了什么,以及改的原因等。最后点击绿色的Create pull request 即可。然后原作者就会收到pull request了。你也完成了对项目的贡献。Mybatis提供了一个简单的逻辑分页使用类RowBounds(逻辑分页就是查询出对应条件所有数据然后再逻辑处理分页逻辑,物理分页当然就是我们在sql语句中指定limit和offset值),在DefaultSqlSession提供的某些查询接口中我们可以看到RowBounds是作为参数用来进行分页的,如下接口:
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds)RowBounds源码如下:
public class RowBounds { /* 默认offset是0**/ public static final int NO_ROW_OFFSET = 0; /* 默认Limit是int的最大值,因此它使用的是逻辑分页**/ public static final int NO_ROW_LIMIT = Integer.MAX_VALUE; public static final RowBounds DEFAULT = new RowBounds(); private int offset; private int limit; public RowBounds() { this.offset = NO_ROW_OFFSET; this.limit = NO_ROW_LIMIT; } public RowBounds(int offset, int limit) { this.offset = offset; this.limit = limit; } public int getOffset() { return offset; } public int getLimit() { return limit; } }逻辑分页的实现原理:
在DefaultResultSetHandler中,逻辑分页会将所有的结果都查询到,然后根据RowBounds中提供的offset和limit值来获取最后的结果,DefaultResultSetHandler实现如下:
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>(); //跳过RowBounds设置的offset值 skipRows(rsw.getResultSet(), rowBounds); //判断数据是否小于limit,如果小于limit的话就不断的循环取值 while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null); Object rowValue = getRowValue(rsw, discriminatedResultMap); storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); } } private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) throws SQLException { //判断数据是否小于limit,小于返回true return !context.isStopped() && context.getResultCount() < rowBounds.getLimit(); } //跳过不需要的行,应该就是rowbounds设置的limit和offset private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException { if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) { if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) { rs.absolute(rowBounds.getOffset()); } } else { //跳过RowBounds中设置的offset条数据 for (int i = 0; i < rowBounds.getOffset(); i++) { rs.next(); } } }总结:Mybatis的逻辑分页比较简单,简单来说就是取出所有满足条件的数据,然后舍弃掉前面offset条数据,然后再取剩下的数据的limit条
mybatis xml中if条件判断中的字段写成数据库字段,导致后续mybatis解析xml中的条件配置,解析出对应字段映射不到对应的java代码中DO的字段,导致查询失败。如:
If标签中的判断要使用DO中传入的字段,不能使用数据库字段,因为IF条件并不需要拼接到sql语句,只需要拼接If标签内部的内容,所以不要写成数据库字段特别是有下划线字段,会报错找不到对应DO中的字段。这是mybatis需要通过If标签中的条件解析出对应的字段,并且通过getxxx方法取出对应字段的值,然后才能判断是否拼接IF内部的条件部分。