Jdbi: @CreateSqlObjectの混乱を少なくしたす。

䜜成日 2018幎02月01日  Â·  20コメント  Â·  ゜ヌス: jdbi/jdbi

問題
JDBIの公匏ドキュメントでは、開発者は@CreateSqlObjectアノテヌションが異皮のDAOにトランザクションサポヌトを远加するためのメカニズムであるず信じおいたす。

http://jdbi.org/#__createsqlobject

これは、実際の動䜜に少し誀解を招くように思われたす。これは、掚奚されるjdbi.onDemand䜜成メカニズムを䜿甚しお䜿甚するず、状態゚ラヌが発生する可胜性がありたす。

フォヌラムには、この混乱を説明するメッセヌゞがいく぀かありたす。

リク゚スト
この問題の最善の解決策が䜕であるかわからない。 頭に浮かぶいく぀か

  • 非掚奚
  • 欠点に関するより良いドキュメント
  • ク゚リを耇数のDAOに分割する別の゜リュヌションですが、論理的なトランザクションセマンティクスでク゚リを結び付けるこずができたす。 具䜓的には、読み取り専甚/曞き蟌みトランザクションの組み合わせをサポヌトしたす。
cleanup improvement

最も参考になるコメント

もう䞀床コメントしおすみたせん。 これに圹立぀ロヌドマップに䜕かありたすか

党く問題無い。 これは明らかに混乱の原因であり、修正したいこずがありたす。前回はしなかったので、今回は確実に正しく修正したいず思いたす:)

 @svladaが述べたように、他のフレヌムワヌクでは、より高いレベルで@Transactionalを䜿甚するのが非垞に䞀般的です

ええ、でも私が理解しおいる限り、それはすべおDIフレヌムワヌクSpringなどのAOPフックを介しお行われたす。 JDBIはすべおのサヌビスオブゞェクトを「ラップ」するわけではないため、自分で䜜成しおいないオブゞェクトにAOPのような゜リュヌションを提䟛する機䌚はありたせん。 叀いcglib実装でさえ、daos自䜓の@Transactionalにしか気付かず、別のサヌビスクラスで機胜するこずはありたせんでした。

圹立぀堎合は、SpringやGuiceのAOPバむンディングを远加しお、より高いレベルのトランザクションを蚱可するこずを怜蚎できたす。 これはcoreの䞀郚ではなく、たずえばspring拡匵機胜の䞀郚になりたす。 これはコア開発者が飛び぀くようなものではないでしょうが、貢献は真剣に含たれるず考えられたす。 倚分それはあなたの問題を「よりクリヌンな」方法で解決したすか

䞻に互換性の理由から、 cglibからProxyに切り替えるこずにしたした- Proxyはサポヌトされおいるjdk apiですが、 cglib たたはより具䜓的asm は、メゞャヌリリヌス8、9、11、...で壊れたごずに壊れる傟向があり、これは倧きなメンテナンスの頭痛の皮になりたす。

党おのコメント20件

これを報告しおいただきありがずうございたす。 ここで技術的に重倧な倉曎が行われるこずになるず思いたすが、既存の動䜜は十分に貧匱であるため、3.xリリヌスサむクルの早い段階で技術的に重倧な倉曎を加えるこずができたす。 既存の動䜜に䟝存しおいる堎合、たたはここで小さな重倧な倉曎を出荷する可胜性に同意しない堎合は、この問題にフラグを立おおください。

_why_ @CreateSqlObjectに関するコンテキストのためだけに、オンデマンドではうたく機胜したせん。

  • オンデマンドはコアレベルの抜象化であり、プロキシを䜿甚しお実装されたす。 オンデマンドプロキシでメ゜ッドを呌び出すず、実際のSQLオブゞェクトが䜜成され、メ゜ッド呌び出しが実際のSQLオブゞェクトに委任されたす。 その実むンスタンスをサポヌトするハンドルは、デリゲヌトメ゜ッド呌び出しが戻った埌に閉じられたす。
  • @CreateSqlObjectは、元のSQLオブゞェクトのバッキングハンドルを䜿甚しおhandle.attach(sqlObjectType)を䜿甚しお実装されたす。

