(7)エントリーから土壌ファンシークエリまでのMyBatis

これはmybatisシリーズの第7章です。以前の提案を読んでいない場合は、まず[Javaつくばフォックス]パブリックアカウントにアクセスして、以前のテキストを表示してください。これは、理解と把握に便利です。前回の記事では、主キーを取得するいくつかの方法について説明しましたが、この記事では、いくつかのクエリ方法、特にマルチテーブルクエリについて詳しく説明します。

開始する前に、データベースやテーブルの作成などの準備を開始します。

データベースを構築し、テーブルを構築します

データベースを作成します:mybatisdemo

4つのテーブル:

  • ユーザー(ユーザーテーブル)
  • 商品(商品リスト)
  • 注文(注文表)
  • order_detail(注文詳細テーブル)

テーブル間の関係:

  • 注文とユーザーの間には1対1の関係があります。1つの注文は1つのユーザーレコードに関連付けられます
  • Ordersとorder_detailは1対多の関係であり、各注文には複数のサブ注文が含まれる場合があり、各サブ注文は製品に対応します。

具体的なテーブル作成ステートメントは次のとおりです。

DROP DATABASE IF EXISTS `mybatisdemo`;
CREATE DATABASE `mybatisdemo`;
USE `mybatisdemo`;
DROP TABLE IF EXISTS user;
CREATE TABLE user(
  id int AUTO_INCREMENT PRIMARY KEY COMMENT '用户id',
  name VARCHAR(32) NOT NULL DEFAULT '' COMMENT '用户名'
) COMMENT '用户表';
INSERT INTO user VALUES (1,'冢狐'),(2,'Java冢狐');
DROP TABLE IF EXISTS goods;
CREATE TABLE goods(
  id int AUTO_INCREMENT PRIMARY KEY COMMENT '商品id',
  name VARCHAR(32) NOT NULL DEFAULT '' COMMENT '商品名称',
  price DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '商品价格'
) COMMENT '商品信息表';
INSERT INTO goods VALUES (1,'Mybatis系列',8.00),(2,'spring系列',16.00);
DROP TABLE IF EXISTS orders;
CREATE TABLE orders(
  id int AUTO_INCREMENT PRIMARY KEY COMMENT '订单id',
  user_id INT NOT NULL DEFAULT 0 COMMENT '用户id,来源于user.id',
  create_time BIGINT NOT NULL DEFAULT 0 COMMENT '订单创建时间(时间戳,秒)',
  up_time BIGINT NOT NULL DEFAULT 0 COMMENT '订单最后修改时间(时间戳,秒)'
) COMMENT '订单表';
INSERT INTO orders VALUES (1,2,unix_timestamp(now()),unix_timestamp(now())),(2,1,unix_timestamp(now()),unix_timestamp(now()));
DROP TABLE IF EXISTS order_detail;
CREATE TABLE order_detail(
  id int AUTO_INCREMENT PRIMARY KEY COMMENT '订单明细id',
  order_id INT NOT NULL DEFAULT 0 COMMENT '订单id,来源于order.id',
  goods_id INT NOT NULL DEFAULT 0 COMMENT '商品id,来源于goods.id',
  num INT NOT NULL DEFAULT 0 COMMENT '商品数量',
  total_price DECIMAL(12,2) NOT NULL DEFAULT 0 COMMENT '商品总金额'
) COMMENT '订单表';
INSERT INTO order_detail VALUES (1,1,1,2,16.00),(2,1,1,1,16.00),(3,2,1,1,8.00);
select * from user;
select * from goods;
select * from orders;
select * from order_detail;

データベースとテーブルを構築した後、次のステップでクエリジャーニーを開始します。最も基本的な単一テーブルクエリから始めて、単一テーブルクエリ、1対1クエリ、および1対多クエリを導入します。順番。

単一テーブルクエリ(3つの方法)

最初の紹介は、単一テーブルクエリです。

要求する

注文情報は、注文IDに従って照会する必要があります。

方法1

各テーブルに対応するモデルを作成します

db内のテーブルのフィールドはアンダースコアで区切られています。モデルでは、OrderModelのようにラクダの命名法を使用して名前を付けています。

