sdkman で Oracle JDK を管理する

たぶん需要ないと思うけど備忘録。sdkman で Oracle JDK を管理する。(開発用途)

2020/11 時点では sdkman で OpenJDK 8 はインストールできないっぽい。

$ sdk ls java
================================================================================
Available Java Versions
================================================================================
 Vendor        | Use | Version      | Dist    | Status     | Identifier
--------------------------------------------------------------------------------
 AdoptOpenJDK  |     | 15.0.1.j9    | adpt    |            | 15.0.1.j9-adpt      
               |     | 15.0.1.hs    | adpt    |            | 15.0.1.hs-adpt      
               |     | 14.0.2.j9    | adpt    |            | 14.0.2.j9-adpt      
               |     | 14.0.2.hs    | adpt    |            | 14.0.2.hs-adpt      
               |     | 13.0.2.j9    | adpt    |            | 13.0.2.j9-adpt      
               |     | 13.0.2.hs    | adpt    |            | 13.0.2.hs-adpt      
               |     | 12.0.2.j9    | adpt    |            | 12.0.2.j9-adpt      
               |     | 12.0.2.hs    | adpt    |            | 12.0.2.hs-adpt      
               |     | 11.0.9.j9    | adpt    |            | 11.0.9.j9-adpt      
               |     | 11.0.9.hs    | adpt    |            | 11.0.9.hs-adpt      
               |     | 8.0.272.j9   | adpt    |            | 8.0.272.j9-adpt     
               |     | 8.0.272.hs   | adpt    |            | 8.0.272.hs-adpt     
 Amazon        |     | 15.0.1       | amzn    |            | 15.0.1-amzn         
               |     | 11.0.9       | amzn    |            | 11.0.9-amzn         
               |     | 8.0.272      | amzn    |            | 8.0.272-amzn        
 Azul Zulu     |     | 15.0.1       | zulu    |            | 15.0.1-zulu         
               |     | 15.0.1.fx    | zulu    |            | 15.0.1.fx-zulu      
               |     | 14.0.2       | zulu    |            | 14.0.2-zulu         
               |     | 14.0.2.fx    | zulu    |            | 14.0.2.fx-zulu      
               |     | 13.0.5       | zulu    |            | 13.0.5-zulu         
               |     | 13.0.5.fx    | zulu    |            | 13.0.5.fx-zulu      
               |     | 12.0.2       | zulu    |            | 12.0.2-zulu         
               |     | 11.0.9       | zulu    |            | 11.0.9-zulu         
               |     | 11.0.9.fx    | zulu    |            | 11.0.9.fx-zulu      
               |     | 10.0.2       | zulu    |            | 10.0.2-zulu         
               |     | 9.0.7        | zulu    |            | 9.0.7-zulu          
               |     | 8.0.272      | zulu    |            | 8.0.272-zulu        
               |     | 8.0.272.fx   | zulu    |            | 8.0.272.fx-zulu     
               |     | 8.0.202      | zulu    |            | 8.0.202-zulu        
               |     | 7.0.282      | zulu    |            | 7.0.282-zulu        
               |     | 7.0.181      | zulu    |            | 7.0.181-zulu        
 BellSoft      |     | 15.0.1.fx    | librca  |            | 15.0.1.fx-librca    
               |     | 15.0.1       | librca  |            | 15.0.1-librca       
               |     | 14.0.2.fx    | librca  |            | 14.0.2.fx-librca    
               |     | 14.0.2       | librca  |            | 14.0.2-librca       
               |     | 13.0.2.fx    | librca  |            | 13.0.2.fx-librca    
               |     | 13.0.2       | librca  |            | 13.0.2-librca       
               |     | 12.0.2       | librca  |            | 12.0.2-librca       
               |     | 11.0.9.fx    | librca  |            | 11.0.9.fx-librca    
               |     | 11.0.9       | librca  |            | 11.0.9-librca       
               |     | 8.0.272.fx   | librca  |            | 8.0.272.fx-librca   
               |     | 8.0.272      | librca  |            | 8.0.272-librca      
               |     | 8.0.265.fx   | librca  |            | 8.0.265.fx-librca   
 GraalVM       |     | 20.2.0.r11   | grl     |            | 20.2.0.r11-grl      
               |     | 20.2.0.r8    | grl     |            | 20.2.0.r8-grl       
               |     | 20.1.0.r11   | grl     |            | 20.1.0.r11-grl      
               |     | 20.1.0.r8    | grl     |            | 20.1.0.r8-grl       
               |     | 20.0.0.r11   | grl     |            | 20.0.0.r11-grl      
               |     | 20.0.0.r8    | grl     |            | 20.0.0.r8-grl       
               |     | 19.3.1.r11   | grl     |            | 19.3.1.r11-grl      
               |     | 19.3.1.r8    | grl     |            | 19.3.1.r8-grl       
 Java.net      |     | 16.ea.22     | open    |            | 16.ea.22-open       
               |     | 16.ea.6.lm   | open    |            | 16.ea.6.lm-open     
               |     | 16.ea.2.pma  | open    |            | 16.ea.2.pma-open    
               |     | 15.0.1       | open    | installed  | 15.0.1-open         
               |     | 14.0.2       | open    |            | 14.0.2-open         
               |     | 13.0.2       | open    |            | 13.0.2-open         
               |     | 12.0.2       | open    |            | 12.0.2-open         
               | >>> | 11.0.2       | open    | installed  | 11.0.2-open         
               |     | 10.0.2       | open    |            | 10.0.2-open         
               |     | 9.0.4        | open    |            | 9.0.4-open          
 SAP           |     | 15.0.1       | sapmchn |            | 15.0.1-sapmchn      
               |     | 14.0.2       | sapmchn |            | 14.0.2-sapmchn      
               |     | 13.0.2       | sapmchn |            | 13.0.2-sapmchn      
               |     | 12.0.2       | sapmchn |            | 12.0.2-sapmchn      
               |     | 11.0.9       | sapmchn |            | 11.0.9-sapmchn      
