Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 673|回复: 0

[小把戏] 之IBatis.Net系统分页问题的解决

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-6-15 12:00:30 | 显示全部楼层 |阅读模式

      本文想解决园子里大家都关心的Ibatis.Net分页的实现问题。其实我也找了Ibatis.Net分页的解决方案,园子里有一些,奈何没有发现我想要的方式,大都的策略是调用两次SQL Statement,第一次,根据条件查询总记录条数,第二次,根据条件查询从第N行到M行的数据集合,不是这种不能满足条件,恰恰相反,这种写法,完全可以满足现有项目的需求,也很具备SQL调优空间,但有个的弊端,是通过一个查询写几遍。很难复用。感觉很是别扭,我看过在查询较多的系统里,到处充斥这分页的SQL语句,另外一点,本来我们码农们只要关心实现获取业务数据就行了,每次在实现功能的基础上,还要再加上分页的SQL语句,使原本的可能就复杂的语句,变得更加复杂和难以理解。

      为此,我特地Reflect看了Ibatis.Net的源码。根据他的处理逻辑扩展了SqlMapper的接口,增加 IList<T> QueryForListWithPage<T>这种功能。本想通过注入的方式实现的,看过Java的筒子们曾用注入的方式搞定过。可惜Ibatis.Net没有发现这种方式(或许我才疏学浅,没有找到)。貌似MyBatis已经支持。但没有实践过。本文代码只针对Ibatis 1.62版本和使用MSSQL数据库。如果感觉此思路还不错,我的源码是共享滴,完全可以下载源码,改造成你想要的其它方式。

      至于分页的SQL,个人偏好row_number这种方法,其它的如分页存储过程,TOP方式就不费笔墨了。

      话多无益。直接上码  

     //获取学生列表(使用配置GetStudentList的sql,按照id升序排序获取从第八十个到第一百学生)
     var list = mapper.QueryForListWithPage<T>("GetStudentList", paras, "id asc", 80, 100, ref count);

       那么具体实现怎么写呢,我采用c#的扩展方法,扩展了Ibatis.Net标配的SqlMapper功能,看起来类似Ibatis.Net原生态的功能,但又没有破坏Ibatis源码,这种插件式,不会给原有的Ibatis引入任何的Bug. 

        public static class SqlMapperExtension
        {
            private const string PageSql =
                "with cte as( select id0=row_number() over(order by {0}),* from  ({1}) as cte1) select * from cte where id0 between @beginNo and @endNo";
    
            private const string CountSql = "select count(*) {0}";
    
            /// <summary>
            /// 查询分页
            /// </summary>
            /// <typeparam name="T">泛型</typeparam>
            /// <param name="mapper">mapper</param>
            /// <param name="tag">SQL Statement的id</param>
            /// <param name="paramObject">参数</param>
            /// <param name="orderby">查询条件,必须确保数据库中有这一列</param>
            /// <param name="beginNo">开始行数</param>
            /// <param name="endNo">结束行数</param>
            /// <param name="totalCount">总条数</param>
            /// <returns>查询结果</returns>
            public static IList<T> QueryForListWithPage<T>(this ISqlMapper mapper, string tag, object paramObject,string orderby, int beginNo, int endNo, ref int totalCount)
            {
                bool flag = false;
                ISqlMapSession sqlMapSession = mapper.LocalSession;
                if (sqlMapSession == null)
                {
                    sqlMapSession = mapper.CreateSqlMapSession();
                    flag = true;
                }
                try
                {
                    IMappedStatement mappedStatement = mapper.GetMappedStatement(tag);
                    IStatement statement = mappedStatement.Statement;
                    RequestScope request = statement.Sql.GetRequestScope(mappedStatement, paramObject, sqlMapSession);
                    string statementsql = request.PreparedStatement.PreparedSql;
                    string cmdPageSql = string.Format(PageSql, orderby, statementsql);
                    string cmdCountSql = string.Format(CountSql,statementsql.Substring(statementsql.ToLower().IndexOf("from")));
    
                    request.PreparedStatement.PreparedSql = cmdPageSql;
                    request.IDbCommand = new DbCommandDecorator(sqlMapSession.CreateCommand(statement.CommandType), request);
                    ApplyParameterMap(sqlMapSession, request.IDbCommand, request, statement, paramObject);
                    totalCount = GetCount(request, sqlMapSession, cmdCountSql);
                    request.IDbCommand.CommandText = request.PreparedStatement.PreparedSql;
                    AddCommandParameters(beginNo, endNo, request);
                    IList<T> result = RunQueryForList<T>(statement, request, sqlMapSession, paramObject, null, null);
                    return result;
                }
                finally
                {
                    if (flag)
                    {
                        sqlMapSession.CloseConnection();
                    }
                }
            }
        }

       园友们若想直接拿来使用,可以下载附件文件,在引用Ibatis.Net的dll同时,在工程里再增加SqlMapperExtension这个类文件,就可以方便调用了。此方法在Ibatis.Net1.62版本下,使用MSSQL,已经通过测试验证。OK,如果你不想分页功能,那么就还是使用下面的方式。  

             var listall = mapper.QueryForList<T>(statementName, paras);
    

      这样你只需要在sqlmapper的xml里写一个SQL语句,获取全部记录和获取分页记录(含有总条数)两件事就都可以搞定.

      觉得好的话,别忘了顶一下哦,呵呵.

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 02:29 , Processed in 0.074017 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表