package com.zhonghu.chat07.demo1.model;
import lombok.*;
import java.util.List;
@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class OrderModel {
    private Integer id;
    private Integer userId;
    private Long createTime;
    private Long upTime;
}

他のいくつかのモデルも同様です。

マッパーxml
<select id="getById" resultType="com.zhonghu.chat07.demo1.model.OrderModel">
    <![CDATA[
    SELECT a.id,a.user_id as userId,a.create_time createTime,a.up_time upTime FROM orders a WHERE a.id = #{value}
    ]]>
</select>

結果のタイプを識別する上記のresultTypeに注意してください。

マッパーインターフェース方式
OrderModel getById(int id);
mybatisグローバル設定ファイル
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 引入外部jdbc配置 -->
    <properties resource="jdbc.properties"/>
    <!-- 环境配置,可以配置多个环境 -->
    <environments default="demo4">
        <environment id="demo4">
            <!-- 事务管理器工厂配置 -->
            <transactionManager type="JDBC"/>
            <!-- 数据源工厂配置,使用工厂来创建数据源 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="demo1/mapper/UserMapper.xml" />
        <mapper resource="demo1/mapper/GoodsMapper.xml" />
        <mapper resource="demo1/mapper/OrderMapper.xml" />
        <mapper resource="demo1/mapper/OrderDetailMapper.xml" />
    </mappers>
</configuration>
テストケース
com.zhonghu.chat07.demo1.Demo1Test#getById
@Before
public void before() throws IOException {
    //指定mybatis全局配置文件
    String resource = "demo1/mybatis-config.xml";
    //读取全局配置文件
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //构建SqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    this.sqlSessionFactory = sqlSessionFactory;
}
@Test
public void getById() {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById(1);
        log.info("{}", orderModel);
    }
}
出力を実行
35:59.211 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById - ==>  Preparing: SELECT a.id,a.user_id as userId,a.create_time createTime,a.up_time upTime FROM orders a WHERE a.id = ? 
35:59.239 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById - ==> Parameters: 1(Integer)
35:59.258 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById - <==      Total: 1
35:59.258 [main] INFO  c.j.chat05.demo1.Demo1Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573)
原理

SQLでは、エイリアスを使用して注文のフィールドをOrderModelのフィールドと同じ名前に変換しました。最後に、mybatisはクエリ結果を内部的に反映して、名前に従ってOrderModelの同じ名前のフィールドを検索し、それらを割り当てます。

方法2

プロジェクトのテーブルに対応するモデルのフィールドがすべてラクダの命名方法を使用している場合、mybatisでいくつかの構成を行って、テーブルのフィールドをモデルのラクダの命名方法に対応するフィールドに自動的にマッピングできます。

mybatisグローバル設定ファイルに次の設定を追加する必要があります。

<settings>
    <!-- 是否开启自动驼峰命名规则映射,及从xx_yy映射到xxYy -->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
マッパーxml
<select id="getById1" resultType="com.zhonghu.chat07.demo1.model.OrderModel">
    <![CDATA[
    SELECT a.id,a.user_id,a.create_time,a.up_time FROM orders a WHERE a.id = #{value}
    ]]>
</select>

上記のSQLでは、エイリアスを記述していないことに注意してください。自動ラクダ命名マッピングを有効にしているため、クエリ結果は次の関係に従って自動的にマッピングされます。

SQL対応フィールド OrderModelのフィールド
id id
ユーザーID ユーザーID
create_time createTime
up_time upTime
マッパーインターフェース
OrderModel getById1(int id);
テストケース
com.zhonghu.chat05.demo1.Demo1Test#getById1
@Test
public void getById1() {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById1(1);
        log.info("{}", orderModel);
    }
}
出力を実行
59:44.884 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==>  Preparing: SELECT a.id,a.user_id,a.create_time,a.up_time FROM orders a WHERE a.id = ? 
59:44.917 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==> Parameters: 1(Integer)
59:44.935 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - <==      Total: 1
59:44.935 [main] INFO  c.j.chat05.demo1.Demo1Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573)