================================================================================

代わりに Oracle JDK 8 をインストールして、sdkman の管理下に dmg でインストールしたディレクトリへのシンボリックリンクを張る。この名前が sdkman の Identifier になる。

$ cd /Users/<USER>/.sdkman/candidates/java
$ ln -s /Library/Java/JavaVirtualMachines/jdk1.8.0_271.jdk/Contents/Home 8u271-oracle

バージョンを切り替える。

$ sdk use java 8u271-oracle
Using java version 8u271-oracle in this shell.

$ java -version
java version "1.8.0_271"
Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)

取り急ぎ、Vendor が Unclassified になってたり Dist が none になってるけど気にしない。

$ sdk ls java
================================================================================
Available Java Versions
================================================================================
 Vendor        | Use | Version      | Dist    | Status     | Identifier
--------------------------------------------------------------------------------
 AdoptOpenJDK  |     | 15.0.1.j9    | adpt    |            | 15.0.1.j9-adpt      
               |     | 15.0.1.hs    | adpt    |            | 15.0.1.hs-adpt      
               |     | 14.0.2.j9    | adpt    |            | 14.0.2.j9-adpt      
               |     | 14.0.2.hs    | adpt    |            | 14.0.2.hs-adpt      
               |     | 13.0.2.j9    | adpt    |            | 13.0.2.j9-adpt      
               |     | 13.0.2.hs    | adpt    |            | 13.0.2.hs-adpt      
               |     | 12.0.2.j9    | adpt    |            | 12.0.2.j9-adpt      
               |     | 12.0.2.hs    | adpt    |            | 12.0.2.hs-adpt      
               |     | 11.0.9.j9    | adpt    |            | 11.0.9.j9-adpt      
               |     | 11.0.9.hs    | adpt    |            | 11.0.9.hs-adpt      
               |     | 8.0.272.j9   | adpt    |            | 8.0.272.j9-adpt     
               |     | 8.0.272.hs   | adpt    |            | 8.0.272.hs-adpt     
 Amazon        |     | 15.0.1       | amzn    |            | 15.0.1-amzn         
               |     | 11.0.9       | amzn    |            | 11.0.9-amzn         
               |     | 8.0.272      | amzn    |            | 8.0.272-amzn        
 Azul Zulu     |     | 15.0.1       | zulu    |            | 15.0.1-zulu         
               |     | 15.0.1.fx    | zulu    |            | 15.0.1.fx-zulu      
               |     | 14.0.2       | zulu    |            | 14.0.2-zulu         
               |     | 14.0.2.fx    | zulu    |            | 14.0.2.fx-zulu      
               |     | 13.0.5       | zulu    |            | 13.0.5-zulu         
               |     | 13.0.5.fx    | zulu    |            | 13.0.5.fx-zulu      
               |     | 12.0.2       | zulu    |            | 12.0.2-zulu         
               |     | 11.0.9       | zulu    |            | 11.0.9-zulu         
               |     | 11.0.9.fx    | zulu    |            | 11.0.9.fx-zulu      
               |     | 10.0.2       | zulu    |            | 10.0.2-zulu         
               |     | 9.0.7        | zulu    |            | 9.0.7-zulu          
               |     | 8.0.272      | zulu    |            | 8.0.272-zulu        
               |     | 8.0.272.fx   | zulu    |            | 8.0.272.fx-zulu     
               |     | 8.0.202      | zulu    |            | 8.0.202-zulu        
               |     | 7.0.282      | zulu    |            | 7.0.282-zulu        
               |     | 7.0.181      | zulu    |            | 7.0.181-zulu        
 BellSoft      |     | 15.0.1.fx    | librca  |            | 15.0.1.fx-librca    
               |     | 15.0.1       | librca  |            | 15.0.1-librca       
               |     | 14.0.2.fx    | librca  |            | 14.0.2.fx-librca    
               |     | 14.0.2       | librca  |            | 14.0.2-librca       
               |     | 13.0.2.fx    | librca  |            | 13.0.2.fx-librca    
               |     | 13.0.2       | librca  |            | 13.0.2-librca       
               |     | 12.0.2       | librca  |            | 12.0.2-librca       
               |     | 11.0.9.fx    | librca  |            | 11.0.9.fx-librca    
               |     | 11.0.9       | librca  |            | 11.0.9-librca       
               |     | 8.0.272.fx   | librca  |            | 8.0.272.fx-librca   
               |     | 8.0.272      | librca  |            | 8.0.272-librca      
               |     | 8.0.265.fx   | librca  |            | 8.0.265.fx-librca   
 GraalVM       |     | 20.2.0.r11   | grl     |            | 20.2.0.r11-grl      
               |     | 20.2.0.r8    | grl     |            | 20.2.0.r8-grl       
               |     | 20.1.0.r11   | grl     |            | 20.1.0.r11-grl      
               |     | 20.1.0.r8    | grl     |            | 20.1.0.r8-grl       
               |     | 20.0.0.r11   | grl     |            | 20.0.0.r11-grl      
               |     | 20.0.0.r8    | grl     |            | 20.0.0.r8-grl       
               |     | 19.3.1.r11   | grl     |            | 19.3.1.r11-grl      
               |     | 19.3.1.r8    | grl     |            | 19.3.1.r8-grl       
 Java.net      |     | 16.ea.22     | open    |            | 16.ea.22-open       
               |     | 16.ea.6.lm   | open    |            | 16.ea.6.lm-open     
               |     | 16.ea.2.pma  | open    |            | 16.ea.2.pma-open    
               |     | 15.0.1       | open    | installed  | 15.0.1-open         
               |     | 14.0.2       | open    |            | 14.0.2-open         
               |     | 13.0.2       | open    |            | 13.0.2-open         
               |     | 12.0.2       | open    |            | 12.0.2-open         
               |     | 11.0.2       | open    | installed  | 11.0.2-open         
               |     | 10.0.2       | open    |            | 10.0.2-open         
               |     | 9.0.4        | open    |            | 9.0.4-open          
 SAP           |     | 15.0.1       | sapmchn |            | 15.0.1-sapmchn      
               |     | 14.0.2       | sapmchn |            | 14.0.2-sapmchn      
               |     | 13.0.2       | sapmchn |            | 13.0.2-sapmchn      
               |     | 12.0.2       | sapmchn |            | 12.0.2-sapmchn      
               |     | 11.0.9       | sapmchn |            | 11.0.9-sapmchn      
 Unclassified  | >>> | 8u271        | none    | local only | 8u271-oracle        
