Spring Boot、MyBatis、Phoenix連携時のケースセンシティブに関する問題と解決策

シナリオ:
Phoenixを使用してクエリサービスを構築し、サーバー側にインターフェースを提供する必要がありました。

設計:
Spring BootでRESTful APIを公開し、MyBatisでPhoenixのSQL処理を行うため、Spring Boot + MyBatis + Phoenixの統合方案を採用しました。

しかし、ここで重大な問題が発生しました!


シナリオの詳細:
ネットワークタクシーの予約単クエリ処理を実装する必要がありました。この処理では6種類の時間情報を使用する必要がありました:

  • 注文プッシュ時間
  • 有効な注文受付時間
  • 注文受注成功時間
  • 注文キャンセル時間
  • 目的地到着時間
  • 支払い時間

課題:
日を跨いだ支払いが発生する可能性があるため、基礎テーブルに対して6回のクエリを実行し、それぞれ異なる時間条件で検索し、最後にUNION処理と合計計算を行う必要がありました(ここで問題が発生しました!)

問題のあるコード


<select id="searchContext" resultType="com.df.entity.SearchInfo">
    SELECT
    TB."driver_id",
    TB."driver_name"",
    TB."mobile",
    TB."alliance_name",
    TB."register_city",
    TB."driver_type",
    SUM(TB."pushOrderNum") AS "pushOrderNum" ,
    SUM(TB."effectiveSlogan") AS "effectiveSlogan",
    SUM(TB."grab_sus_order") AS "grab_sus_order",
    SUM(TB."cancel_order_num") AS "cancel_order_num",
    SUM(TB."cancel_passenger_num") AS "cancel_passenger_num",
    SUM(TB."cancel_driver_num") AS "cancel_driver_num",
    SUM(TB."cancel_service_num") AS "cancel_service_num",
    SUM(TB."destination_reached_num") AS "destination_reached_num",
    SUM(TB."pay_num") AS "pay_num",
    SUM(TB."order_cumulative_num") AS "order_cumulative_num",
    SUM(TB."order_pay_cumulative_num") AS "order_pay_cumulative_num"
    FROM
    (
    SELECT
    "driver_id" ,
    "driver_name" ,
    "mobile" ,
    "alliance_name" ,
    "register_city" ,
    "driver_type" ,
    sum(to_number("pushOrderNum")) AS "pushOrderNum" ,
    sum(0) AS "effectiveSlogan" ,
    sum(0) AS "grab_sus_order" ,
    sum(0) AS "cancel_order_num",
    sum(0) AS "cancel_passenger_num",
    sum(0) AS "cancel_driver_num",
    sum(0) AS "cancel_service_num" ,
    sum(0) AS "destination_reached_num" ,
    sum(0) AS "pay_num" ,
    sum(0) AS "order_cumulative_num",
    sum(0) AS "order_pay_cumulative_num"
    FROM
    "_crontab_reservation"
    WHERE
    CASE WHEN "pushOrderTime" != '0' THEN
    TO_DATE("pushOrderTime",'yyyy-MM-dd') >= TO_DATE(#{start_time},'yyyy-MM-dd')
    AND
    TO_DATE("pushOrderTime",'yyyy-MM-dd') <= TO_DATE(#{end_time},'yyyy-MM-dd')
    ELSE 1=1 END
    <if test="driver_id != null and driver_id !=''" >
        and "driver_id"= #{driver_id}
    </if>
    <if test="driver_name != null and driver_name !=''" >
        and "driver_name" = #{driver_name}
    </if>
    <if test="mobile != null and mobile !=''" >
        and "mobile" = #{mobile}
    </if>
    <if test="alliance_name != null and alliance_name !=''" >
        and "driver_management_id" = #{alliance_name}
    </if>
    <if test="register_city != null and register_city !=''" >
        and substr("register_city" , 0 , 4) = substr(#{register_city} , 0 , 4)
    </if>
    <if test="driver_type != null and driver_type !=''" >
        and "driver_type" = #{driver_type}
    </if>
    GROUP BY
    "driver_id" ,
    "driver_name" ,
    "mobile" ,
    "alliance_name" ,
    "register_city" ,
    "driver_type"

    union all

    -- 他のUNION ALLセクションも同様の構造を持っています

    ) as TB
    GROUP BY
    TB."driver_id" ,
    TB."driver_name" ,
    TB."mobile" ,
    TB."alliance_name" ,
    TB."register_city" ,
    TB."driver_type"
</select>

問題の分析

このコードの問題点は、MyBatisでUNION操作を実行すると、生成されるテーブル名とフィールド名は大文字小文字を区別しないが、Phoenixでは公式に大文字小文字を区別するという点にあります。

MyBatis統合後のUNIONで生成されたテーブル名とフィールド名には、大文字小文字を区別する必要がなく、かつ二重引用符を付けるべきではないため、二重引用符を付けるとフィールドが見つからないなどのエラーが発生します。

解決策

解決策は、最終的なクエリでのテーブルエイリアスとフィールド参照の方法を変更することです。以下が修正後のコードです:


<select id="searchContext" resultType="com.df.entity.SearchInfo">
    SELECT
    "TB1".driver_id,
    "TB1".driver_name,
    "TB1".mobile,
    "TB1".alliance_name,
    "TB1".register_city,
    "TB1".driver_type,
    SUM("TB1".pushOrderNum) AS "pushOrderNum" ,
    SUM("TB1".effectiveSlogan) AS "effectiveSlogan",
    SUM("TB1".grab_sus_order) AS "grab_sus_order",
    -- 他のSUM関数も同様に修正
    
    FROM
    (
    -- ここではUNION ALLセクションは同じですが、
    -- 最終的なテーブルエイリアスを"TB1"としています
    
    ) AS "TB1"
    GROUP BY
    "TB1".driver_id ,
    "TB1".driver_name ,
    "TB1".mobile ,
    "TB1".alliance_name ,
    "TB1".register_city ,
    "TB1".driver_type
</select>

まとめ

この問題は、Phoenixの大文字小文字を区別する特性とMyBatisが生成するSQLの間の不一致によって引き起こされました。解決策として、UNION操作で生成されたテーブルのフィールド参照方法を変更し、大文字小文字の区別を適切に処理することで問題を解決しました。

このケースから学んだ教訓は、異なるデータベース技術を統合する際には、それぞれの特性を深く理解し、特に大文字小文字の扱いに注意を払う必要があるということです。

タグ: Spring Boot MyBatis Phoenix HBase SQL

6月30日 20:08 投稿