出力から、sqlのフィールドに下線が引かれ、OrderModelのフィールドがラクダの名前であり、結果が自動的にアセンブルされていることがわかります。これは、mapUnderscoreToCamelCaseをオンにした効果です。

方法3

mapper xmlにはより強力な要素resultMapがあり、これを介してクエリ結果のマッピング関係を定義できます。

マッパーxml
<resultMap id="orderModelMap2" type="com.zhonghu.chat07.demo1.model.OrderModel">
    <id column="id" property="id" />
    <result column="user_id" property="userId" />
    <result column="create_time" property="createTime" />
    <result column="up_time" property="upTime" />
</resultMap>
<select id="getById2" resultMap="orderModelMap2">
    <![CDATA[
    SELECT a.id,a.user_id,a.create_time,a.up_time FROM orders a WHERE a.id = #{value}
    ]]>
</select>

上記のresultMapには、指定する必要のある2つの要素があります。

  • id:resultMapの識別
  • type:結果をカプセル化するタイプ。ここでは、結果をOrderModelとしてパッケージ化する必要があります。

上記のselect要素には、クエリ結果のマッピングに使用されるresultMapを識別するresultMapがあることに注意してください。ここではorderModelMap2を使用するため、クエリ結果はorderModelMap2に関連付けられたresultMapに従ってマッピングされます。

マッパーインターフェース
OrderModel getById2(int id);
テストケース
com.zhonghu.chat07.demo1.Demo1Test#getById2
@Test
public void getById2() {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById2(1);
        log.info("{}", orderModel);
    }
}

出力を実行

14:12.518 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==>  Preparing: SELECT a.id,a.user_id,a.create_time,a.up_time FROM orders a WHERE a.id = ? 
14:12.546 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==> Parameters: 1(Integer)
14:12.564 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - <==      Total: 1
14:12.564 [main] INFO  c.j.chat05.demo1.Demo1Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573)

1対1の関連クエリ(4つの方法)

単一テーブルクエリについて説明した後、テーブルクエリから始めましょう。最初は、1対1のクエリです。

要求する

注文IDで注文を照会すると、注文に関連付けられたユーザー情報も返されます。

次のように、OrderModelコードを変更し、内部にUserModelを追加しましょう。

package com.zhonghu.chat07.demo2.model;
import lombok.*;
import java.util.List;
@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class OrderModel {
    private Integer id;
    private Integer userId;
    private Long createTime;
    private Long upTime;
    //下单用户信息
    private UserModel userModel;
}

UserModelコンテンツ:

package com.zhonghu.chat07.demo2.model;
import lombok.*;
@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UserModel {
    private Integer id;
    private String name;
}

方法1

マッパーxml
<resultMap id="orderModelMap1" type="com.zhonghu.chat07.demo2.model.OrderModel">
    <id column="id" property="id" />
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <result column="user_id" property="userModel.id"/>
    <result column="name" property="userModel.name"/>
</resultMap>
<select id="getById1" resultMap="orderModelMap1">
    <![CDATA[
    SELECT
        a.id,
        a.user_id,
        a.create_time,
        a.up_time,
        b.name
    FROM
        orders a,
        user b
    WHERE
        a.user_id = b.id
    AND a.id = #{value}
    ]]>
</select>

上記の2行に注意してください。

<result column="user_id" property="userModel.id"/>
<result column="name" property="userModel.name"/>

この場所では、カスケード割り当てが使用され、複数のレベル間の参照に使用されます。ここでは、レベルが1つしかないため、多くのレベルが存在する可能性があります。

マッパーインターフェース
OrderModel getById1(int id);
テストケース
com.zhonghu.chat07.demo2.Demo2Test#getById1
@Before
public void before() throws IOException {
    //指定mybatis全局配置文件
    String resource = "demo2/mybatis-config.xml";
    //读取全局配置文件
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //构建SqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    this.sqlSessionFactory = sqlSessionFactory;
}
@Test
public void getById1() {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById1(1);
        log.info("{}", orderModel);
    }
}
出力を実行
24:20.811 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==>  Preparing: SELECT a.id, a.user_id, a.create_time, a.up_time, b.name FROM orders a, user b WHERE a.user_id = b.id AND a.id = ? 
24:20.843 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==> Parameters: 1(Integer)
24:20.861 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - <==      Total: 1
24:20.861 [main] INFO  c.j.chat05.demo2.Demo2Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573, userModel=UserModel(id=2, name=Java冢狐))