したがっお、䜜成されたSQLオブゞェクトのバッキングハンドルは、SQLオブゞェクトが返される前に閉じられたす。

䞊蚘のどれも決たっおいない-それはたさに今それが実装されおいる方法です。

これを修正するために互換性を砎る必芁があるずは思いたせん。

申し蚳ありたせんが、実際にはわかりたせん... onDemandずCreateSqlObjectの正確な問題は䜕ですか 私はそれで問題を抱えたこずは䞀床もありたせん、そしお@qualidafialの説明に぀いおの䜕かが私の心を傟けさせおいるだけです...

image

fooProxy.usecaseの呌び出しのために接続が取埗されたす。 Foo.usecaseは、createSqlObjectメ゜ッドバヌを呌び出したす。このバヌは、珟圚のナヌスケヌスのハンドルにアタッチした埌に新しいバヌを返したす。 ナヌスケヌスが戻るず、ナヌスケヌスのハンドルは閉じられたす。 返されたBarず非同期で䜕もしおいない限り、 barのハンドルが早く期限切れになるのはどうしおですか バヌのラむフサむクルず䜿甚は、ハンドルず同様にFoo.usecaseの本䜓に限定されおいたす。

JDBIの内郚に぀いお話すこずはできたせんが、本番環境で芋た動䜜に぀いおコメントするこずはできたす。

基本的に、私たちのより䜎い環境では物事は倧䞈倫でした。 しかし、本番環境での負荷が増えるず、SQLステヌトメントが適切なデヌタベヌスノヌドに察しお実行されないこずが継続的に発生したす。 たずえば、読み取り専甚の遞択はマスタヌノヌドにヒットし、挿入は読み取りレプリカにヒットしたす。 さらに、操䜜の途䞭で接続が閉じられるずいう゚ラヌが発生したした。

基本的に、 @ CreateSqlObjectによっおスレッドセヌフの問題が発生したようです。぀たり、競合するリク゚ストによっお読み取り専甚フラグが倉曎されおいたした。

問題を「解決」するために、 @CreateSqlObjectの䜿甚をすべお削陀し、次のようになりたした。

  • class FooDao
  • class BarDao
  • class CombinedDao extends FooDao, BarDao

そしお、 jdbi.onDemand(CombinedDao)し、それを介したアクセスのみを䜿甚したす。
そのパタヌンに切り替えるこずで、それほどきれいではありたせんが、本番環境での前述の゚ラヌをすべお取り陀くこずができたした。

ちなみに、珟時点ではすべおのコヌドが抜象クラスでonDemandを䜿甚しおいるため、JDBI 2に戻るこずを考えおいたす。たた、満足のいく方法で再構築する方法を理解できたせん。

私は、ロゞックを含むがSQLを含たない抜象実装クラスを持ち、トランザクションずしお泚釈が付けられたメ゜ッドを持ち、CreateSqlObjectを䜿甚しお玔粋にSQLであるDAOクラスぞのアクセスを提䟛するサヌビスむンタヌフェむスを持぀傟向がありたす。 簡単な䟋

むンタヌフェヌス

public interface AccountService {
    void addAccount(Account account, User user);
}  

実装

public abstract class AccountServiceJdbi implements AccountService {

    <strong i="11">@Override</strong>  
    <strong i="12">@Transaction</strong>  
    public final void addAccount(@BindBean() Account account, User user) {
        long accountId =  accountDao().insertAccount(account);
        accountDao().linkAccountToOwner(accountId, user.getId());
    }

    <strong i="13">@CreateSqlObject</strong>
    abstract AccountDao accountDao();
}

あなたはダオを想像するこずができたす

これにより、耇数のDAOメ゜ッドを介したトランザクションを可胜にしながら、ロゞックずデヌタアクセスを非垞にうたく分離できたす。 サヌビスの単䜓テストは、DAOむンタヌフェヌスを実装するこずにより、簡単に蚘述および理解できたす。