================================================================================

現場からは以上です。

Docker道場オンライン #1 に行ってきた #dockerdojo

Docker道場オンライン #1 に参加しました。今回はオンライン開催。簡単に所感をまとめます。

dockerdojo.connpass.com

所感

Docker は、社内でちょっとした開発ツールを試すときに触ってみた程度です。きちんと基本から理解しておきたいところ。今回は Docker のコンセプトや基本的な概念の話でした。特にイメージレイヤの話は参考になりました。

Play with Docker は初めて知りました。便利そう。Docker Desktop でプロキシに悩まされたあの頃はなんだったのか...。

第2回があったら参加したいなー。

YouTube はこちら。

youtu.be

以下、メモから抜粋。

www.slideshare.net

  • 仮想サーバーをコンテナで代替するものではない
  • Build, Share (Ship), Run
  • Play with Docker
  • Linux のコンテナ技術を簡単にアプリを移動したり共有したりしたい ⇒ Docker
  • すべての依存関係をパッケージ化してコンテナ化して動かす
  • 一般的なプロセス実行
    • OS がユーザー空間にプロセスを起動する
  • コンテナでは特別な状態でプロセスを起動する
  • cgroup でリソースを制限する
    • CPU, メモリ, I/O, ...
  • Docker エンジン (dockerd デーモン)
    • Docker クライアントのコマンドを受け付ける
    • Docker イメージを使ってコンテナのプロセスを起動する
  • Docker イメージ
  • イメージレイヤ☆
    • ファイルシステム/アプリケーションとメタ情報が含まれる
      • 設定ファイル, コマンド, プログラム, ...
    • 親子関係を持つ
    • 親子関係のイメージレイヤをまとめてタグを付けられる
    • 他のイメージレイヤと共有できる (GitHub の fork みたいなもの)
  • イメージレイヤは削除できない
    • 部分的に差し替える場合は派生イメージとして別に作られる
  • ベースイメージ = OSレイヤ?
  • Dockerfile
    • Docker イメージを作成するための設計図
    • FROM, ADD, ENTRYPOINT, CMD, ...
    • Docker は docker commit でイメージレイヤ群を自動構築する
  • カーネルに依存するプログラムでは Docker は向かない
  • Docker コンテナ
    • イメージレイヤは読み込み専用
    • コンテナ実行時に読み書き可能なイメージレイヤを追加する☆
    • Copy on Write
  • docker inspect
    • Docker コンテナの情報を表示する
  • docker history
    • イメージレイヤの情報を表示する?
  • Docker Compose
    • 複数のコンテナをまとめて管理する
    • コンテナ, ネットワーク, ボリューム, ...
  • Docker ボリューム
    • 永続領域の管理
    • ホスト上の領域を参照可
  • ドキュメント