方法2

今回は、mapper xmlで別の要素の関連付けを使用する必要があります。この要素は、関連付けられたオブジェクトのマッピング関係を構成できます。例を参照してください。

マッパーxml
<resultMap id="orderModelMap2" type="com.zhonghu.chat07.demo2.model.OrderModel">
    <id column="id" property="id" />
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <association property="userModel">
        <id column="user_id" property="id"/>
        <result column="name" property="name" />
    </association>
</resultMap>
<select id="getById2" resultMap="orderModelMap2">
    <![CDATA[
    SELECT
        a.id,
        a.user_id,
        a.create_time,
        a.up_time,
        b.name
    FROM
        orders a,
        user b
    WHERE
        a.user_id = b.id
    AND a.id = #{value}
    ]]>
</select>

上記のコードの次の部分に注意してください。

<association property="userModel">
    <id column="user_id" property="id"/>
    <result column="name" property="name" />
</association>

上記のプロパティ属性に注意してください。これは、SQLクエリ結果とOrderModel.userModelオブジェクト間のマッピング関係を構成し、user_idをuserModelのidにマップし、名前をuserModelの名前にマップするためです。

マッパーインターフェース
OrderModel getById2(int id);
テストケース
@Test
public void getById2() {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById2(1);
        log.info("{}", orderModel);
    }
}
運転結果
51:44.896 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==>  Preparing: SELECT a.id, a.user_id, a.create_time, a.up_time, b.name FROM orders a, user b WHERE a.user_id = b.id AND a.id = ? 
51:44.925 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==> Parameters: 1(Integer)
51:44.941 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - <==      Total: 1
51:44.942 [main] INFO  c.j.chat05.demo2.Demo2Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573, userModel=UserModel(id=2, name=Java冢狐))

結果の最後の行から、すべてのフィールドの値のマッピングに問題がないことがわかります。

方法3

最初に注文IDに従って注文データをクエリし、次にユーザーテーブルに移動して、注文のuser_idを介してユーザーデータをクエリします。2回のクエリの後、ターゲットの結果が結合されます。Mybatisには、この種の操作が組み込まれています。次のように。

UserMapper.xml

まず、次のように、ユーザーIDでユーザー情報を照会するためのselect要素を定義します。

<select id="getById" resultType="com.zhonghu.chat07.demo2.model.UserModel">
    <![CDATA[
    SELECT id,name FROM user where id = #{value}
    ]]>
</select>
OrderModel.xml
<resultMap id="orderModelMap3" type="com.zhonghu.chat07.demo2.model.OrderModel">
    <id column="id" property="id" />
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <association property="userModel" select="com.zhonghu.chat07.demo2.mapper.UserMapper.getById" column="user_id" />
</resultMap>
<select id="getById3" resultMap="orderModelMap3">
    <![CDATA[
    SELECT
        a.id,
        a.user_id,
        a.create_time,
        a.up_time
    FROM
        orders a
    WHERE
        a.id = #{value}
    ]]>
</select>

OrderModel.userModel属性の値は別のクエリから取得されます。このクエリは、関連付け要素のselect属性によって指定されます。

com.zhonghu.chat07.demo2.mapper.UserMapper.getById

このクエリは条件付きであり、条件は関連付けの列を介して渡されます。ここで、getById3のクエリ結果のuser_idフィールドが渡されます。