JDBI 3でも同様のこずを詊みたしたが、サヌビスクラスの実装は、ロゞックを含むメ゜ッドのデフォルトメ゜ッドずのむンタヌフェむスである必芁があるこずを意味するず思いたす。 デフォルトのメ゜ッドをfinalにするこずはできないため、コヌドは簡朔ではなく、クラスの䜿甚方法をあたり制埡できたせん。

JDBI 3でコヌドを構造化しお、最終的なトランザクションメ゜ッドを䜜成する方法はありたすか

むンタヌフェむスメ゜ッドをfinalずしお定矩する方法がないこずは正しいです。

ただし、 @SqlQuery 、 @SqlUpdateなどず同等の独自のSQLメ゜ッドアノテヌションを定矩し、そのアノテヌションを持぀メ゜ッドの静的実装を提䟛するこずはできたす。

ただし、 @SqlQuery 、 @SqlUpdateなどず同等の独自のSQLメ゜ッドアノテヌションを定矩し、そのアノテヌションを持぀メ゜ッドの静的実装を提䟛するこずはできたす。

返信ありがずうございたす-私はそれが私をどのように助けるかに぀いおは完党にはフォロヌしおいたせん。 耇数のDAOでク゚リを実行しながら、同じトランザクションでク゚リを実行するための掚奚される方法は䜕ですか

耇数のDAOでク゚リを実行するが、同じトランザクションでク゚リを実行する方法はありたすか

個人的には

interface Dao1 {
  @SqlQuery("...")
  void query1();
}

interface Dao2 {
  @SqlQuery("...")
  void query2();
}

interface JdbiServiceImpl extends Service {
  <strong i="8">@CreateSqlObject</strong>
  Dao1 dao1();
  <strong i="9">@CreateSqlObject</strong>
  Dao2 dao2();

  <strong i="10">@Transaction</strong>
  <strong i="11">@Override</strong>
  void businessCase() {
    dao1().query1();
    dao2().query2();
  }
}

Service service = handle.attach(JdbiServiceImpl.class);
service.businessCase();

このように私にずっおは玠晎らしい働きをしたす。 @CreateSqlObjectは基本的に、getter / setterによるSpringの䟝存性泚入に䌌おいたす。 私はonDemandむンスタンスをBeanずしおSpringコンテキストに配眮しおいるため、通垞のサヌビスずたったく同じように機胜したす。呌び出し元はjdbiや実装むンタヌフェむスに぀いお知る必芁はありたせん。

image

衚瀺されるアンチパタヌンのようなStockReductionCaseは、CreateSqlObjectを䜿甚したネストされたjdbiの「䟝存性泚入」の䟋です。 サヌビスの実装ず同じように、内郚に独自の䟝存関係がありたす。 これは基本的にそれ自䜓がサヌビスです。サヌビストップレベルの再利甚䞍可胜なロゞックずク゚リのいずれかにCases耇数の堎所で必芁を配眮するだけで埪環䟝存を回避するために、ServiceではなくCaseず呌びたす。

image

特にonDemand()ず組み合わせるず、トランザクションを@CreateSqlObjectで正しくスコヌプするこずに成功したずいうさたざたな報告を聞いたこずがありたす。

同じトランザクションで耇数のSQLオブゞェクトを実行する最も確実な方法は、 Handle.inTransaction()たたはJdbi.inTransaction()を介しおトランザクションを実行するこずです。 コヌルバック内では、 Handle.attach()を介しお䜜成されたDAOは、ハンドルのトランザクションの䞀郚になりたす。

jdbi.useTransaction(handle -> {
  Dao1 dao1 = handle.attach(Dao1.class);
  Dao2 dao2 = handle.attach(Dao2.class);

  dao1.doStuff();
  dao2.doMoreStuff();
});

返信ありがずうございたす
@qualidafialこれは私が行かなければならない方法のように芋えたすが、サヌビスクラスの単䜓テストを䜜成するのは難しくなりたす。 Daos自䜓をむンスタンス化するため、単䜓テストの代わりにモックDaosを䜿甚するこずはできたせん。

@TheRealMarnesにも感謝したす-これは私が詊したものず䌌おいたすが、デフォルトのメ゜ッドを䜿甚するのは奜きではありたせん。オヌバヌラむドできるからです。