Records の Compact Constructors の中ではフィールドを初期化する処理は書けない

Java の Records に Compact Constructors と呼ばれる機能があります。

record Foo(int x) {
    Foo {
        x = 100;
    }
}

Compact Constructors の中ではフィールドを初期化する処理は書けません。コンパイルエラーになります。

record Foo(int x) {
    Foo {
        this.x = 100; // エラー: final変数xに値を代入することはできません
    }
}

ふつうのコンストラクタの場合は問題なし。

record Foo(int x) {
    Foo(int x) {
        this.x = 100; // OK
    }
}

なんであえてコンパイルエラーになるようにしたんだろうか...?

そのあたりの理由というか経緯は見つけられませんでしたが、とりあえず最初の Compact Constructors 版を javap してみました。

> java --version
openjdk 15 2020-09-15
OpenJDK Runtime Environment (build 15+36-1562)
OpenJDK 64-Bit Server VM (build 15+36-1562, mixed mode, sharing)

> javac --enable-preview --release 15 Foo.java

> javap -c Foo.class
Compiled from "Foo.java"
final class Foo extends java.lang.Record {
  Foo(int);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Record."<init>":()V
       4: bipush        100
       6: istore_1
       7: aload_0
       8: iload_1
       9: putfield      #7                  // Field x:I
      12: return

