MyBatis desde cero-MyBatis consulta avanzada

Directorio de blogs de la serie: directorio de blogs MyBatis desde cero

5. Consulta avanzada de MyBatis

En las bases de datos relacionales, a menudo tenemos que lidiar con relaciones de uno a uno y de uno a muchos. Por ejemplo: un estudiante solo puede estar en una clase y una clase puede tener muchos estudiantes.

preparación de datos

-- ----------------------------
-- Table structure for `t_class_info`
-- ----------------------------
DROP TABLE IF EXISTS `t_class_info`;
CREATE TABLE `t_class_info` (
  `class_id` int(11) NOT NULL AUTO_INCREMENT,
  `class_name` varchar(255) DEFAULT NULL COMMENT '班级名称',
  PRIMARY KEY (`class_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_class_info
-- ----------------------------
INSERT INTO `t_class_info` VALUES ('1', '一年级');
INSERT INTO `t_class_info` VALUES ('2', '二年级');
INSERT INTO `t_class_info` VALUES ('3', '三年级');
INSERT INTO `t_class_info` VALUES ('4', '四年级');

-- ----------------------------
-- Table structure for `t_student_info`
-- ----------------------------
DROP TABLE IF EXISTS `t_student_info`;
CREATE TABLE `t_student_info` (
  `student_id` int(11) NOT NULL AUTO_INCREMENT,
  `student_name` varchar(255) DEFAULT NULL,
  `class_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`student_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_student_info
-- ----------------------------
INSERT INTO `t_student_info` VALUES ('1', '张三', '1');
INSERT INTO `t_student_info` VALUES ('2', '李四', '2');
INSERT INTO `t_student_info` VALUES ('3', '路人甲', '3');
INSERT INTO `t_student_info` VALUES ('4', '路人乙', '1');

5.1 Mapeo uno a uno

Escenario: un alumno solo puede corresponder a una clase

5.1.1 Utilice el mapeo automático para manejar relaciones uno a uno

Clase de información del estudiante: StudentInfo.java

public class StudentInfo {
    
    
	private Integer studentId;
	private String studentName;
    /**
	 * 所在班级
	 */
	private ClassInfo classInfo;

	// 此处省略其它get、set方法
    // 此处省略无参的构造方法
	// 此处toString()方法
    
    public ClassInfo getClassInfo() {
    
    
		return classInfo;
	}

	public void setClassInfo(ClassInfo classInfo) {
    
    
		this.classInfo = classInfo;
	}
}

Clase de información de clase: ClassInfo.java

public class ClassInfo {
    
    
	private Integer classId;
	private String className;

	// 此处省略其它get、set方法
    // 此处省略无参的构造方法
	// 此处toString()方法
}

Clase de interfaz: StudentInfoMapper.java

import org.apache.ibatis.annotations.Param;
import com.xiangty.bean.StudentInfo;

public interface StudentInfoMapper {
    
    
	/**
	 * 根据学生id查询学生信息和班级信息
	 * @param studentId 学生id
	 * @return
	 */
	StudentInfo selectStudentAndClassById(@Param("studentId") Integer studentId);
}

StudentInfoMapper.xml

<select id="selectStudentAndClassById" resultType="com.xiangty.bean.StudentInfo">
    select s.student_id, 
            s.student_name, 
            s.class_id, 
            c.class_name 
    from t_student_info s 
    left join t_class_info c
    on c.class_id = s.class_id
    where s.student_id = #{studentId}
</select>

Clase de prueba unitaria StudentInfoTest.java

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import com.xiangty.bean.StudentInfo;
import com.xiangty.mapper.StudentInfoMapper;

public class StudentInfoTest {
    
    
	@Test
	public void testSelectStudentAndClassById(){
    
    
		SqlSession sqlSession = SqlSessionUtil.getSqlSession();
		try {
    
    
			StudentInfoMapper studentInfoMapper = sqlSession.getMapper(StudentInfoMapper.class);
			Integer studentId = 1;
			StudentInfo studentInfo = studentInfoMapper.selectStudentAndClassById(studentId);
			System.out.println(studentInfo);
		} finally {
    
    
			sqlSession.close();
		}
	}
}


输出结果:
DEBUG [main] - ==>  Preparing: select s.student_id, s.student_name, s.class_id, c.class_name from t_student_info s left join t_class_info c on c.class_id = s.class_id where s.student_id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
TRACE [main] - <==    Columns: student_id, student_name, class_id, class_name
TRACE [main] - <==        Row: 1, 张三, 1, 一年级
DEBUG [main] - <==      Total: 1
StudentInfo [studentId=1, studentName=张三, classInfo=null]

Nota: El objeto classInfo en la información de consulta anterior está vacío. Necesita realizar la siguiente transformación en el archivo Mapper.xml

StudentInfoMapper.xml

<!--  
		c.class_id列后面的"classInfo.classId",这种是复杂的属性映射,可以多层嵌套。
		MyBatis会先查找classInfo属性,如果存在这个属性就创建classInfo对象,然后继续查找classId属性,将c.class_id的值绑定到这个属性上面。
	-->
<select id="selectStudentAndClassById" resultType="com.xiangty.bean.StudentInfo">
    select s.student_id, 
    s.student_name, 
    c.class_id "classInfo.classId", 
    c.class_name "classInfo.className" 
    from t_student_info s 
    left join t_class_info c
    on c.class_id = s.class_id
    where s.student_id = #{studentId}
</select>

Clase de prueba unitaria StudentInfoTest.java

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import com.xiangty.bean.StudentInfo;
import com.xiangty.mapper.StudentInfoMapper;

public class StudentInfoTest {
    
    
	@Test
	public void testSelectStudentAndClassById(){
    
    
		SqlSession sqlSession = SqlSessionUtil.getSqlSession();
		try {
    
    
			StudentInfoMapper studentInfoMapper = sqlSession.getMapper(StudentInfoMapper.class);
			Integer studentId = 1;
			StudentInfo studentInfo = studentInfoMapper.selectStudentAndClassById(studentId);
			System.out.println(studentInfo);
		} finally {
    
    
			sqlSession.close();
		}
	}
}


输出结果:
DEBUG [main] - ==>  Preparing: select s.student_id, s.student_name, c.class_id "classInfo.classId", c.class_name "classInfo.className" from t_student_info s left join t_class_info c on c.class_id = s.class_id where s.student_id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
TRACE [main] - <==    Columns: student_id, student_name, classInfo.classId, classInfo.className
TRACE [main] - <==        Row: 1, 张三, 1, 一年级
DEBUG [main] - <==      Total: 1
StudentInfo [studentId=1, studentName=张三, classInfo=ClassInfo [classId=1, className=一年级]]
	通过控制台答应的日志看到查询出一条数据,MyBatis将这条数据映射到了班级和学生类中。这种通过一次查询将结果映射到不同对象的方式,称之为关联的嵌套结果映射。

El mapeo de resultados anidado asociado requiere la asociación de varias tablas y todos los valores requeridos se consultan a la vez. La ventaja de este método es reducir el número de consultas a la base de datos y reducir la presión sobre la base de datos La desventaja es escribir SQL complejo.

5.1.2 Utilice resultMap para configurar el mapeo uno a uno

Además de utilizar el mapeo automático de MyBatis para manejar el anidamiento uno a uno, también puede configurar el mapeo de resultados en el archivo de mapeo XML. La configuración usando resultMap también puede lograr el efecto en 5.1.1, el código es el siguiente:

StudentInfoMapper.xml

<!-- 
  association标签用于和一个负载的类型进行关联,即用于一对一的关联配置。
  学生和班级是一对一的,所以在学生的resultMap里面加上association标签配置的班级信息即可。
  property属性表示的是实体类中的属性名称;
  column属性表示的是对应的数据库中字段的名称。
  -->
<resultMap type="com.xiangty.bean.StudentInfo" id="studentMap">
    <id property="studentId" column="student_id"/>
    <result property="studentName" column="student_name"/>
    <association property="classInfo" javaType="com.xiangty.bean.ClassInfo">
        <result property="classId" column="class_id"/>
        <result property="className" column="class_name"/> 
    </association>
</resultMap>
<!-- 注意这个方法使用resultMap配置映射,所以放回值不能用resultType来设置,而是需要使用resultMap属性将其配置为上面的studentMap -->
<select id="selectStudentAndClassById2" resultMap="studentMap">
    select s.student_id, 
    s.student_name, 
    s.class_id, 
    c.class_name
    from t_student_info s 
    left join t_class_info c
    on c.class_id = s.class_id
    where s.student_id = #{studentId}
</select>

Clase de prueba unitaria StudentInfoTest.java

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import com.xiangty.bean.StudentInfo;
import com.xiangty.mapper.StudentInfoMapper;

public class StudentInfoTest {
    
    
	@Test
	public void testSelectStudentAndClassById2(){
    
    
		SqlSession sqlSession = SqlSessionUtil.getSqlSession();
		try {
    
    
			StudentInfoMapper studentInfoMapper = sqlSession.getMapper(StudentInfoMapper.class);
			Integer studentId = 1;
			StudentInfo studentInfo = studentInfoMapper.selectStudentAndClassById2(studentId);
			System.out.println(studentInfo);
		} finally {
    
    
			sqlSession.close();
		}
	}
}


输出结果:
DEBUG [main] - ==>  Preparing: select s.student_id, s.student_name, s.class_id, c.class_name from t_student_info s left join t_class_info c on c.class_id = s.class_id where s.student_id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
TRACE [main] - <==    Columns: student_id, student_name, class_id, class_name
TRACE [main] - <==        Row: 1, 张三, 1, 一年级
DEBUG [main] - <==      Total: 1
StudentInfo [studentId=1, studentName=张三, classInfo=ClassInfo [classId=1, className=一年级]]

5.2 Mapeo de uno a muchos

La colección de etiquetas del mapeo de relaciones de uno a muchos es similar a la asociación. El mapeo de resultados anidado combinado se refiere a consultar todos los resultados a través de una consulta SQL y luego mapear los datos a diferentes objetos a través del mapeo de resultados configurado.

Escenario uno a muchos, una clase contiene varios estudiantes:

ClassInfo.java agrega studentInfoList

package com.xiangty.bean;
import java.util.List;
/**
 * 班级信息
 * @author xiangty
 */
public class ClassInfo {
    
    
	private Integer classId;
	private String className;
	
	// 学生集合
	List<StudentInfo> studentInfoList;
	
	// 此处省略其它get、set方法
    // 此处省略无参的构造方法
	// 此处toString()方法
}

ClassInfoMapper.java

package com.xiangty.mapper;

import org.apache.ibatis.annotations.Param;

import com.xiangty.bean.ClassInfo;
public interface ClassInfoMapper {
    
    
	
	/**
	 * 根据班级id查询班级和学生信息
	 * @param classId 班级id
	 * @return
	 */
	ClassInfo selectClassInfoAndStudentById(@Param("classId") Integer classId);
	 
}

ClassInfoMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiangty.mapper.ClassInfoMapper">
	<!-- 
		collection标签用于和一个负载的类型进行关联,即用于一对多的关联配置。
		班级和学生是一对多的,所以在班级的resultMap里面加上collection标签配置的班级信息即可。
		property属性表示的是实体类中的属性名称;
		column属性表示的是对应的数据库中字段的名称。
	 -->
	<resultMap type="com.xiangty.bean.ClassInfo" id="classMap">
		<id property="classId" column="class_id"/>
		<result property="className" column="class_name"/>
		<collection property="studentInfoList" ofType="com.xiangty.bean.StudentInfo">
			<result property="studentId" column="student_id"/>
			<result property="studentName" column="student_name"/>
		</collection>
	</resultMap>
	<!-- 注意这个方法使用resultMap配置映射,所以放回值不能用resultType来设置,而是需要使用resultMap属性将其配置为上面的studentMap -->
	<select id="selectClassInfoAndStudentById" resultMap="classMap">
		select s.student_id, 
			 s.student_name, 
			 s.class_id, 
			 c.class_name
		from t_class_info c
		left join t_student_info s 
		on s.class_id = c.class_id 
		where c.class_id = #{classId}
	</select>
	
</mapper>

ClassInfoTest.java

package com.xiangty.test;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import com.xiangty.bean.ClassInfo;
import com.xiangty.mapper.ClassInfoMapper;

public class ClassInfoTest {
    
    
	
	@Test
	public void selectClassInfoAndStudentById(){
    
    
		SqlSession sqlSession = SqlSessionUtil.getSqlSession();
		try {
    
    
			ClassInfoMapper classInfoMapper = sqlSession.getMapper(ClassInfoMapper.class);
			Integer classId = 1;
			ClassInfo classInfo = classInfoMapper.selectClassInfoAndStudentById(classId);
			System.out.println(classInfo);
		} finally {
    
    
			sqlSession.close();
		}
	}
	
}


运行效果:
DEBUG [main] - ==>  Preparing: select s.student_id, s.student_name, s.class_id, c.class_name from t_class_info c left join t_student_info s on s.class_id = c.class_id where c.class_id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
TRACE [main] - <==    Columns: student_id, student_name, class_id, class_name
TRACE [main] - <==        Row: 1, 张三, 1, 一年级
TRACE [main] - <==        Row: 4, 路人乙, 1, 一年级
DEBUG [main] - <==      Total: 2
ClassInfo [classId=1, className=一年级, studentInfoList=[StudentInfo [studentId=1, studentName=张三, classInfo=null], StudentInfo [studentId=4, studentName=路人乙, classInfo=null]]]

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-zPA06dON-1614513937815) (C: \ Users \ xiangty \ Desktop \ s8.jpg )]

Si hay algún problema en el documento, puede contactarme directamente para que pueda corregirlo y avanzar. Espero que la documentación te sea de ayuda. Dirección de GitHub del código en el documento: https://gitee.com/xiangty1/learn-MyBatis/

Supongo que te gusta

Origin blog.csdn.net/qq_33369215/article/details/114239028
Recomendado
Clasificación