dbflute / dbflute-core

DBFlute core libraries for Java8
http://dbflute.seasar.org/
23 stars 18 forks source link

DBFlute Engine: PostgreSQL, improve serial sequence schema prefix #163

Closed jflute closed 4 months ago

jflute commented 1 year ago

from DBFlute Slack: https://dbflute.slack.com/archives/CAPH91CH2/p1667284569063309

DBFlute 1.2.6 + PostgreSQL 10.19 + Java 17 + Spring Boot 2.7.4 で開発しております。
一つのDatabase内に複数のスキーマを作成しています。
# 以下の様な感じ
     dba
        +-- schema1
        |   +-- table11
        +-- schema2
            +-- table21
一つのスキーマには一つのDBFluteクライアントを作成しています。
# 一つのスキーマをライブラリとして利用したいので、追加スキーマという選択肢はなし
この際 littleAdjustmentMap.dfprop の isAvailableAddingSchemaToTableSqlName を true に設定することで、
共通の dataSource にて select は問題無く実行出来ています。
select dfloc.id from schema1.table11 dfloc where dfloc.....
で、問題なんですが、レコード追加時、idの値生成で
select nextval ('table11_id_seq')
とスキーマ装飾なしで実行されてしまい、does not exist と怒られてしまいます。
正しくスキーマを装飾して、
select nextval ('schema1.table11_id_seq')
と実行するにはどの様に設定すれば良いでしょうか?
とりあえず、sequenceMap.dfprop に一つ一つ書いていますが、
あんまりスマートじゃないので...
# 一つのスキーマ毎に専用のデータソースを用意すればこの様な問題は発生しませんが、
# スキーマ間を跨がるトランザクションが面倒なのと、
# スキーマ毎にコネクションが発生するのでちょっと勿体ない。

...

一つのスキーマには一つのDBFluteクライアントを作成しています。
# 一つのスキーマをライブラリとして利用したいので、追加スキーマという選択肢はなし
追加スキーマ使わない話の方ですが…
共通の dataSource にて
そうか、なるほど。1スキーマ1DBFluteクライアントで、でもコネクションは同じものを使ってるってことですね。
ちょっとあまりイメージがなかったので、ごめんなさい、ちょと勘違いしました。
…
自動生成単位をスキーマごとに分離したい
(プロジェクトをスキーマごとに分けて別ライブラリにしたい)
 ↓
追加スキーマは使わない。
…
でも同じデータソースを使ってアクセスしたい。トランザクションとかはまとめて扱いたいし、コネクションプールは一つで十分。
 ↓
少なくとも片方のDBFluteクライアントでは、スキーマ名をちゃんと付与してあげないとSQLが発行できない。
(両方ともpublicスキーマじゃなく独自スキーマであれば、両方ともスキーマ名を付与しないといけない)
 ↓
シーケンス名にスキーマ名が付与されないぞぅ問題発生
…
こういうことですね?

でも確かに、DB変更のライフサイクルとか考えると、自動生成単位は分けたい、ってのは十分ありそうですね。
追加スキーマはわりと固定的な隣のDB(旧システムのDBとか)を想定した感じで作られたものなので、両方とも能動的なDBならちょっと一つに入れ込んで管理するのは向かなさそうですね。
でもって、コネクションは同じにしたいってのも確かなって感じなので、DBFluteとしてもちゃんと対応できないと良くないですね。
(今までそういうExampleなかったので、作ったほうが良いかも…)

(一方で、ひとまずserial型のSequenceを前提に調査…実況中継)

serial型のSequence名は、デフォルト制約から抜き出した名前をそのまま使っちゃってるから、AdditionalSchemaかisAvalableかどちらにせうよ、スキーマ名の修飾はされずにselect文になってしまいそうだな。。。これは問題。
少なくともserialの方は開発者が何も手を出せずに名前が決まってしまうので、ちゃんと追従しないといけなさそう。