マッパーインターフェース
OrderModel getById3(int id);
テストケース
com.zhonghu.chat07.demo2.Demo2Test#getById3
@Test
public void getById3() {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById3(1);
        log.info("{}", orderModel);
    }
}
出力を実行
07:12.569 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById3 - ==>  Preparing: SELECT a.id, a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
07:12.600 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById3 - ==> Parameters: 1(Integer)
07:12.619 [main] DEBUG c.j.c.d.mapper.UserMapper.getById - ====>  Preparing: SELECT id,name FROM user where id = ? 
07:12.620 [main] DEBUG c.j.c.d.mapper.UserMapper.getById - ====> Parameters: 2(Integer)
07:12.625 [main] DEBUG c.j.c.d.mapper.UserMapper.getById - <====      Total: 1
07:12.625 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById3 - <==      Total: 1
07:12.625 [main] INFO  c.j.chat05.demo2.Demo2Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573, userModel=UserModel(id=2, name=Java冢狐))

出力から、2つのクエリがあり、最初に注文IDに従って注文をクエリし、次にユーザーテーブルに移動して、注文レコードのユーザーIDを介してユーザー情報をクエリし、最後に2つのクエリを実行することがわかります。

方法4

方法3では、1つのパラメーターが2番目のクエリに渡されます。2番目のクエリに複数のパラメーターを渡す必要がある場合はどうなりますか?このように書くことができます

<association property="属性" select="查询对应的select的id" column="{key1=父查询字段1,key2=父查询字段2,key3=父查询字段3}" />

これは、マップをサブクエリに渡すことと同じです。サブクエリでは、対応する条件を取得するためにマップのキーを使用する必要があります。次の場合を参照してください。

OrderMapper.xml

<resultMap id="orderModelMap4" type="com.zhonghu.chat07.demo2.model.OrderModel">
    <id column="id" property="id" />
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <association property="userModel" select="com.zhonghu.chat07.demo2.mapper.UserMapper.getById1" column="{uid1=user_id,uid2=create_time}" />
</resultMap>
<select id="getById4" resultMap="orderModelMap4">
    <![CDATA[
    SELECT
        a.id,
        a.user_id,
        a.create_time,
        a.up_time
    FROM
        orders a
    WHERE
        a.id = #{value}
    ]]>
</select>

UserMapper.xml

<select id="getById1" resultType="com.zhonghu.chat07.demo2.model.UserModel">
    <![CDATA[
    SELECT id,name FROM user where id = #{uid1} and id = #{uid2}
    ]]>
</select>

マッパーインターフェース

OrderModel getById4(int id);

テストケース

com.zhonghu.chat07.demo2.Demo2Test#getById4
@Test
public void getById4() {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById4(1);
        log.info("{}", orderModel);
    }
}

出力を実行

19:59.881 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById4 - ==>  Preparing: SELECT a.id, a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
19:59.914 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById4 - ==> Parameters: 1(Integer)
19:59.934 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====>  Preparing: SELECT id,name FROM user where id = ? and id = ? 
19:59.934 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====> Parameters: 2(Integer), 1610803573(Long)
19:59.939 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - <====      Total: 0
19:59.939 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById4 - <==      Total: 1
19:59.939 [main] INFO  c.j.chat05.demo2.Demo2Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573, userModel=null)

出力の2番目のクエリの条件を見てください。渡されるのは最初のクエリのuser_idとcreate_timeです。

1対多のクエリ(2つの方法)

最後のステップは、複数のクエリのチームを分析することです

要求する

注文IDに従って注文情報を照会し、注文詳細リストを照会します。

まず、OrderModelコードを次のように変更します。

package com.zhonghu.chat07.demo3.model;
import lombok.*;
import java.util.List;
@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class OrderModel {
    private Integer id;
    private Integer userId;
    private Long createTime;
    private Long upTime;
    //订单详情列表
    private List<OrderDetailModel> orderDetailModelList;
}

コレクションorderDetailModelListがOrderModelに追加され、注文の詳細のリストが保存されます。

方法1

OrderMapper.xml
<resultMap id="orderModelMap1" type="com.zhonghu.chat07.demo3.model.OrderModel">
    <id column="id" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <collection property="orderDetailModelList" ofType="com.zhonghu.chat07.demo3.model.OrderDetailModel">
        <id column="orderDetailId" property="id"/>
        <result column="order_id" property="orderId"/>
        <result column="goods_id" property="goodsId"/>
        <result column="num" property="num"/>
        <result column="total_price" property="totalPrice"/>
    </collection>
