mybatis实战教程之四:实现关联数据的查询

合集下载

mybatis主从表关联查询,返回对象带有集合属性解析

mybatis主从表关联查询,返回对象带有集合属性解析

mybatis主从表关联查询,返回对象带有集合属性解析⽬录主从表关联查询,返回对象带有集合属性VersionResult为接收返回数据对象UpdateRecordEntity为从表数据mapper.xml写法,这个是关键sql查询语句执⾏sql返回的数据页⾯调取接⼝mybatis关联查询(对象嵌套对象)⼀种是⽤关联另⼀个resultMap的形式⼀种联合查询(⼀对⼀)的实现主从表关联查询,返回对象带有集合属性昨天有同事让我帮着看⼀个问题,mybatis主从表联合查询,返回的对象封装集合属性。

我先将出现的问题记录⼀下,然后再讲处理⽅法也简单说明⼀下:VersionResult为接收返回数据对象get\set⽅法我这⾥就省略了。

public class VersionResult extends BaseResult implements Serializable{private Integer id;private String code;@JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")private Date createTimes;//记录内容表的集合对象private List<UpdateRecordEntity> UpdateRecordEntityList;}UpdateRecordEntity为从表数据同样get\set⽅法我这⾥就省略了。

@Table(name = "z_update_record")public class UpdateRecordEntity extends BaseEntity {@Idprivate Integer id;@Column(name = "version_id")private Integer versionId;@Column(name = "module_name")private String moduleName;@Column(name = "update_content")private String updateContent;@JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone = "GMT+8")@Column(name = "create_time")private Date createTime;@Column(name = "is_delete")private Integer isDelete;}mapper.xml写法,这个是关键<!--跟新记录表封装的对象--><resultMap id="BaseResultMap" type="com.wangtiansoft.wisdomedu.persistence.result.server.VersionResult"><id column="id" property="id" jdbcType="INTEGER"/><result column="code" property="code" /><result column="create_time" property="createTimes" /><collection property="UpdateRecordEntityList" ofType="com.wangtiansoft.wisdomedu.persistence.entity.UpdateRecordEntity"><id property="id" column="id"/><result property="versionId" column="version_id"/><result property="moduleName" column="module_name"/><result property="updateContent" column="update_content"/><result property="createTime" column="create_time"/><result property="isDelete" column="is_delete"/><result property="tenantId" column="tenant_id"/></collection></resultMap>sql查询语句<select id="selectVersionList" parameterType="map" resultMap="BaseResultMap">SELECTz.`code`,z.create_time createTimes,zur.module_name moduleName,zur.update_content updateContent,zur.create_time createTimeFROMz_version zLEFT JOIN z_update_record zur ON z.id = zur.version_idWHEREz.tenant_id = #{tenantId}AND z.is_delete = 0AND z.is_disabled = 0AND zur.tenant_id = #{tenantId}AND zur.is_delete = 0AND YEAR(z.create_time)=YEAR(#{date})ORDER by z.create_time desc</select>执⾏sql返回的数据页⾯调取接⼝下⾯我将接⼝数据粘贴下来:{"code": "0","msg": "","data": [{"id": null,"code": "1419","createTimes": null,"updateRecordEntityList": []}, {"id": null,"code": "开发修改1111","createTimes": null,"updateRecordEntityList": []}, {"id": null,"code": "开发修改1111","createTimes": null,"updateRecordEntityList": []}, {"id": null,"code": "开发修改1111","createTimes": null,"updateRecordEntityList": []}, {"id": null,"code": "开发修改1111","createTimes": null,"updateRecordEntityList": []}]}观察code、createTimes、updateRecordEntityList三个属性,会发现只有code字段有值其余的全部为null。

关于QueryWrapper,实现MybatisPlus多表关联查询方式

关于QueryWrapper,实现MybatisPlus多表关联查询方式

