oracle踩坑

  好久沒有寫博客了,就分享一些亂七八糟的東西吧!

1.oracle遞歸查詢

  大家應該使用有的時候會使用遞歸查詢數據庫菜單的吧,比如下面這樣的(偷的圖)( ̄▽ ̄)ノ

  這種一般是業務管理系統比較多,比如菜單樹,權限樹或者機構樹等等,從數據庫中查詢出的數據,然後使用java代碼構建成前端需要的樹的結構,然後返回給前端,ui組件渲染展示

  所以通常我們會有下面這種的表(oracle版本建表語句可以自己做修改),有着父節點和字節點的關係,就是id和parent_id

CREATE TABLE jrbac_menu (
id number(8) primary key not null , --主鍵id
real_name varchar(50) NULL,
parent_id varchar(50) NULL,   -- 父級菜單id
url_path varchar(500) NOT NULL,
icon varchar2(20) null,
torder varchar(50) NOT NULL
);

INSERT INTO jrbac_menu VALUES (1, 'Forms', null, 'forms.html', 'fa fa-edit', '0');
INSERT INTO jrbac_menu VALUES (2, 'UI Elements', null, 'Elements.html', 'fa fa-wrench', '1');
INSERT INTO jrbac_menu VALUES (3, 'Buttons', '2', 'buttons.html', 'Buttons', '0');
INSERT INTO jrbac_menu VALUES (4, 'Icons', '2', 'icons.html', 'Icons', '1');
INSERT INTO jrbac_menu VALUES (5, 'Multi-Level Dropdown', null, 'Dropdown.html', 'fa fa-sitemap', '2');
INSERT INTO jrbac_menu VALUES (6, 'Second Level Item', '5', 'second.html', 'Second', '0');
INSERT INTO jrbac_menu VALUES (7, 'Third Level', '5', 'Third.html', 'Third', '1');
INSERT INTO jrbac_menu VALUES (8, 'Third Level Item', '7', 'third.html', 'Third Level Item', '0');

 

  至於java代碼的話,會大概像下面這種寫法(比較懶,代碼是隨便找的),簡而言之就是:先找出所有的一級菜單,然後遍歷每個一級菜單,找到每一個一級菜單的二級菜單,再用遞歸的方式找到三級菜單,四級菜單.....

public void testQueryMenuList() {
    // 所有的菜單數據
    List<Menu> rootMenu = menuDao.queryMenuList(null);

    // 結果樹
    List<Menu> menuList = new ArrayList<Menu>();
    // 先找到所有的一級菜單
    for (int i = 0; i < rootMenu.size(); i++) {
        // 一級菜單沒有parentId
        if (StringUtils.isBlank(rootMenu.get(i).getParentId())) {
            menuList.add(rootMenu.get(i));
        }
    }
    // 爲一級菜單設置子菜單,getChild是遞歸調用的
    for (Menu menu : menuList) {
        menu.setChildMenus(getChild(menu.getId(), rootMenu));
    }
    Map<String,Object> jsonMap = new HashMap<>();
    jsonMap.put("menu", menuList);
    System.out.println(JSON.toJSONString(jsonMap));

}

/**
 * 遞歸查找子菜單
 * 
 * @param id
 *            當前菜單id
 * @param rootMenu
 *            要查找的列表
 * @return
 */
private List<Menu> getChild(String id, List<Menu> rootMenu) {
    // 子菜單
    List<Menu> childList = new ArrayList<>();
    for (Menu menu : rootMenu) {
        // 遍歷所有節點,將父菜單id與傳過來的id比較
        if (StringUtils.isNotBlank(menu.getParentId())) {
            if (menu.getParentId().equals(id)) {
                childList.add(menu);
            }
        }
    }
    // 把子菜單的子菜單再循環一遍
    for (Menu menu : childList) {// 沒有url子菜單還有子菜單
        if (StringUtils.isBlank(menu.getUrl())) {
            // 遞歸
            menu.setChildMenus(getChild(menu.getId(), rootMenu));
        }
    } // 遞歸退出條件
    if (childList.size() == 0) {
        return null;
    }
    return childList;
}

 

  我以前也是這樣的寫的,這種寫法就很煩,後來我就查了一下資料,可以直接使用sql遞歸查詢

  start with ... connect by prior 語法來實現遞歸查詢,使用了這種語法之後,一條sql就實現上面一堆代碼的功能了:

  例如表中原始數據:

  select * from jrbac_menu;

 

  我們想要查詢real_name爲'Multi-Level Dropdown' 的一級菜單下的所有子菜單,我們把這個一級菜單當作一個根節點

  從根節點向下遞歸查詢:select * from jrbac_menu start with real_name='Multi-Level Dropdown' connect by prior id =  parent_id;

 

  sql使用說明,假如下面的sql是查詢所有的子菜單節點,如果最後是parent_id=id,那麼就是查詢當前根節點的所有父級節點;

  所以我覺得使用start with connect ... by prior 語法必須的兩個條件:1.oracle數據庫   2.菜單有個公共的根節點,或者只是查詢其中其中一部分子樹節點;

 

2.orcale分頁查詢

  在mysql中我們可以使用limit關鍵字就很容易的實現了分頁,但是在oracle中,語法就比較長一點

  1.首先前端傳遞分頁參數,page和pageSize

  2.我們需要將他轉爲起始條數和終止條數:startSize=(page-1)*pageSize+1    endSize=page*pageSize

  3.設置到oracle的分頁語句中:

SELECT * FROM
(
  SELECT ROWNUM  rowno, t.* FROM emp t  WHERE hire_date BETWEEN TO_DATE ('20060501', 'yyyymmdd')
  AND ROWNUM <= #{endSize}
) table_alias
WHERE table_alias.rowno >= #{startSize};

  有興趣的可以自己開發一個基於mybatis+oracle的分頁插件:參考這裏 

  不過這裏是mysql的,可以將我上面寫第2點和第3點丟過去,稍微魔改一下就行了

  爲什麼需要自己開發一個分頁插件呢?不是有開源的pageHelper麼,哎,一言難盡,那種很老的項目的話我都不敢去引入第三方依賴,不要本來還能跑的,結果引入了第三方依賴出現奇怪的問題(╯—﹏—)╯(┷━━━┷

  還有就是搞不懂爲什麼有的人就能每次都習慣用這麼麻煩的分頁語句,我第一次看的時候都看的有點懵逼,還是在不影響現在的功能的前提下,自己動手豐衣足食吧

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章