  public final java.lang.String toString();
    Code:
       0: aload_0
       1: invokedynamic #13,  0             // InvokeDynamic #0:toString:(LFoo;)Ljava/lang/String;
       6: areturn

  public final int hashCode();
    Code:
       0: aload_0
       1: invokedynamic #17,  0             // InvokeDynamic #0:hashCode:(LFoo;)I
       6: ireturn

  public final boolean equals(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokedynamic #21,  0             // InvokeDynamic #0:equals:(LFoo;Ljava/lang/Object;)Z
       7: ireturn

  public int x();
    Code:
       0: aload_0
       1: getfield      #7                  // Field x:I
       4: ireturn
}

どうやらコンストラクタのローカル変数に代入して、そのあとにインスタンスフィールドを初期化してるっぽいです。おそらく、Compact Constructors に書いた処理はインスタンスフィールドの初期化の前に差し込まれるのではないかと思います。(想像で書いてるので正確ではないと思います)

最初の Compact Constructors 版の record は次のようなクラスになっていると思われます。

class Foo extends Record {
    private final int x;
    public Foo(int x) {
        x = 100;
        this.x = x;
    }
    // ... (略)
}

ちなみにふつうのコンストラクタ版を javap するとこういう感じ。

> javap -c Foo.class
Compiled from "Foo.java"
final class Foo extends java.lang.Record {
  Foo(int);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Record."<init>":()V
       4: aload_0
       5: bipush        100
       7: putfield      #7                  // Field x:I
      10: return

  ... ()

参考

追記

ここにいろいろ書いてありました。(原文)

blogs.oracle.com

コンパクト・コンストラクタを宣言する目的は、カノニカル・コンストラクタの本体で必要となる、検証や正規化のみを行うコードを提供することにあります。その他の初期化コードはコンパイラが提供します。

あと、このあたりにもいろいろ書いてあるっぽい。ちゃんと読んでないですが...。

8.10.4 Record Constructor Declarations - Records - Oracle Help Center

JJUGナイトセミナー「Java 15 リリース記念イベント」に行ってきた #jjug

JJUGナイトセミナー「Java 15 リリース記念イベント」に参加しました。今回はオンライン開催。簡単に所感をまとめます。

jjug.doorkeeper.jp

所感

チャットにも書かれてましたが、リリースサイクルが変わってから少しずつ機能が追加されていくのでキャッチアップしやすくていいですね。

Sealed Classes の最終目標は「使えるパターンマッチング」とのことで、機能をうまく分割して導入しているようです。なるほど。将来、どういう機能を実現したいのかを意識しておくのは大事かも。

あと、Biased Locking とか Hidden Classes は初めて聞きました。Hidden Classes は新しい機能なのでちょっと調べてみるか。

YouTube はこちら。

youtu.be

以下、メモから抜粋。

Welcome, Java 15!

