【问题标题】:how can i implement a pagination in spring jdbcTemplate我如何在spring jdbcTemplate中实现分页
【发布时间】:2017-02-04 18:03:11
【问题描述】:

这是我的以下 dao 实现

@Override
    public List<UserAddress> getAddresses(int pageid,int total) {

        String sql = "select * FROM user_addresses order by id desc limit "+(pageid-1)+","+total;
        List<UserAddress> userAddresses  = jdbcTemplate.query(sql, new RowMapper<UserAddress>() {
            @Override
            public UserSessionLog mapRow(ResultSet rs, int rowNum) throws SQLException {
                UserAddress userAdd = new UserAddress();
                userAdd.setId(rs.getInt("id"));
                userAdd.setId(rs.getString("city"));
                return userSession;
            }
        });
        return userAddresses;
    }

在上面的dao实现中,我列出了所有的用户地址,试图用limit列出

@RequestMapping("/userAddresses/{pageid}")
       public ModelAndView userAddresses(@PathVariable int pageid) {
        int total=5;  
        if(pageid==1){}  
        else{  
            pageid=(pageid-1)*total+1;  
        }  
         List<UserAddress> listAddresses = userAddressFacade.getAddresses(pageid,total);
         return new ModelAndView("userAddresses", "listAddresses", listAddresses);
    }

这是我的观点,

<table class="table table-condensed">
        <thead>
            <tr>
                <th>Address1</th>
                <th>City</th>
            </tr>
        </thead>
        <tbody>
            <c:if test="${not empty addresses}">
                <c:forEach var="address" items="${addresses}">
                    <tr>
                        <td>${address.address1}</td>
                        <td>${address.city}</td>
                    </tr>
                </c:forEach>
            </c:if>
        </tbody>
    </table>

     <br/>  
   <a href="/pro/userAddress/1">1</a>   
   <a href="/pro/userAddress/2">2</a>   
   <a href="/pro/userAddress/3">3</a>  

我已经硬编码了分页部分,有没有人知道如何进行分页。我是 java jdbcTemplate 的新手,