</resultMap>
<select id="getById1" resultMap="orderModelMap1">
    <![CDATA[
    SELECT
        a.id ,
        a.user_id,
        a.create_time,
        a.up_time,
        b.id orderDetailId,
        b.order_id,
        b.goods_id,
        b.num,
        b.total_price
    FROM
        orders a,
        order_detail b
    WHERE
        a.id = b.order_id
        AND a.id = #{value}
    ]]>
</select>

上記のgetById1のSQLに注意してください。このSQLはt_orderおよびt_order_detail接続クエリを使用します。このクエリは複数の結果を返しますが、最終結果はorderModelMap1に従ってマッピングされ、最後に1つのOrderModelオブジェクトのみが返されます。キーはにあります。コレクション要素、この要素コレクション内の要素のマッピング関係を定義するために使用され、注意する必要がある2つの属性があります。

  • プロパティ:対応するプロパティ名
  • ofType:コレクション内の要素のタイプ。これがOrderDetailModelです。

原則はこれです、あることに注意してください

<id column="id" property="id"/>

クエリ結果は、この構成で指定された列に従ってグループ化されます。つまり、注文IDに従ってグループ化されます。各注文は、複数の注文の詳細に対応します。注文の詳細は、ofType要素で指定されたオブジェクトにマッピングされます。コレクションの構成。

実際のresultMap要素のid要素はresult要素に置き換えることができますが、idはパフォーマンスを向上させることができます。Mybatisはid要素によって構成された列の値によって唯一のレコードを判断できます。result要素を使用する場合、同じレコードかどうかを判断する場合は、すべての列で判断する必要があるため、idでパフォーマンスを向上させ、id要素で1対多のパフォーマンスを向上させることができます。idの場合もパフォーマンスは同じです。要素または結果要素は、単一のテーブルクエリで使用されます。

マッパーインターフェース
OrderModel getById1(Integer id);
テストケース
com.zhonghu.chat07.demo3.Demo3Test#getById1
@Before
public void before() throws IOException {
    //指定mybatis全局配置文件
    String resource = "demo3/mybatis-config.xml";
    //读取全局配置文件
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //构建SqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    this.sqlSessionFactory = sqlSessionFactory;
}
@Test
public void getById1() {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        Integer id = 1;
        OrderModel orderModel = mapper.getById1(id);
        log.info("{}", orderModel);
    }
}
出力を実行
03:52.092 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time, b.id orderDetailId, b.order_id, b.goods_id, b.num, b.total_price FROM orders a, order_detail b WHERE a.id = b.order_id AND a.id = ? 
03:52.124 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==> Parameters: 1(Integer)
03:52.148 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - <==      Total: 2
03:52.148 [main] INFO  c.j.chat05.demo3.Demo3Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573, orderDetailModelList=[OrderDetailModel(id=1, orderId=1, goodsId=1, num=2, totalPrice=16.00), OrderDetailModel(id=2, orderId=1, goodsId=1, num=1, totalPrice=16.00)])

最後の出力は期待される結果と一致していることに注意してください。

方法2

2つのクエリを介して、結果がサブパッケージ化されます。最初に注文IDを使用して注文情報をクエリし、次に注文IDを使用して注文詳細リストをクエリし、次に結果をカプセル化します。このプレイはmybatisでデフォルトでサポートされており、コレクション要素を介して実現されます。

OrderDetailMapper.xml
<select id="getListByOrderId1" resultType="com.zhonghu.chat07.demo3.model.OrderDetailModel" parameterType="int">
    <![CDATA[
    SELECT
        a.id,
        a.order_id AS orderId,
        a.goods_id AS goodsId,
        a.num,
        a.total_price AS totalPrice
    FROM
        order_detail a
    WHERE
        a.order_id = #{value}
    ]]>
</select>
OrderMapper.xml
<resultMap id="orderModelMap2" type="com.zhonghu.chat07.demo3.model.OrderModel">
    <id column="id" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <collection property="orderDetailModelList" select="com.zhonghu.chat07.demo3.mapper.OrderDetailMapper.getListByOrderId1" column="id"/>
