(7) MyBatis desde la entrada hasta la consulta de suelo

Este es el séptimo capítulo de la serie mybatis. Si no ha leído las sugerencias anteriores, primero vaya a la cuenta pública [Java Tsukuba Fox] para ver el texto anterior, que es conveniente para comprender y comprender. En el artículo anterior, hablamos sobre algunos métodos para obtener claves primarias. En este artículo, presentaremos algunos métodos de consulta con más profundidad, especialmente la consulta de múltiples tablas.

Antes de comenzar, comience los preparativos, como crear una base de datos y una tabla.

Construye una base de datos y construye una tabla

Crear una base de datos: mybatisdemo

4 mesas:

  • usuario (tabla de usuarios)
  • bienes (lista de productos)
  • pedidos (tabla de pedidos)
  • order_detail (tabla de detalles del pedido)

La relación entre las tablas:

  • Existe una relación de uno a uno entre los pedidos y el usuario. Un pedido está asociado con un registro de usuario
  • Los pedidos y order_detail son una relación de uno a muchos, cada pedido puede contener varios subórdenes y cada suborden corresponde a un producto

La declaración de construcción de la tabla específica es la siguiente:

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;

Después de construir la base de datos y las tablas, comenzaremos nuestro viaje de consultas en el siguiente paso, comenzando con la consulta de tabla única más básica y luego introduciendo la consulta de tabla única, la consulta de uno a uno y la consulta de uno a muchos en vuelta.

Consulta de tabla única (3 formas)

La primera introducción es la consulta de tabla única.

demanda

La información del pedido debe consultarse de acuerdo con la identificación del pedido.

Camino 1

Crea un modelo correspondiente a cada tabla

Los campos de la tabla en db están separados por guiones bajos. En el modelo, usamos la nomenclatura camel para nombrar, como 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;
}

Varios otros modelos son similares.

Asignador 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>

Tenga en cuenta el resultType anterior, que identifica el tipo de resultado.

Método de interfaz del asignador
OrderModel getById(int id);
archivo de configuración global 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>
Caso de prueba
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);
    }
}
Ejecutar salida
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)
principio

En sql, usamos alias para convertir los campos en pedidos en los mismos nombres que los campos en OrderModel. Finalmente, mybatis reflejará internamente los resultados de la consulta para buscar campos con los mismos nombres en OrderModel de acuerdo con los nombres, y luego asignarlos.

Camino 2

Si todos los campos del modelo correspondientes a la tabla de nuestro proyecto utilizan el método de denominación de camellos, se pueden realizar algunas configuraciones en mybatis para mapear automáticamente los campos de la tabla con los campos correspondientes al método de denominación de camellos en el modelo.

Es necesario agregar la siguiente configuración al archivo de configuración global mybatis:

<settings>
    <!-- 是否开启自动驼峰命名规则映射,及从xx_yy映射到xxYy -->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
Asignador 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>

Tenga en cuenta que en el sql anterior, no escribimos alias. Dado que hemos habilitado el mapeo automático de nombres de camellos, los resultados de la consulta se mapearán automáticamente de acuerdo con la siguiente relación:

campo correspondiente de sql Campos en OrderModel
identificación identificación
user_id userId
create_time createTime
up_time upTime
Interfaz del mapeador
OrderModel getById1(int id);
Caso de prueba
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);
    }
}
Ejecutar salida
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)

Se puede ver en la salida que los campos en sql están subrayados y los campos en OrderModel tienen nombres de camello, y el resultado se ensambla automáticamente.Este es el efecto de activar mapUnderscoreToCamelCase.

Camino 3

Hay un elemento resultMap más poderoso en mapper xml, a través del cual se puede definir la relación de mapeo de los resultados de la consulta.

Asignador 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>

El resultMap anterior tiene 2 elementos que deben especificarse:

  • id: identificación de resultMap
  • tipo: Qué tipo encapsular el resultado, aquí necesitamos empaquetar el resultado como OrderModel

Tenga en cuenta que en el elemento de selección anterior, hay un resultMap que identifica qué resultMap se usa para mapear los resultados de la consulta. Aquí usamos orderModelMap2, por lo que los resultados de la consulta se mapearán de acuerdo con el resultMap asociado con orderModelMap2.