关于QueryWrapper,实现MybatisPlus多表关联查询⽅式⽬录QueryWrapper实现MybatisPlus多表关联查询1.dao层接⼝使⽤Select注解写SQL2.service层代码⽰例3.反射⼯具类4.判空⼯具类MybatisPlusQueryWrapper简单⽤法QueryWrapper实现MybatisPlus多表关联查询1.dao层接⼝使⽤Select注解写SQL重点:@Param("ew") Wrapper参数是必须,因为${ew.customSqlSegment} 底层其实就是where 条件,所以为了保证Wrapper不为空,service层代码中的Wrapper⾄少需要有⼀个条件:1 = 1@Override@Select("select a.code as code , as name , b.barcode as barcode , a.ware_code as wareCode , as wareName , a.qty as qty , a.oprice as oprice , a.total as total , " + " a.id as id , a.create_by as createBy , a.create_date as createDate , a.update_by as updateBy , a.update_date as updateDate , a.status as status , a.remarks as remarks " + "from sku_stock a , goods b , warehouse c " +"${ew.customSqlSegment} and a.code = b.code and a.ware_code = c.code")IPage<SkuStock> selectPage(IPage<SkuStock> page, @Param("ew")Wrapper<SkuStock> queryWrapper);2.service层代码⽰例service⽗类封装的findPage⽅法:/*** 封装findPage* @param entity* @param search Map中的key:";"为保留关键字,拆分数组,仅⽀持最⼤长度2的数组,* 下标0:QueryWrapper查询条件中的列名(⽀持多表关联查询的表别名 + 列名⽅式,需要dao层接⼝⽀持)* 下标1: QueryWrapper中不同的查询条件,eq:等于,ge:⼤于等..... todo:请⾃⾏完善Mybatis eq、ne、gt、lt、ge、le等* Map中的value:QueryWrapper需要查询的值* @param args QueryWrapper中order by 排序数组* @return*/public IPage<T> findPage(T entity , Map<String , Object> search , String... args){long current = 1L;long size = 10L;if (EmptyUtil.isNoEmpty(ReflexUtil.getFieldValue(entity , "page")) && (long) ReflexUtil.getFieldValue(entity , "page") != 0){current = (long) ReflexUtil.getFieldValue(entity , "page");}if (EmptyUtil.isNoEmpty(ReflexUtil.getFieldValue(entity , "limit")) && (long) ReflexUtil.getFieldValue(entity , "limit") != 0){size = (long) ReflexUtil.getFieldValue(entity , "limit");}QueryWrapper<T> queryWrapper;if (EmptyUtil.isNoEmpty(search)){queryWrapper = new QueryWrapper<>();for (Map.Entry<String , Object> entry:search.entrySet()) {String[] key = entry.getKey().split(";");if (key.length > 1){if (key[1].equals("eq")){queryWrapper.eq(key[0] , entry.getValue());}else if (key[1].equals("ge")){queryWrapper.ge(key[0] , entry.getValue());}else if (key[1].equals("lt")){queryWrapper.lt(key[0] , entry.getValue());}}else {queryWrapper.like(entry.getKey() , entry.getValue());}}}else {queryWrapper = new QueryWrapper<>(entity);}queryWrapper.orderByAsc(args);return super.page(new Page<T>(current , size) , queryWrapper);}service实现类⽅法:public IPage<SkuStock> findPage(SkuStock entity, String... args) {Map<String , Object> search = null;search = new HashedMap();search.put("1;eq" , "1");if (EmptyUtil.isNoEmpty(entity.getCode())|| EmptyUtil.isNoEmpty(entity.getWareCode())){if (EmptyUtil.isNoEmpty(entity.getCode())){search.put("code" , entity.getCode());if (EmptyUtil.isNoEmpty(entity.getWareCode())){search.put("ware_code" , entity.getWareCode());}}else {long limit = entity.getLimit();long page = entity.getPage();entity = new SkuStock();entity.setLimit(limit);entity.setPage(page);}return super.findPage(entity , search , args);}3.反射⼯具类package m.utils;import ng.reflect.Field;import ng.reflect.Method;import java.util.ArrayList;import java.util.Arrays;import java.util.List;/*** @ClassName ReflexUtil* @Description TODO* @Author foxsand* @Data 2021-06-09 15:17* @Version*/public class ReflexUtil {/*** 返回 entity 对象的所有属性,包含⽗类* @param obj* @return*/public static List<Field> getObjectFields(Object obj){Class clazz = obj.getClass();List<Field> fieldList = new ArrayList<>() ;while (clazz != null) {//当⽗类为null的时候说明到达了最上层的⽗类(Object类).fieldList.addAll(Arrays.asList(clazz .getDeclaredFields()));clazz = clazz.getSuperclass(); //得到⽗类,然后赋给⾃⼰}return fieldList;}public static List<Field> getObjectFields(Class<?> clazz){List<Field> fieldList = new ArrayList<>() ;while (clazz != null){fieldList.addAll(Arrays.asList(clazz .getDeclaredFields()));clazz = clazz.getSuperclass(); //得到⽗类,然后赋给⾃⼰}return fieldList;}/*** 判断 Class entity 是否存在名称为 fieldName 的属性* @param fieldName* @param entity* @return*/public static Boolean isField(String fieldName , Object entity){List<Field> fieldList = getObjectFields(entity);for (Field f1:fieldList) {if (fieldName.equals(f1.getName()))return true;}return false;}/*** 返回 entity 对象中的所有⽅法,包含⽗类* @param entity* @return*/public static List<Method> getObjectMethods(Object entity){Class<?> clazz = entity.getClass();List<Method> methods = new ArrayList<>();while (clazz != null && clazz != Object.class) {//当⽗类为null的时候说明到达了最上层的⽗类(Object类). methods.addAll(Arrays.asList(clazz .getDeclaredMethods()));clazz = clazz.getSuperclass(); //得到⽗类,然后赋给⾃⼰}return methods;}public static List<Method> getObjectMethods(Class<?> clazz){List<Method> methods = new ArrayList<>();while (clazz != null && clazz != Object.class) {//当⽗类为null的时候说明到达了最上层的⽗类(Object类). methods.addAll(Arrays.asList(clazz .getDeclaredMethods()));clazz = clazz.getSuperclass(); //得到⽗类,然后赋给⾃⼰return methods;}/*** 判断 Class entity 是否存在名称为 methodName 的⽅法* @param methodName* @param entity* @return*/public static Boolean isMethod(String methodName , Object entity){List<Method> methods = getObjectMethods(entity);for (Method m1:methods) {if (methodName.equals(m1.getName()))return true;}return false;}/*** 循环向上转型, 获取对象的 DeclaredMethod* @param obj* @param methodName* @param parameterTypes ⽅法参数类型* @return*/public static Method getDeclaredMethod(Object obj , String methodName , Class<?>...parameterTypes) {for (Class<?> clazz = obj.getClass(); clazz != Object.class && clazz != null; clazz = clazz.getSuperclass()) { try {return clazz.getDeclaredMethod(methodName, parameterTypes);} catch (Exception e) {// 这⾥甚么都不要做!并且这⾥的异常必须这样写,不能抛出去。

MyBatis关联查询,一对一关联查询

MyBatis关联查询,一对一关联查询

MyBatis关联查询,⼀对⼀关联查询数据库E-R关系实体类public class City {Long id;String name;Long countryId;Date lastUpdate;}public class Country {Long id;String name;Date lastUpdate;}public class CityPlus {Long id;String name;Long countryId;Date lastUpdate;Country country;}public class CountryPlus {Long id;String name;Date lastUpdate;List<City> cityList;}⼀对⼀关联查询 ⼀对⼀关联查询可采⽤的⽅式有:1. 单步查询,通过级联属性赋值result标签级联属性赋值association标签级联属性赋值2. 分步查询单步查询数据模型:⼀个实体Bean中包含另外⼀个实体BeanSQL查询:关联SQL 查询语句,如inner join、left join、right join具体实现⽅式:为级联属性赋值association标签采⽤相同的select标签<select id="selectCityPlusById" resultMap="cityPlusResultMap">select city_id,city,city.country_id as country_id,st_update as last_update,country.country_id as country_country_id,country,st_update as country_last_updatefrom city,countrywhere city.country_id = country.country_id and city_id=#{id}</select>result标签级联属性赋值<id column="city_id" property="id"/><result column="city" property="name"/><result column="country_id" property="countryId"/><result column="last_update" property="lastUpdate"/><result column="country_country_id" property="country.id"/><result column="country" property=""/><result column="country_last_update" property="stUpdate"/></resultMap>association标签级联属性赋值需要指定级联实体Bean在上级Bean中的属性名称,即association标签的property属性;需要指定级联实体Bean的类型,即association标签的javaType属性;association标签的内部和resultMap标签内部具有相同的结构;association标签也可以嵌套association标签;<resultMap id="cityPlusResultMap" type="canger.study.chapter04.bean.CityPlus"><id column="city_id" property="id"/><result column="city" property="name"/><result column="country_id" property="countryId"/><result column="last_update" property="lastUpdate"/><association property="country" javaType="canger.study.chapter04.bean.Country"><id column="country_country_id" property="id"/><result column="country" property="name"/><result column="country_last_update" property="lastUpdate"/></association></resultMap>分步查询 分步查询是指通过两次(或更多次)的查询,来为⼀个⼀对⼀关系的实体Bean赋值。

mybatis关联表查询

mybatis关联表查询

7 public class Teacher {
2、Classes 类,Classes 类是 class 表对应的实体类
1 package me.gacl.domain; 2 3 /** 4 5 * @author gacl * 定义 class 表对应的实体类 2 / 13
6 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
47 }
1.4、定义 sql 映射文件 classMapper.xml
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN" "/dtd/mybatis-3-mapper.dtd"> 3 <!-- 为这个 mapper 指定一个唯一的 namespace,namespace 的值习惯上设置成包名+sql 映射文件名,这样就能够 保证 namespace 的值是唯一的 4 例如 namespace="me.gacl.mapping.classMapper"就是 me.gacl.mapping(包名)+classMapper(classMapper.xml 文件去除后缀) 5 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 --> <select id="getClass" parameterType="int" resultMap="ClassResultMap"> select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=#{id} </select> <!-- 使用 resultMap 映射实体类和字段之间的一一对应关系 --> <resultMap type="me.gacl.domain.Classes" id="ClassResultMap"> <id property="id" column="c_id"/> <result property="name" column="c_name"/> <association property="teacher" javaType="me.gacl.domain.Teacher"> <id property="id" column="t_id"/> <result property="name" column="t_name"/> </association> 4 / 13 <!-方式一:嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集 封装联表查询的数据(去除重复的数据) select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=1 ##2. 执行两次查询 SELECT * FROM class WHERE c_id=1; //teacher_id=1 SELECT * FROM teacher WHERE t_id=1;//使用上面得到的 teacher_id --> <!-根据班级 id 查询班级信息(带老师的信息) ##1. 联表查询 SELECT * FROM class c,teacher t WHERE c.teacher_id=t.t_id AND c.c_id=1; --> 6 <mapper namespace="me.gacl.mapping.classMapper">

MyBatis级联查询

MyBatis级联查询

第1章关联关系查询1.1关联查询当查询内容涉及到具有关联关系的多个表时,就需要使用关联查询。

根据表与表间的关联关系的不同,关联查询分为四种:(1)一对一关联查询(2)一对多关联查询(3)多对一关联查询(4)多对多关联查询由于日常工作中最常见的关联关系是一对多、多对一与多对多,所以这里就不专门只讲解一对一关联查询了,其解决方案与多对一解决方案是相同的。

1.1.1一对多关联查询项目:one2many,在项目dynamicMapper基础上进行修改。

这里的一对多关联查询是指,在查询一方对象的时候,同时将其所关联的多方对象也都查询出来。

下面以国家Country与部长Minister间的一对多关系进行演示。

(1)定义实体在定义实体时,若定义的是双向关联,即双方的属性中均有对方对象作为域属性出现,那么它们在定义各自的toString()方法时需要注意,只让某一方可以输出另一方即可,不要让双方的toString()方法均可输出对方。

这样会形成递归调用,程序出错。

(2)定义数据库表(3)定义Dao层接口A、多表连接查询方式注意,此时即使字段名与属性名相同,在<resultMap/>中也要写出它们的映射关系。

因为框架是依据这人<resultMap/>封装对象的。

另外,在映射文件中使用<collection/>标签体现出两个实体对象间的关联关系。

其两个属性的意义为:➢property:指定关联属性,即Country类中的集合属性➢ofType:集合属性的泛型类型B、多表单独查询方式项目:one2many-2,在项目one2many基础上进行修改。

多表连接查询方式是将多张表进行连接,连为一张表后进行查询。

其查询的本质是一张表。

而多表单独查询方式是多张表各自查询各自的相关内容,需要多张表的联合数据了,则将主表的查询结果联合其它表的查询结果,封装为一个对象。

当然,这多个查询是可以跨越多个映射文件的,即是可以跨越多个namespace的。

mybatis实现关联数据的查询

mybatis实现关联数据的查询

mybatis实现关联数据的查询mybatis实战教程(mybatis in action)之四:实现关联数据的查询有了前面几章的基础,对一些简单的应用是可以处理的,但在实际项目中,经常是关联表的查询,比如最常见到的多对一,一对多等。

这些查询是如何处理的呢,这一讲就讲这个问题。

我们首先创建一个Article 这个表,并初始化数据. 程序代码Drop TABLE IF EXISTS `article`;Create TABLE`article` ( `id` int(11) NOT NULL auto_increment,`userid` int(11) NOT NULL, `title` varchar(100) NOT NULL, `content` text NOT NULL, PRIMARY KEY(`id`)) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ------------------------------ 添加几条测试数据-- ----------------------------Insert INTO `article` VALUES ('1', '1', 'test_title', 'test_content');Insert INTO `article` VALUES ('2', '1', 'test_title_2', 'test_content_2');Insert INTO `article` VALUES ('3', '1', 'test_title_3', 'test_content_3');Insert INTO `article` VALUES ('4', '1', 'test_title_4', 'test_content_4');你应该发现了,这几个文章对应的userid都是1,所以需要用户表user里面有id=1的数据。

mybatis两张表关联查询

mybatis两张表关联查询

iBatis/MyBatis 主子表关联查询主表:MASTER字段:ORDER_ID--主键RELATE_ID --申请单位STOCK_ADDRESS --仓库地址TERMINAL_VENDER --供应商PROVINCE_ID --省分IDSTATE --状态子表:DETAIL字段:ORDER_ID--与主表ORDER_ID关联PROPERTY_CODE --属性编码SALE_PRICE --价格TERMINAL_VENDER --供应商与主表TERMINAL_VENDER关联PROVINCE_ID --省分ID 与主表PROVINCE_ID关联主键为ORDER_ID + PROPERTY_CODE要求,取得主表:MASTER 中STATE为1的记录,并映射成易于操作的java对象。

并关联子表,ORDER_ID、TERMINAL_VENDER、PROVINCE_ID作为查询子表的条件。

将查询出的子表数据映射成List<Object> ,作为主表映射成对象的一个成员变量。

以便后续操作。

定义java对象Master,对应主表数据:1package com.test.ibatis.po;23import java.util.List;45/**6 * 主表对应数据7 */8public class Master implements java.io.Serializable {9private static final long serialVersionUID = 1L;10/** ID */11private String channelsId = null;12/** 地址 */13private String deliveryLoc = null;1415/** 对应子表数据 */16private List<Detail> details = null;1718public String getChannelsId() {19return channelsId;20 }2122public void setChannelsId(String channelsId) { 23this.channelsId = channelsId;24 }2526public String getDeliveryLoc() {27if (deliveryLoc == null)28return "";29return deliveryLoc;30 }3132public void setDeliveryLoc(String deliveryLoc) { 33this.deliveryLoc = deliveryLoc;34 }3536public List<Detail> getDetails() {37return details;38 }3940public void setDetails(List<Detail> details) {41this.details = details;42 }43}定义Detail类,对应子表数据:1package com.test.ibatis.po;23import java.text.DecimalFormat;45public class Detail implements java.io.Serializable {6private static final long serialVersionUID = 1L;78private static final DecimalFormat df = new DecimalFormat("### 0.00");9/** 产品编号 */10private String partNo = null;11/** 价格 */12private String price = null;1314public String getPartNo() {15return partNo;16 }1718public void setPartNo(String partNo) {19this.partNo = partNo;20 }2122public String getPrice() {23if (price == null)24return "0";25return df.format(Double.parseDouble(price) / 1000.0);26 }2728public void setPrice(String price) {29this.price = price;30 }31}sql如下配置:1<?xml version="1.0" encoding="gbk" ?>23<!DOCTYPE sqlMap4 PUBLIC "-////DTD SQL Map 2.0//EN"5 "/dtd/sql-map-2.dtd">6<sqlMap namespace="TEST_SQL">7<typeAlias alias="HashMap" type="java.util.HashMap"/>89<!-- Master对象定义 -->10<resultMap id="master" class="com.test.ibatis.po.Master">11<result property="channelsId" column="ORDER_CHANNEL"/>12<result property="deliveryLoc" column="DELIVER_ADDRESS"/>13<result property="details" column="{province=PROVINCE_CODE,id=O RDER_ID,VENDER=TERMINAL_VENDER}"14 select="select-dtl"/>15</resultMap>16<!-- Detail对象定义 -->17<resultMap id="detail" class="com.linkage.ess.ordercreate.po.OrderDetail ">18<result property="partNo" column="PROPERTY_CODE"/>19<result property="price" column="SALE_PRICE"/>20</resultMap>21<select id="selectData" resultMap="master">22<!--[CDATA[23 SELECT T.RELATE_ID ORDER_CHANNEL,24 T.STOCK_ADDRESS DELIVER_ADDRESS25 FROM MASTER T26 WHERE T.PROVINCE_ID = #PROVINCE_ID#27 AND T.STATE = '1'28 ]]>29 </select>30 <statement id="select-dtl" resultMap="detail">31 <![CDATA[32 SELECT D.PROPERTY_CODE,33 D.SALE_PRICE,34 FROM DETAIL D35 WHERE D.ORDER_ID = #id#36 AND D.TERMINAL_VENDER = #VENDER#37 AND D.PROVINCE_ID = #province#38 ]]-->39</statement>40</sqlMap>这样所有的工作都OK,执行List<Master> masters = (List<Master>) sqlMap.queryForList("selectData", param);// param 为HashMap,put("PROVINCE_ID", "BJ"); 作为查询条件用。

mybatis关联查询(一对多和多对一)

mybatis关联查询(一对多和多对一)

mybatis关联查询(⼀对多和多对⼀)⽬录mybatis关联查询DBUtil mybatis⼯具类public class DBUtil {private static SqlSessionFactory factory = null;static {try {String mybatis_config = "mybatis-config.xml";InputStream in = Resources.getResourceAsStream(mybatis_config);factory = new SqlSessionFactoryBuilder().build(in);} catch (Exception e) {e.printStackTrace();}}// 获取SqlSessionpublic static SqlSession getSqlSession() {return factory.openSession(true);}// 获取mapperpublic static <T> T getMapper(Class<T> mapper) {return getSqlSession().getMapper(mapper);}}mybatis⼀对多查询resultMap格式:cloumn属性可以是表字段名或者别名<resultMap id="唯⼀的标识" type="映射的pojo对象"><id column="表的主键字段" jdbcType="字段类型" property="映射pojo对象的主键属性" /><result column="表字段名或者别名" jdbcType="字段类型" property="映射到pojo对象的⼀个属性"/> <!--多个标签<result>...--><collection property="pojo的集合属性名" ofType="集合中的pojo对象"><id column="主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" /><result column="表字段名或者别名" jdbcType="字段类型" property="集合中的pojo对象的属性" /> <!--多个标签<result>...--></collection></resultMap>案例⼀个⽼师对应多个学⽣, 查询⽼师的时候把⽼师学⽣类:@Data@AllArgsConstructor@NoArgsConstructorpublic class Student {private Integer id;private String name;}⽼师类:@Data@AllArgsConstructor@NoArgsConstructorpublic class Teacher {private Integer id;private String name;List<Student> students;}⽼师dao接⼝public interface TeacherMapper {List<Teacher> findAllTeacher();}⽅试⼀: 案结果嵌套处理(联表查询)TeacherMapper.xml<select id="findAllTeacher" resultMap="teacherStudent">selectt.id as t_id, as t_name,s.id as s_id, as s_namefrom teacher tleft join student s ons.t_id = t.id</select><resultMap id="teacherStudent" type="teacher"><id column="t_id" property="id"/><result column="t_name" property="name"/><collection property="students" ofType="student"><id column="s_id" property="id"/><result column="s_name" property="name"/></collection></resultMap>⽅式⼆: 按查询嵌套处理TeacherMapper.xml<select id="findAllTeacher" resultMap="teacherStudent">select * from teacher;</select><select id="findStudentById" resultType="student">select * from student where t_id = #{id};</select><resultMap id="teacherStudent" type="teacher"><id column="id" property="id"/><result column="name" property="name"/><collection property="students" javaType="ArrayList" ofType="student" select="findStudentById" column="id"/> </resultMap>⽅式⼀⽅式⼆测试均如下:@Testpublic void test1() {TeacherMapper mapper1 = DBUtil.getMapper(TeacherMapper.class);List<Teacher> teachers = mapper1.findAllTeacher();for (Teacher teacher : teachers) {System.out.println(teacher.getName());for (Student student : teacher.getStudents()) {System.out.println("\t" + student);}}}结果:张⽼师Student(id=1, name=张三)Student(id=2, name=李四)Student(id=3, name=王五)Student(id=4, name=赵六)王⽼师Student(id=5, name=李七)Student(id=6, name=冯⼋)mybatis多对⼀查询resultMap格式:<resultMap id="唯⼀的标识" type="映射的pojo对象"><id column="表的主键字段" jdbcType="字段类型" property="映射pojo对象的主键属性" /><result column="表字段名或者别名" jdbcType="字段类型" property="映射到pojo对象的⼀个属性"/> <!--多个标签<result>...--><association property="pojo的集合属性名" javaType="饮⽤配型"><id column="主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" /><result column="表字段名或者别名" jdbcType="字段类型" property="集合中的pojo对象的属性" /> <!--多个标签<result>...--></association></resultMap>案例查询学⽣, 并查询学⽣的⽼师学⽣类:@Data@AllArgsConstructor@NoArgsConstructorpublic class Student {private Integer id;private String name;private Teacher teacher;}⽼师类:@Data@AllArgsConstructor@NoArgsConstructorpublic class Teacher {private Integer id;private String name;}学⽣dao层public interface StudentMapper {List<Student> findAllStudent();}⽅式⼀: 案结果嵌套处理(联表查询)StudentMapper.xml<select id="findAllStudent" resultMap="studentTeacher">selects.id as s_id, as s_name,t.id as t_id, as t_namefrom student s left join teacher t ons.t_id = t.id;</select><resultMap id="studentTeacher" type="student"><id column="s_id" property="id"/><result column="s_name" property="name"/><association property="teacher" javaType="teacher"><id column="t_id" property="id"/><result column="t_name" property="name"/></association></resultMap>⽅式⼆: 按查询结果嵌套StudentMapper.xml<select id="findAllStudent" resultMap="studentTeacher">select * from student;</select><select id="findTeacherById" resultType="teacher">select * from teacher where id = #{t_id};</select><resultMap id="studentTeacher" type="student"><id column="id" property="id"/><result column="name" property="name"/><association property="teacher" column="t_id" javaType="teacher" select="findTeacherById"/> </resultMap>⽅式⼀⽅式⼆测试均如下:@Testpublic void test1() {StudentMapper mapper = DBUtil.getMapper(StudentMapper.class);List<Student> students = mapper.findAllStudent();for (Student student : students) {System.out.println(student);}}结果:Student(id=1, name=张三, teacher=Teacher(id=1, name=张⽼师)) Student(id=2, name=李四, teacher=Teacher(id=1, name=张⽼师)) Student(id=3, name=王五, teacher=Teacher(id=1, name=张⽼师)) Student(id=4, name=赵六, teacher=Teacher(id=1, name=张⽼师)) Student(id=5, name=李七, teacher=Teacher(id=2, name=王⽼师)) Student(id=6, name=冯⼋, teacher=Teacher(id=2, name=王⽼师))。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

mybatis实战教程(mybatis in action)之四:实现关联数据的查询有了前面几章的基础,对一些简单的应用是可以处理的,但在实际项目中,经常是关联表的查询,比如最常见到的多对一,一对多等。

这些查询是如何处理的呢,这一讲就讲这个问题。

我们首先创建一个Article 这个表,并初始化数据.程序代码Drop TABLE IF EXISTS `article`;Create TABLE `article` (`id` int(11) NOT NULL auto_increment,`userid` int(11) NOT NULL,`title` varchar(100) NOT NULL,`content` text NOT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ------------------------------ 添加几条测试数据-- ----------------------------Insert INTO `article` VALUES ('1', '1', 'test_title', 'test_content');Insert INTO `article` VALUES ('2', '1', 'test_title_2', 'test_content_2');Insert INTO `article` VALUES ('3', '1', 'test_title_3', 'test_content_3');Insert INTO `article` VALUES ('4', '1', 'test_title_4', 'test_content_4');你应该发现了,这几个文章对应的userid都是1,所以需要用户表user里面有id=1的数据。

可以修改成满足自己条件的数据.按照orm的规则,表已经创建了,那么肯定需要一个对象与之对应,所以我们增加一个Article 的class程序代码package com.yihaomen.mybatis.model;public class Article {private int id;private User user;private String title;private String content;public int getId() {return id;}public void setId(int id) {this.id = id;}public User getUser() {return user;}public void setUser(User user) {er = user;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) { this.content = content;}}注意一下,文章的用户是怎么定义的,是直接定义的一个User对象。

而不是int类型。

多对一的实现场景:在读取某个用户发表的所有文章。

当然还是需要在User.xml 里面配置select 语句, 但重点是这个select 的resultMap 对应什么样的数据呢。

这是重点,这里要引入association 看定义如下:程序代码< !-- User 联合文章进行查询方法之一的配置(多对一的方式) --><resultMap id="resultUserArticleList" type="Article"><id property="id" column="aid" /><result property="title" column="title" /><result property="content" column="content" /><association property="user" javaType="User"><id property="id" column="id" /><result property="userName" column="userName" /><result property="userAddress" column="userAddress" /> </association></resultMap>< select id="getUserArticles" parameterType="int" resultMap="resultUserArticleList"> select user.id,erName,erAddress,article.idaid,article.title,article.content from user,articlewhere user.id=erid and user.id=#{id}</select>这样配置之后,就可以了,将select 语句与resultMap 对应的映射结合起来看,就明白了。

用association 来得到关联的用户,这是多对一的情况,因为所有的文章都是同一个用户的。

还有另外一种处理方式,可以复用我们前面已经定义好的resultMap ,前面我们定义过一个resultListUser ,看这第二种方法如何实现:程序代码<resultMap type="User" id="resultListUser"><id column="id" property="id" /><result column="userName" property="userName" /><result column="userAge" property="userAge" /><result column="userAddress" property="userAddress" /></resultMap><!-- User 联合文章进行查询方法之二的配置(多对一的方式) --><resultMap id="resultUserArticleList-2" type="Article"><id property="id" column="aid" /><result property="title" column="title" /><result property="content" column="content" /><association property="user" javaType="User" resultMap="resultListUser"/></resultMap><select id="getUserArticles" parameterType="int"resultMap="resultUserArticleList">select user.id,erName,erAddress,article.id aid,article.title,article.content from user,articlewhere user.id=erid and user.id=#{id}</select>将association 中对应的映射独立抽取出来,可以达到复用的目的。

好了,现在在Test 类中写测试代码:程序代码public void getUserArticles(int userid){SqlSession session = sqlSessionFactory.openSession();try {IUserOperationuserOperation=session.getMapper(IUserOperation.class);List<Article> articles = userOperation.getUserArticles(userid);for(Article article:articles){System.out.println(article.getTitle()+":"+article.getContent()+":作者是:"+article.getUser().getUserName()+":地址:"+article.getUser().getUserAddress());}} finally {session.close();}}漏掉了一点,我们一定要在IUserOperation 接口中,加入select 对应的id 名称相同的方法:public List<Article> getUserArticles(int id);然后运行就可以测试。

相关文档
最新文档