@qualidafial耇数のdaoメ゜ッドを呌び出すサヌビスメ゜ッドでjdbiの@Transactionアノテヌションを䜿甚できないこずを確認したいず思いたすか

この仮定が正しければ、公匏文曞の䞀郚ずしお適切に文曞化されおいないず、この動䜜は非垞に危険です。 倚数の開発者がSpringスタックの経隓があり、 @Transactionalアノテヌションを䜿甚するこずは、耇数のDAO間のトランザクションをサポヌトするための非垞に暙準的な方法です。

@svlada @TransactionアノテヌションはSQLオブゞェクトのメ゜ッドでのみ機胜したす。 「サヌビスメ゜ッド」ず蚀うず、Jdbiの圱響を受けないオブゞェクト、たずえば泚入されたクラスにアノテヌションを䜿甚しおいるずいう印象を受けたす。

テストスむヌトの䟋

<strong i="9">@Test</strong>
public void testInsertAndFind() {
    Foo foo = handle.attach(Foo.class);
    Something s = foo.insertAndFind(1, "Stephane");
    assertThat(s).isEqualTo(new Something(1, "Stephane"));
}

<strong i="10">@Test</strong>
public void testTransactionPropagates() {
    Foo foo = dbRule.getJdbi().open().attach(Foo.class);

    assertThatExceptionOfType(Exception.class)
        .isThrownBy(() -> foo.insertAndFail(1, "Jeff"));

    Something n = foo.createBar().findById(1);
    assertThat(n).isNull();
}

public interface Foo {
    <strong i="11">@CreateSqlObject</strong>
    Bar createBar();

    @SqlUpdate("insert into something (id, name) values (:id, :name)")
    int insert(@Bind("id") int id, @Bind("name") String name);

    <strong i="12">@Transaction</strong>
    default Something insertAndFind(int id, String name) {
        insert(id, name);
        return createBar().findById(id);
    }

    <strong i="13">@Transaction</strong>
    default Something insertAndFail(int id, String name) {
        insert(id, name);
        return createBar().explode();
    }
}

public interface Bar {
    @SqlQuery("select id, name from something where id = :id")
    Something findById(@Bind("id") int id);

    default Something explode() {
        throw new RuntimeException();
    }
}

onDemand() + @CreateSqlObjectに぀いおも明確にしおおきたい

  • @CreateSqlObject DAOは、䞊蚘の䟋のように、それらを䜜成したDAOの内郚メ゜ッドからのみ䜿甚できたす。
  • fooDao.createBar().findById()を呌び出すず、接続が閉じられたこずを瀺す䟋倖がスロヌされたす。

もう䞀床コメントしおすみたせん。 これに圹立぀ロヌドマップに䜕かありたすか

抜象クラスでCreateSqlObjectを䜿甚できるのはただ本圓に寂しいです。 むンタヌフェむスですべおを実行する必芁があるこずは、䟝然ずしお制限を感じたす。 倚くの堎合、「サヌビス」タむプのメ゜ッドをトランザクションにしたいのですが、これは、サヌビスクラスもデフォルトのメ゜ッドを䜿甚するむンタヌフェむスである必芁があり、関心の分離、具䜓的な最終メ゜ッドなどの明確さが倱われ始めるこずを意味したす。

@tamslinn抜象クラスではなくむンタヌフェヌスの問題に関する限り、近い将来、その決定から戻っおくるこずはないず私は安党に蚀えるず思いたす。 Jdbi3は、むンタヌフェヌスのみをサポヌトするjdkプロキシを䜿甚したす。

cglibに基づいお構築された、この機胜を提䟛する別のモゞュヌルが提䟛されおいるこずは完党に問題倖ではないず思いたすが、珟時点では問題ではありたせん。

sqlobjectの公理がそれに合わない堎合は、い぀でもサヌビスをリファクタリングしお、jdbiによっお拡匵されおいない通垞のクラスにするこずができたすが、代わりに流暢なAPIを䜿甚するためにJdbiむンスタンスを泚入するこずができたす。

トランザクションサポヌトやオンデマンドなどの本来の振る舞いに぀いおは、ただ具䜓的な蚈画はないず思いたすが、たすたす泚目が集たっおいたす。 しかし、私たちはそれに到達しおいたす。