Interfaz del mapeador
OrderModel getById2(int id);
Caso de prueba
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);
    }
}

Ejecutar salida

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)

Consulta relacionada uno a uno (4 formas)

Después de hablar sobre la consulta de tabla única, comencemos con la consulta de tabla, la primera es la consulta uno a uno.

demanda

Al consultar un pedido por ID de pedido, también se devuelve la información del usuario asociada con el pedido.

Modifiquemos el código OrderModel y agreguemos un UserModel dentro, de la siguiente manera:

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;
}

Contenido de UserModel:

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

Camino 1

Asignador 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>

Preste atención a las dos líneas de arriba:

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

En este lugar, se usa la asignación en cascada, y. Se usa como referencia entre múltiples niveles. Aquí solo tenemos un nivel, y puede haber muchos niveles.

Interfaz del mapeador
OrderModel getById1(int id);
Caso de prueba
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);
    }
}
Ejecutar salida
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冢狐))

Camino 2

Esta vez necesitamos usar otra asociación de elementos en mapper xml, este elemento puede configurar la relación de mapeo de los objetos asociados, ver el ejemplo.

Asignador 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>

Tenga en cuenta la siguiente parte del código anterior:

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

Preste atención al atributo de propiedad anterior. Esto es para configurar la relación de mapeo entre el resultado de la consulta sql y el objeto OrderModel.userModel, y mapear el user_id al id en el userModel y el nombre al nombre en el userModel.

Interfaz del mapeador
OrderModel getById2(int id);
Caso de prueba
@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);
    }
}
resultado de la operación
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冢狐))

Se puede ver en la última línea del resultado que la asignación de valores de todos los campos está bien.

Camino 3

Primero consulta los datos del pedido de acuerdo con el ID del pedido y luego ve a la tabla de usuarios para consultar los datos del usuario a través del user_id en el pedido. Después de dos consultas, el resultado de destino se combina. Mybatis ha incorporado este tipo de operación, como sigue.

UserMapper.xml

Primero definimos un elemento de selección para consultar la información del usuario por identificación de usuario, de la siguiente manera

<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>

El valor del atributo OrderModel.userModel proviene de otra consulta, esta consulta es especificada por el atributo select del elemento de asociación, aquí está

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

Esta consulta es condicional y la condición se pasa a través de la columna de asociación, donde se pasa el campo user_id en el resultado de la consulta de getById3.

Interfaz del mapeador
OrderModel getById3(int id);
Caso de prueba
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);
    }
}
Ejecutar salida
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冢狐))

Se puede ver en la salida que hay 2 consultas, primero consulta el pedido de acuerdo con el ID del pedido, y luego ve a la tabla de usuarios para consultar la información del usuario a través del ID del usuario en el registro del pedido, y finalmente realiza 2 consultas.

Camino 4

En el Método 3, se pasa un parámetro a la segunda consulta. ¿Qué sucede si necesita pasar varios parámetros a la segunda consulta? Se puede escribir así

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

Esto equivale a pasar un mapa a la subconsulta. En la subconsulta, se debe usar la clave del mapa para obtener las condiciones correspondientes. Ver el caso:

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>

Interfaz del mapeador

OrderModel getById4(int id);

Caso de prueba

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);
    }
}

Ejecutar salida

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)

Observe las condiciones de la segunda consulta en la salida. Lo que se pasa es el user_id y create_time de la primera consulta.

Consulta de uno a varios (2 formas)

El último paso es analizar un equipo de múltiples consultas.

demanda

Consulte la información del pedido de acuerdo con el ID del pedido y consulte la lista de detalles del pedido.

Primero modifique el código OrderModel de la siguiente manera:

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;
}

Se agrega una colección orderDetailModelList a OrderModel para almacenar la lista de detalles del pedido.

Camino 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>

Preste atención al sql en getById1 anterior. Este sql utiliza consultas de conexión t_order y t_order_detail. Esta consulta devolverá varios resultados, pero el resultado final se asignará de acuerdo con orderModelMap1 y, finalmente, solo se devolverá un objeto OrderModel. La clave está en el elemento de la colección, este elemento Utilizado para definir la relación de mapeo de los elementos de la colección, hay dos atributos que deben tenerse en cuenta:

  • propiedad: el nombre de propiedad correspondiente
  • ofType: el tipo de elementos de la colección, aquí es OrderDetailModel