(実況中継というか独り言)
あれ…でもPostgreSQLのテストプロジェクトだとserialのSequence名にスキーマ名が付与されてるな…
DBFlute Engineが接続してるコネクションの対象スキーマによって挙動が変わるかも???
テストプロジェクトは追加スキーマなので、コネクションの対象スキーマがpublicのとき、隣のスキーマのメタデータには自然とスキーマが付与されるのかも。
takeさんの構成の場合は、たぶんdatabaseInfoMapの対象スキーマは、そのままそのスキーマを指定されてると推測されるので、DBFlute Engineのコネクションから見ればスキーマ名を付与しなくても良いのでスキーマ名が付かず、でも実行環境だと共有のコネクションで対象スキーマはどちらかは別になるので実行できないと。恐らくこうかな。(やはり同じにような環境作らないと検証できないか)

(続・独り言)
単純に、isAvailableで付与するように修正するのは簡単だけど、万が一2重でスキーマ名が付与されてしまうケースがあると良くないので、論理的にピタっと来るロジックを考え中。。。
レス遅くなってしまい申し訳ございませんでした。
SQL上のスキーマ名も自動で付与されるので、schema2を追加スキーマとして登録しても問題ないかなとは思ったのですが、どうなんでしょう?
スキーマを分割しているのは、例えば郵便番号辞書とか消費税計算ロジックだとか使い回しを前提としているライブラリなんですよ。
一つのスキーマをmavenの一モジュールとして作成しているので、追加スキーマという選択肢は取りたくないんですよ。
Sequenceは、実際にserial型で自動生成されたSequenceでしょうか?
はい。自動生成されたsequenceです。
よろしくお願いします。
なるほど、もう業務依存しないマスター系なのですね。serial型でりょうかいです。
ちょと修正検討しますので、しばらくdfpropでの回避でお願いしますm(_ _)m
少なくともテーブル名については正しくスキーマ装飾されているので、同じロジックで問題無いように思いますがどんなもんでしょうか?
また、sequenceMap.dfpropへの設定がされている場合、「わざわざ」設定されているとみなせるので、下手にスキーマ装飾を付加としてしまうと、開発者の意図から外れてしまう可能性が高いと思います。
こちらは現行通りで問題無いのでは、って思いますです。
そうですね、dfpropの方はそのままの仕様で、明示的に書くの方が良さそうですね。ありがとうございます。
serial型のSequenceの方は、メタデータの取り方がテーブルとSequenceで全然違うので、素のメタデータの状態でスキーマ名が付与されてたりされてなかったりがブレる可能性があるんですよね。
いま、それぞれのDBFluteクライアントでのdatabaseInfoMap.dfpropの「schema」は、対象のスキーマにしていますか?
例えば、seaとlandというスキーマがあったとしたら、それぞれのDBFluteクライアントで自分のスキーマを指定します。
dbflute_seadb:
schema = sea

dbflute_landdb:
schema = land
(まあそうじゃないとメタデータ取得できないですよね)
一方で、アプリ実行時の接続データソースのスキーマは何か指定されていますか?(指定なければpublicがデフォルトになるような気がします)
databaseInfoMap.dfprop の設定はご指摘の通りです。
dataSource のカレントデータベースはpublicではなく、業務ロジック用に仕立てたスキーマを指定しています。
ありがとうございます。
まあやはり、自動生成時と実行時でコネクションの対象スキーマが変わることによるズレってのが、serial型のSequence名で発生しちゃうってところですね。
検証環境を作ってから修正ロジック考えて対応していきますね。
jflute commented 1 year ago

とりあえず、isAvalable=true、かつ、serial sequenceに何もスキーマ名がなければ付与するで良いかな。 スキーマ名が付いてるかどうか?は、ドットが含まれてるかどうか?で判断しても問題ないだろう。 (追加スキーマの場合は勝手にスキーマ名が付くので、メタデータにスキーマ名があるならそっちを使うようにする)