  • Azul では 13/15 が MTS
  • Java 15 の JEP は 14個
  • Nashorn ⇒ GraalJS への移行を推奨
  • Biased Locking
    • デフォルト無効化
    • デフォルトのロック実装
    • アトミックな CAS 命令が高コストではなくなった
  • Hidden Classes
  • UDP socket API を Fiber 対応
  • ZGC
  • Text Blocks
  • Shenandoah
  • (Preview) Pattern Matching for instanceof
    • 型テストパターン (type-test pattern)
    • 型が一致するときは変数にバインドされる
  • (Preview) Records
    • フィールドの名前がそのまま getter になる (フィールド変数の命名に注意)
    • immutable
    • インタフェース実装可
    • extends 不可
    • フィールドは final (リフレクション利用不可)
  • (Preview) Sealed Classes
    • 実装/継承先を同一コンパイル単位内のクラスのみに制限する?
    • パターンマッチングと組み合わせて使う
    • sealed で宣言
    • permits で拡張を許可するサブクラスを列挙する
    • 拡張許可されたサブクラスの制約☆
  • Foreign-Memory Access API
    • よくわからず...
  • Parallel/G1 GC
    • -XX:MaxRAM=16g のみ, ヒープサイズ指定なしの場合?
    • Parallel GCスループット重視
    • G1 はスループット&レイテンシ重視
    • Java 15 ではヒープのリージョンサイズ指定を変更

Recordsを中心にした新機能の紹介と今後の展望

  • Records (2nd Preview)
  • 名前付きタプル
  • record はキーワードではない
    • 型には使えないけど変数名には使える
  • Record の要素はコンポーネントと呼ぶ
  • 中括弧は省略不可
  • Canonical Constructor
  • Compact Constructor
  • コンパクトコンストラク
    • コンストラクタのパラメータは省略可
    • フィールドは初期化してはいけない
  • Pattern Matching for instanceof (2nd Preview)
    • Kotlin のスマートキャストみたいな機能
  • Sealed Classes (Preview)
  • 継承できるクラスを限定する
  • 現状では使い道なし?
    • 後発の機能と組み合わせて使う?
    • Pattern Matching for switch とか
  • sealed, final, non-sealed
    • non-sealed を付けるとそれ以下の階層は継承可
  • Sealed Classes の今後の計画☆
  • Pattern Matching for switch
    • Sealed Classes と組み合わせると default なしで書けるようになる
  • Deconstruction
    • パターンマッチングで構造を分解する
    • Optional をパターンマッチングしたい☆
    • Optional を interface にする必要がある
      • ※リフレクションで非互換性が出る
    • Some, None が Optional を実装する
      • Sealed Classes がないため final class になっている
  • 最終目標は使えるパターンマッチング☆

Vue.js でウィジェットっぽいもの (TypeScript) (仮)

以前、Vue.js の学習を兼ねてウィジェットっぽいものを作りました。

Vue.js でウィジェットっぽいものを作ってみる (仮) - kntmr-blog

Vue.js でウィジェットっぽいもの (仮) その2 - kntmr-blog

続編として今回はこれを TypeScript に移植しました。とは言ってもそんなに大したことはやってなくて TypeScript のお作法的にもかなり怪しいと思います...。

github.com


以下、備忘録。

前回は学習を兼ねてたので Vuex とか Vue Router を使ってましたが、今回はもっとシンプルに。あと、Vue.js はとりあえず 2.x 系にしています。後々、3.x に移行したい。

> vue create vue-widget-sample-ts

Vue CLI v4.5.6
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS
? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

axios だけインストール。

> yarn add axios

vue.config.js

Configuration Reference - Vue CLI

Webpack の設定などはここに書く。

コンポーネント

基本的に Vue.js + JS 版を Vue.extend でラップしてるだけであまり変わってないです。

これからやりたいこと

もう少し TypeScript や Vue 3.x の学習を兼ねるようなサンプルにしたい。

Engineers in VOYAGE #voyagebook

先月、Engineers in VOYAGE を読みました。VOYAGE GROUP のエンジニアのインタビューをまとめた本です。

Engineers in VOYAGE ― 事業をエンジニアリングする技術者たちwww.lambdanote.com

内容が生々しいという噂が気になって読んでみました。確かに生々しかったです。

大小さまざまな問題があって、個人としてチームとして組織としてそれらにどう向き合うか、ビジネスやプロダクトの方向性をどうするのか、いろいろな迷いや葛藤の中で日々戦っているエンジニアの話です。

なんだか読んでて勇気が出ました。みんなすごい頑張ってるんだなぁって。

「はじめに」に書いてある通り、読むひとがそれぞれの立場で共感できる本です。どこかに刺さるキーワードや一文があると思います。個人的には5章の旧システムの話があるあるでグッと来ました。その他、興味深った一文を抜粋します。