El principio es este, tenga en cuenta que hay un

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

Los resultados de la consulta se agruparán de acuerdo con la columna especificada en esta configuración, es decir, se agruparán de acuerdo con el ID del pedido. Cada pedido corresponde a varios detalles del pedido. Los detalles del pedido se asignarán al objeto especificado por el elemento ofType de acuerdo con el configuración de la colección.

El elemento id en el elemento resultMap real puede ser reemplazado por el elemento result, pero el id puede mejorar el rendimiento. Mybatis puede juzgar el único registro por el valor de la columna configurada por el elemento id. Si usamos el elemento result, entonces cuando a juzgar si es el mismo registro, debe ser juzgado por todas las columnas, por lo que el rendimiento se puede mejorar por id, y el elemento id puede mejorar el rendimiento en uno a varios. El rendimiento es el mismo si el id elemento o el elemento de resultado se utiliza en una consulta de tabla única.

Interfaz del mapeador
OrderModel getById1(Integer id);
Caso de prueba
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);
    }
}
Ejecutar salida
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)])

Tenga en cuenta que la última salida es coherente con el resultado esperado.

Camino 2

A través de 2 consultas, los resultados se sub-empaquetan, primero consulta la información de la orden a través de la identificación de la orden, luego consulta la lista de detalles de la orden a través de la identificación de la orden y luego encapsula los resultados. Este juego es compatible por defecto en mybatis, y se logra a través del elemento de colección.

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>

La atención se centra en la siguiente configuración:

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

Indica que el valor del atributo orderDetailModelList se obtiene a través de la consulta especificada por el atributo select, a saber:

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

Los parámetros de consulta se especifican mediante el atributo de columna. Aquí, el id en getById2 sql se utiliza como condición, es decir, el id del pedido.

Interfaz del mapeador
OrderModel getById2(int id);
Caso de prueba
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);
    }
}
Ejecutar salida
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)])

Hay 2 consultas en la salida. Primero consulta la información del pedido a través de la identificación de la orden y luego consulta los detalles de la orden a través de la identificación de la orden. Los resultados son ensamblados internamente por mybatis.

para resumir

  1. En el archivo de configuración global mybatis, mapUnderscoreToCamelCase puede abrir los campos en sql y los campos de nombres de camellos en javabean para el mapeo automático
  2. Domina el uso común del elemento resultMap
  3. La consulta de asociación uno a uno usa resultMap-> elemento de asociación (2 formas)
  4. Consulta de uno a muchos usando resultMap-> elemento de colección (2 formas)
  5. El elemento id que se usa en resultMap puede mejorar la eficiencia en consultas complejas relacionadas. Puede usarlo para determinar la unicidad del registro. Si no lo tiene, debe pasar todas las columnas relacionadas con los resultados para determinar la unicidad del registro.

Sugerir

Mybatis nos proporciona poderosas consultas de asociación, pero recomiendo usarlas lo menos posible. Es mejor usar una sola consulta de tabla, a través de múltiples consultas en el programa, y ​​luego ensamblar los resultados usted mismo.

Es mejor definir solo algunos atributos asociados con campos de una sola tabla en el modelo y no mezclarlos con referencias a otros objetos.

Por fin

  • Si sientes que eres recompensado después de leerlo, espero que le prestes atención. Por cierto, dame un pulgar hacia arriba. Esta será la mayor motivación para mi actualización. Gracias por tu apoyo.
  • Bienvenidos a todos para que presten atención a mi cuenta pública [Java Fox], enfocándome en los conocimientos básicos de Java y la computadora, prometo dejarles obtener algo después de leerlo, si no me creen, péguenme
  • Busque la conexión triple con un clic: me gusta, reenviar y mirar.
  • Si tiene diferentes opiniones o sugerencias después de leer, por favor comente y comparta con nosotros. Gracias por su apoyo y cariño.

——Soy Chuhu, y amo la programación tanto como a ti.

Bienvenido a seguir la cuenta pública "Java Fox" para conocer las últimas noticias.

Supongo que te gusta

Origin blog.csdn.net/issunmingzhi/article/details/113831504
Recomendado
Clasificación