</resultMap>
<select id="getById2" resultMap="orderModelMap2">
    <![CDATA[
    SELECT
        a.id ,
        a.user_id,
        a.create_time,
        a.up_time
    FROM
        orders a
    WHERE
        a.id = #{value}
    ]]>
</select>

焦点は次の構成にあります。

<collection property="orderDetailModelList" select="com.zhonghu.chat07.demo3.mapper.OrderDetailMapper.getListByOrderId1" column="id"/>

orderDetailModelList属性の値が、select属性で指定されたクエリを通じて取得されることを示します。

com.zhonghu.chat07.demo3.mapper.OrderDetailMapper.getListByOrderId1

クエリパラメータはcolumn属性で指定されます。ここでは、getById2 sqlのIDが条件、つまり注文IDとして使用されます。

マッパーインターフェース
OrderModel getById2(int id);
テストケース
com.zhonghu.chat07.demo3.Demo3Test#getById2
@Test
public void getById2() {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        OrderModel orderModel = mapper.getById2(1);
        log.info("{}", orderModel);
    }
}
出力を実行
10:07.087 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time FROM ordera a WHERE a.id = ? 
10:07.117 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==> Parameters: 1(Integer)
10:07.135 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ====>  Preparing: SELECT a.id, a.order_id AS orderId, a.goods_id AS goodsId, a.num, a.total_price AS totalPrice FROM order_detail a WHERE a.order_id = ? 
10:07.136 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ====> Parameters: 1(Integer)
10:07.141 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - <====      Total: 2
10:07.142 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - <==      Total: 1
10:07.142 [main] INFO  c.j.chat05.demo3.Demo3Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573, orderDetailModelList=[OrderDetailModel(id=1, orderId=1, goodsId=1, num=2, totalPrice=16.00), OrderDetailModel(id=2, orderId=1, goodsId=1, num=1, totalPrice=16.00)])

出力には2つのクエリがあります。最初に注文IDを使用して注文情報をクエリし、次に注文IDを使用して注文の詳細をクエリします。結果はmybatisによって内部的にアセンブルされます。

総括する

  1. mybatisグローバル構成ファイルで、mapUnderscoreToCamelCaseは、自動マッピングのためにsqlのフィールドとjavabeanのラクダ命名のフィールドを開くことができます。
  2. resultMap要素の一般的な使用法を習得する
  3. 1対1の関連付けクエリはresultMap-> association要素を使用します(2つの方法)
  4. resultMap-> collection要素を使用した1対多のクエリ(2つの方法)
  5. resultMapで使用されるid要素は、複雑な関連クエリの効率を向上させることができます。これを使用して、レコードの一意性を判断できます。これがない場合は、すべての結果関連列を渡して、記録。

提案する

Mybatisは強力な関連付けクエリを提供しますが、できるだけ使用しないことをお勧めします。プログラム内の複数のクエリで単一のテーブルクエリを使用し、結果を自分でアセンブルすることをお勧めします。

モデル内の単一テーブルフィールドに関連付けられた一部の属性のみを定義し、他のオブジェクトへの参照と混合しないことをお勧めします。

やっと

  • 読んでやりがいを感じたら、気をつけたいと思います。ちなみに、いいねを言ってください。これが私のアップデートの最大のモチベーションになります。ご支援ありがとうございます。
  • Javaとコンピュータの基本的な知識に焦点を当てた私の公開アカウント[JavaFox]に注目してください。私を信じていない場合は、私を叩いてください。
  • ワンクリックのトリプル接続を探します:いいね、転送、視聴。
  • 読んだ後に異なる意見や提案がある場合は、コメントして私たちと共有してください。皆様のご支援、ご愛顧を賜りますようお願い申し上げます。

-私は竹湖です。あなたと同じくらいプログラミングが大好きです。

最新ニュースについては、パブリックアカウント「JavaFox」をフォローすることを歓迎します

おすすめ

転載: blog.csdn.net/issunmingzhi/article/details/113831504