1. 程式人生 > >MyBatis,MySql儲存過程分頁查詢

MyBatis,MySql儲存過程分頁查詢

前言

如果涉及到同一臺機器上不同庫不同表的關聯查詢,可以通過 資料庫名.表名 的形式來進行跨庫查詢,若不用外掛,這時可以通過儲存過程來完成查詢。

編寫儲存過程

以學生資訊查詢為例,例如有兩個庫。
學生庫student(學生資訊表 stu_info)

CREATE TABLE `stu_info` (
  `id` varchar(64) NOT NULL,
  `name` varchar(64) NOT NULL COMMENT '學生姓名',
  `teacher_id` varchar(64) DEFAULT NULL COMMENT '教師id',
  PRIMARY
KEY (`id`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

教師庫teacher(教師資訊表 teacher_info)


CREATE TABLE `teacher_info` (
  `id` varchar(64) NOT NULL,
  `name` varchar(64) NOT NULL COMMENT '教師姓名',
  PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

其中每個學生有一個指導老師,每個指導老師可以指導多個學生。
先要查詢出所有學生的名字及其指導教師。由於分頁引數是呼叫方傳入,因此分頁引數通過佔位符(?,?)來替代,並使用MySql Prepared SQL Statement[1]。最終儲存過程如下。

CREATE PROCEDURE test_proc_paging(
IN pageNum int,
IN pageSize int
)
BEGIN
    SET @pageSize = pageSize;
    SET @pageNum = pageNum;
    PREPARE s1 FROM "
    select s.name as stu,t.name as teacher from student.stu_info s left join teacher.teacher_info t on s.teacher_id = t.id
    limit ?,?"
    EXECUTE s1 USING @pageNum,@pageSize;
    DEALLOCATE PREPARE s1;
    SELECT FOUND_ROWS() as recordCounts;
END
  • PREPARE s1 … 定義prepared statement s1
  • EXECUTE s1 … 執行s1,並用引數替換佔位符
  • DEALLOCATE PREPARE s1… 釋放prepared statement
  • SELECT FOUND_ROWS() as recordCounts; 返回總記錄數

最終呼叫儲存過程會返回兩個結果,一個是分頁查詢的結果,一個是總的結果數。

MyBatis呼叫儲存過程

StuInfoDao定義為,其中StuInfoForm 包含了查詢引數,即兩個分頁引數。注意由於呼叫的儲存過程返回多個結果集,因此DAO中的查詢語句返回結果為List<Object>

public interface StuInfoDao {
    public List<Object> queryStuByProc(StuInfoForm form);
}

Mybatis mapper.xml 定義,由於返回結果包含兩個結果集,因此定義了兩個ResultMap,並在select查詢中指定了兩個ResultMap[2]。

  <resultMap type="java.lang.Integer" id="recordCounts">
    <result column="recordCounts" jdbcType="INTEGER" />
  </resultMap> 


  <resultMap id="dtoResultMap" type="com.fengdai.report.model.Certification">
    <result column="stu" jdbcType="VARCHAR" property="stu" />
    <result column="teacher" jdbcType="VARCHAR" property="teacher" />
  </resultMap>

  <select id="queryStuByProc" resultMap="dtoResultMap,recordCounts" statementType="CALLABLE" >
    {
        CALL  test_proc_paging(#{pageNum,jdbcType=INTEGER},
                                                  #{pageSize,jdbcType=INTEGER})
    }
  </select>

查詢與返回結果的處理

返回結果,那麼通過如下的程式碼獲取結果,及總記錄數,然後填入返回物件的成員中,最後返回給前端即可。

form.setPageNum((form.getPageNum()-1)*form.getPageSize());
List<Object> result = certificationDao.queryStuByProc(form);
// 結果
List<Object> result = list.get(0);
// 總記錄數
Integer size = ((ArrayList<Integer>)list.get(1)).get(1);

form中的pageNum定義了頁號,pageSize定義的單頁大小,因此在查詢前需要將pageNum,pageSize轉換為相應的分頁查詢引數。
例如 查第5頁,每頁10條,那麼sql中的limit偏移就是 limit (5-1)*10,10

參考