【问题讨论】:

    标签: java spring pagination jdbctemplate


    【解决方案1】:

    只要您的数据库支持 LIMITOFFSET,就可以做到这一点。

    给出了一个例子here。关键代码如下(可以忽略fluent builder子句):

    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageImpl;
    import org.springframework.data.domain.Pageable;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public class DemoRepository {
        private JdbcTemplate jdbcTemplate;
    
        @Autowired
        public DemoRepository(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
    
        public List<Demo> findDemo() {
            String querySql = "SELECT name, action, operator, operated_at " +
                    "FROM auditing " +
                    "WHERE module = ?";
            return jdbcTemplate.query(querySql, new Object[]{Module.ADMIN_OPERATOR.getModule()}, (rs, rowNum) ->
                    Demo.builder()
                            .rowNum(rowNum)
                            .operatedAt(rs.getTimestamp("operated_at").toLocalDateTime())
                            .operator(rs.getString("operator"))
                            .action(rs.getString("action"))
                            .name(rs.getString("name"))
                            .build()
            );
        }
    
        public Page<Demo> findDemoByPage(Pageable pageable) {
            String rowCountSql = "SELECT count(1) AS row_count " +
                    "FROM auditing " +
                    "WHERE module = ? ";
            int total =
                    jdbcTemplate.queryForObject(
                            rowCountSql,
                            new Object[]{Module.ADMIN_OPERATOR.getModule()}, (rs, rowNum) -> rs.getInt(1)
                    );
    
            String querySql = "SELECT name, action, operator, operated_at " +
                    "FROM auditing " +
                    "WHERE module = ? " +
                    "LIMIT " + pageable.getPageSize() + " " +
                    "OFFSET " + pageable.getOffset();
            List<Demo> demos = jdbcTemplate.query(
                    querySql,
                    new Object[]{Module.ADMIN_OPERATOR.getModule()}, (rs, rowNum) -> Demo.builder()
                            .rowNum(rowNum)
                            .operatedAt(rs.getTimestamp("operated_at").toLocalDateTime())
                            .operator(rs.getString("operator"))
                            .action(rs.getString("action"))
                            .name(rs.getString("name"))
                            .build()
            );
    
            return new PageImpl<>(demos, pageable, total);
        }
    }
    

    【讨论】:

    • Gist 中非常有用的解释。
    • 不是我的要点,我只是发布了链接。很高兴它有帮助。
    • 我很好奇,如果有人在 findDemoByPage 方法内的这两个查询之间进行干预并在 auditing 表中删除或添加一些行会发生什么。如果有这种可能性,我们不应该在具有 SERIALIZABLE 隔离级别的事务中扭曲findDemoByPage 方法以避免幻读吗?
    • 一如既往,这取决于您的用例,但这肯定会奏效。
    【解决方案2】:

    我同意 @Erica Kane 使用 LIMIT 和 OFFSET。

    但是,如果数据库不支持 LIMIT 和 OFFSET,那么您可以使用 ROW_NUMBER()

    例如 -
    SELECT * FROM ( SELECT ROW_NUMBER() OVER(ORDER BY id) as RRN FROM user_addresses as T1 ) WHERE RRN between :start and :end; :start 和 :end 你可以给出你想获取结果的任何数字。 1到100等
    如果总行数小于结束数,那么它将简单地返回存在的任何行。

    我找到了一些关于 ROW_NUMBER() 的最佳链接,并提供了很好的解释-

    https://blog.sqlauthority.com/2011/08/12/sql-server-tips-from-the-sql-joes-2-pros-development-series-ranking-functions-rank-dense_rank-and-row_number-day-12-of-35/

    https://blog.sqlauthority.com/2007/10/09/sql-server-2005-sample-example-of-ranking-functions-row_number-rank-dense_rank-ntile/

    https://blog.sqlauthority.com/2008/03/12/sql-server-2005-find-nth-highest-record-from-database-table-using-ranking-function-row_number/

    https://blog.sqlauthority.com/2015/09/03/sql-server-whats-the-difference-between-row_number-rank-and-dense_rank-notes-from-the-field-096/

    【讨论】:

      【解决方案3】:

      我在搜索其他内容时遇到了这个问题,并注意到这个问题没有得到回答,所以想发布我的 2cents。 您可以创建一个包含 Pagination 对象和 pageId 的包装器(请求)对象。

      请求

      • 分页分页
      • int pageId(任何业务相关数据/SQL参数)
      • 任何域对象

      分页

      • int start(用于在 SQL 中设置 OFFSET 属性)
      • int size(用于在 SQL 中设置 FETCH NEXT 属性)

      【讨论】:

        【解决方案4】:

        您不必为分页创建自己的实现逻辑。使用 Spring 的PagedListHolder,它适合和可配置的分页目的。

        在这里您可以看到一个示例实现:Spring Pagination Example

        【讨论】:

        • 您的建议有一个小问题。问题是如何实现数据库查询的分页,这意味着我们想要避免的是必须通过网络从数据库中检索大量数据并将它们存储在内存中,而我们只能使用其中的一小部分。但是,您的方法是在内存中对集合进行分页,更具体地说是列表。但这个想法恰恰是不必创建这些列表。因此,除非我在这里遗漏了什么,否则这个解决方案的提议恐怕是矛盾的。
        • 最初的问题是关于“分页”,为此目的是为 PagedListHolder 设计的,不是吗?
        • 在某种程度上,是的。但问题不仅仅与此有关,不是吗?它说使用 JDBCTemplate 进行分页,这暗示这是数据库查询的分页。如果您的 JDBCTemplate 发出一个带 5000 条记录的查询,那么在数据库级别进行分页比通过网络带 5000 条记录更有效,将它们存储在内存中以仅使用 PageListHolder 返回前 100 条记录,然后重复所有操作当用户请求第二页时,你不觉得吗?更不用说如果我们这样做会浪费大量的资源。
        • 我想我们已经进行了不必要的讨论,但为了澄清,您可以看到原始问题中有数据库查询,您可以看到 OP 正在尝试在数据库级别限制分页我们得到select * FROM user_addresses order by id desc limit "+(pageid-1)+"的结果。 OP 的问题正是关于我们如何使用 JDBCTemplate 正确地做到这一点。因此,无论我们给出什么答案,我们都不能简单地忽视这一点。
        • @user1315357,正如 Edwin 建议的那样,我正在寻找分页的想法,这给了我有限的记录。
        猜你喜欢
        • 2015-12-02
        • 2011-01-15
        • 2014-08-10
        • 1970-01-01
        • 1970-01-01
        • 2013-08-31
        • 1970-01-01
        • 2023-03-19
        • 2011-02-25
        相关资源
        最近更新 更多