アップデヌトしおいただきありがずうございたす。 プロキシに関しおは完党に理にかなっおいたす。
私にずっおの特定の制限は、JDBIクラスの倖郚でトランザクションを開始/終了できないこずです。
 @svladaが述べたように、他のフレヌムワヌクでは、より高いレベルで@Transactionalを䜿甚するのが非垞に䞀般的です
私はJDBIの他のすべおが本圓に奜きなので、それを維持したす。おそらく、サヌビスクラスに満足しおいるデザむンパタヌンを思い付くでしょう:)

もう䞀床コメントしおすみたせん。 これに圹立぀ロヌドマップに䜕かありたすか

党く問題無い。 これは明らかに混乱の原因であり、修正したいこずがありたす。前回はしなかったので、今回は確実に正しく修正したいず思いたす:)

 @svladaが述べたように、他のフレヌムワヌクでは、より高いレベルで@Transactionalを䜿甚するのが非垞に䞀般的です

ええ、でも私が理解しおいる限り、それはすべおDIフレヌムワヌクSpringなどのAOPフックを介しお行われたす。 JDBIはすべおのサヌビスオブゞェクトを「ラップ」するわけではないため、自分で䜜成しおいないオブゞェクトにAOPのような゜リュヌションを提䟛する機䌚はありたせん。 叀いcglib実装でさえ、daos自䜓の@Transactionalにしか気付かず、別のサヌビスクラスで機胜するこずはありたせんでした。

圹立぀堎合は、SpringやGuiceのAOPバむンディングを远加しお、より高いレベルのトランザクションを蚱可するこずを怜蚎できたす。 これはcoreの䞀郚ではなく、たずえばspring拡匵機胜の䞀郚になりたす。 これはコア開発者が飛び぀くようなものではないでしょうが、貢献は真剣に含たれるず考えられたす。 倚分それはあなたの問題を「よりクリヌンな」方法で解決したすか

䞻に互換性の理由から、 cglibからProxyに切り替えるこずにしたした- Proxyはサポヌトされおいるjdk apiですが、 cglib たたはより具䜓的asm は、メゞャヌリリヌス8、9、11、...で壊れたごずに壊れる傟向があり、これは倧きなメンテナンスの頭痛の皮になりたす。

たぶんhttps://github.com/jdbi/jdbi/pull/1252は関係がありたすか

こんにちは、

情報@stevenschlanskerをありがずう。 私は珟圚のプロゞェクトで実際にSpringずJDBIを䜿甚しおいたせんが、比范のために蚀及されたした。 私はAOPのこずを完党に理解しおいたす。それを回避する方法を芋぀けようずしおいるだけです。぀たり、コヌドを奜きなように分割できたす。これは、以前は抜象クラスでしたが、 cglibから離れるこずは完党に理にかなっおいたす。

今は、必芁なずきにサヌビスクラスを䜜成するだけで、トランザクション内でサヌビスクラスを䜜成できるようになるず考えおいたす。

         try (Handle handle = jdbi.open()) {
                handle.useTransaction(h -> {
                    AccountService accountService = new AccountServiceImpl(h.attach(AccountDao.class));                    
                    accountService.addAccount(a, u);
                });
          }

これは、Mock Daoを䜿甚しおサヌビスを単䜓テストし、サヌビスメ゜ッドを最終的に維持し、トランザクション管理のむンタヌフェむスのデフォルトメ゜ッドに䟝存しないこずを意味するず思いたす。たた、サヌビスクラスのむンスタンス化の远加オヌバヌヘッドが倧きな圱響を䞎えるこずはありたせん。

最埌のコメントのコヌド䟋に簡単に返信しおくださいtryブロックをスキップしお、$ jdbi.useTransaction()を盎接呌び出すこずができたす。 このメ゜ッドは、コヌルバックが戻ったずきに自動的に閉じられる䞀時的なハンドルを割り圓おたす。

みなさん、こんにちは。PR1579がありたす。jdbi3.10.0の時点で、CreateSqlObjectずonDemandは最終的にうたく連携するはずです。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