  • 同じ目的を共有するチーム間で「依頼」が発生するのは本意ではない
  • 最初はよかれと思って導入したものがアンチパターンになる
  • 重要なのは切り戻しできるかどうか
  • 葬りで問題の分母を減らす
  • 「事業葬り」「機能葬り」「コード葬り」
  • 部屋のドアノブを回すと風呂の底が抜ける
  • データベース設計の意図を辿れるようにする
  • 実装から距離をとってテストを書くことで独立性を保つ
  • 自分たちの予測モデルの存在が将来の予測を陳腐化させる

閉包テーブル (Closure Table)

閉包テーブル (Closure Table) は RDB で階層構造を表現する際に使われるデータモデルです。数年前にとある案件で使ったのですが、内容を忘れかけてるので復習します。備忘録。

閉包テーブルでは直接の親子関係だけでなく、階層全体の関係を持つ。閉包テーブルを利用すると階層構造をシンプルに表現できる。特にクエリがシンプルになるのが利点。ただし、階層全体の関係を持つため、階層が深くなるほどデータサイズは大きくなる。

ルートアクセス

ルート直下 (最上位階層) のフォルダを取得する場合、祖先フォルダIDにルートのIDを指定して、深さ 1 で検索する。ルートは特別な扱いになるため、IDには何かしらの固定値を用いる。

SELECT * FROM FolderPath as fp
JOIN Folder as f ON fp.祖先フォルダID = f.id
WHERE fp.祖先フォルダID = {ルート} AND fp.深さ = 1

サブフォルダアクセス

ルートアクセスと同様。祖先フォルダIDにカレントのフォルダIDを指定して、深さ 1 で検索する。

-- フォルダAを基点にする場合
SELECT * FROM FolderPath as fp
JOIN Folder as f ON fp.祖先フォルダID = f.id
WHERE fp.祖先フォルダID = {フォルダA} AND fp.深さ = 1

パンくずリスト

カレントフォルダまでのパス。子孫フォルダIDにカレントのフォルダIDを指定して検索する。深さを降順で並べ替えるとパンくずリストになる。

-- フォルダCを基点にする場合
SELECT f.* FROM FolderPath as fp
JOIN Folder as f ON fp.祖先フォルダID = f.id
WHERE fp.子孫フォルダID = {フォルダC}
ORDER BY fp.深さ DESC

フォルダ削除

閉包テーブルでは階層全体の関係を持つ。フォルダ削除では、子孫フォルダIDに対象のフォルダIDを持つすべての階層データを削除する。

-- フォルダDを削除する場合
DELETE FROM FolderPath as fp
WHERE fp.子孫フォルダID = {フォルダD}

フォルダ追加

閉包テーブルでは階層全体の関係を持つ。フォルダ追加では、子孫フォルダIDに対象のフォルダIDを持つすべての階層データを作成する。対象のフォルダ自身を深さ 0 として、親フォルダのパンくずリストでルートまで辿りながら深さを +1 する。以下はフォルダE配下にフォルダXを追加する場合。