MyBatisストリーミングクエリの3つの実装方法


ガイド:ストリーミングクエリとは、クエリが成功した後、集合に戻るのではなく、1つのサブコーダに戻り、その都度、サブコーダからクエリ結果を抽出することを意味します。ストリーミングクエリの利点は、メモリの使用を低減することです。
もしストリーミングクエリがないなら、私達はデータベースから1000万本の記録を取りたいですが、十分なメモリがない場合は、ページ別に調べなければなりません。ページ別の検索効率は表の設計によって決まります。もしデザインが良くないなら、効率的なページ別のクエリを実行することができません。したがって、ストリーミングクエリはデータベースアクセスフレームに必須の機能です。
ストリーミングクエリのプロセスでは、データベース接続はオープン状態を維持していますので、ストリーミングクエリを実行した後、データベースアクセスフレームはデータベース接続をオフにする責任がありません。データを取った後、自分でシャットダウンする必要があります。
MyBatisフロー式クエリインターフェース
MyBatisはorg.apphe.ibatis.cursor.Cursorというインターフェースクラスを提供しています。このインターフェースはjava.io.loseableとjava.lang.Iterableインターフェースを継承しています。
  • Cursorはオフできます。実際にCursorをオフにすると、データベース接続も一緒にオフになります。
  • Cursorは遍歴可能です。
  • この他に、Cursorは、3つの方法を提供する。
  • isOpen():データを取る前にCursorオブジェクトがオン状態であるかどうかを判断するためのもの。開けた時にのみCursorはデータを取ります。
  • isConsmed():クエリーの結果が全部取れたかどうかを判断するために使用されます。
  • get CurrenntIndex():いくつかのデータが取得されたかを返す。
  • Currsorは、ディケンサインターフェースを実現しているので、実際の使用では、Curerからデータを取るのは非常に簡単です。
    
    try(Cursor cursor = mapper.querySomeData()) {
        cursor.forEach(rowObject -> {
            // ...
        });
    }
    
    try-resource方式を使用するとCursorが自動的に閉じることができます。
    しかし、Cursorを構築する過程は簡単ではない。
    私たちは実際の例を挙げます。次はMapper類です。
    
    @Mapper
    public interface FooMapper {
        @Select("select * from foo limit #{limit}")
        Cursor<Foo> scan(@Param("limit") int limit);
    }
    
    方法scan()は非常に簡単な検索です。この当事者を定義するとき、戻り値をCursorタイプに指定します。MyBatisはこのクエリ方法がストリーミングクエリであることが分かります。
    その後、SpringMVC Controller方法を書いて、Mapperを呼び出します。
    
    @GetMapping("foo/scan/0/{limit}")
    public void scanFoo0(@PathVariable("limit") int limit) throws Exception {
        try (Cursor<Foo> cursor = fooMapper.scan(limit)) {  // 1
            cursor.forEach(foo -> {});                      // 2
        }
    }
    
    fooMapperが@Autowiredで入ってきたと仮定します。注釈1はCursorオブジェクトを取得し、最後に閉じることができることを保証する。2箇所は、cursorからデータを取ります。
    上のコードは問題ないようですが、scanFoo 0を実行するとエラーが発生します。
    java.lang.Illagal StateException:A Currsor is already closed.
    これは前に言ったように、データを取る過程でデータベース接続を維持する必要がありますが、Mapper方法は通常実行後に接続がオフになりますので、Cusorも一緒にオフになりました。
    だから、この問題を解決する考えは複雑ではなく、データベース接続を維持して開けばいいです。私たちは少なくとも三つの案があります。
    案一:Sql Session Factory
    Sql Session Factoryでデータベース接続を手動で開くことができます。Controller方法を以下のように修正します。
    
    @GetMapping("foo/scan/1/{limit}")
    public void scanFoo1(@PathVariable("limit") int limit) throws Exception {
        try (
            SqlSession sqlSession = sqlSessionFactory.openSession();  // 1
            Cursor<Foo> cursor = 
                  sqlSession.getMapper(FooMapper.class).scan(limit)   // 2
        ) {
            cursor.forEach(foo -> { });
        }
    }
    
    上のコードの中で、1箇所はSql Sessionを開いています。(実際にはデータベース接続を表しています。)最後に閉じることができるように保証します。2箇所はSql Sessionを使ってMapperオブジェクトを獲得します。このようにして得られたCursorオブジェクトはオープン状態であることが保証されます。
    案二:Transaction Template
    Springでは、Transaction Templateでデータベーストランザクションを実行できます。この過程でデータベース接続は同じように開かれています。コードは以下の通りです
    
    @GetMapping("foo/scan/2/{limit}")
    public void scanFoo2(@PathVariable("limit") int limit) throws Exception {
        TransactionTemplate transactionTemplate = 
                new TransactionTemplate(transactionManager);  // 1
        transactionTemplate.execute(status -> {               // 2
            try (Cursor<Foo> cursor = fooMapper.scan(limit)) {
                cursor.forEach(foo -> { });
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        });
    }
    
    上記のコードの中で、1つのTransaction Templateオブジェクトを作成しました。2つはデータベース事務を実行します。データベース事務の中身はMapper対象のストリーミングクエリを呼び出します。ここのMapperオブジェクトはSql Sessionで作成する必要がありません。
    案三:@Transactionalコメント
    この本質は方案と同じで、コードは以下の通りです。
    
    @GetMapping("foo/scan/3/{limit}")
    @Transactional
    public void scanFoo3(@PathVariable("limit") int limit) throws Exception {
        try (Cursor<Foo> cursor = fooMapper.scan(limit)) {
            cursor.forEach(foo -> { });
        }
    }
    
    ただ元の方法に@Transationコメントを付けただけです。この案は一番簡潔に見えるが、Springフレームの中で使用されている穴に注意してください。外部呼び出し時のみ有効です。この方法を現在のクラスで呼び出しても、エラーが発生します。
    これまでMyBatis流动调査の実现方法についての记事をここに绍介します。MyBatis流动调査の内容については、以前の文章を検索してください。または、下の関连する文章を引き続きご覧ください。これからもよろしくお愿いします。