Mybatis第五篇:查询详解
分为单表查询、一对一关联查询、一对多查询。
一、单表查询
单表查询的字段映射方式有三种:一般使用别名和在xml文件中配置resultMap进行映射。还有一种是使用自动映射。需要在Mybatis的全局配置文件件中增加配置开启自动映射的配置。配置驼峰命名规则自动映射可能会导致一些bug,不建议使用。
<settings> <!-- 是否开启自动驼峰命名规则映射,及从xx_yy映射到xxYy --> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>
1、直接使用别名进行查询。
bean对象:
@Data @Builder public class TOrder implements Serializable { private Integer id; private Integer userId; private Long createTime; private Long upTime; private static final long serialVersionUID = 1L; }
sql语句:返回结果为resultType配置上具体的实体类。
<select id="selectById" parameterType="java.lang.Integer" resultType="entity.TOrder">
select
t.id, t.user_id userId, t.create_time createTime, t.up_time upTime
from t_order t
where id = #{id,jdbcType=INTEGER}
</select>
2、在xml文件中配置resultMap进行映射。
xml文件中配置resultMap标签:
<resultMap id="BaseResultMap" type="entity.TOrder"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="user_id" jdbcType="INTEGER" property="userId" /> <result column="create_time" jdbcType="BIGINT" property="createTime" /> <result column="up_time" jdbcType="BIGINT" property="upTime" /> </resultMap>
sql语句:返回结果为resultMap,配置上具体resultMap的Id值。
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from t_order where id = #{id,jdbcType=INTEGER} </select>
二、一对一关联查询(一对一关联查询存在4种方式)
实现目标:订单查询时,查出该订单相关的用户信息
更改TOrde 的实体类属性,增加Tuser属性。
@Data @Builder public class TOrder implements Serializable { private Integer id; private Integer userId; private Long createTime; private Long upTime; //用户信息() private TUser tUser;
private static final long serialVersionUID = 1L; }
TUser的实体类:
@Data @Builder public class TUser implements Serializable { private Integer id; private String name; private static final long serialVersionUID = 1L; }
xml文件配置:
1、resultMap直接配置级联实体类的字段:
<resultMap id="BaseResultMap2" type="entity.TOrder">
<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="tUser.id" />
<result column="name" property="tUser.name" />
</resultMap>
sql语句:
<select id="selectOrderAndUserInfoById" parameterType="java.lang.Integer" resultMap="BaseResultMap2">
select
t.id, t.user_id, t.create_time, t.up_time, u.name
from
t_order t, t_user u
where
t.user_id = u.id
and t.id = #{id,jdbcType=INTEGER}
</select>
test方法运行结果:
测试案例运行时要注意lombok的@Builder注解的使用,1.18.8版本的lombok在实体类上加上@Builder,会使得查询之后的结果解析错误。慎用lombok。
Cause: java.lang.IllegalArgumentException: argument type mismatch
实体类上去掉@Builder注解,正常解析查询结果:
2、resultMap增加association标签配置
resultMap结果集增加association标签配置
<resultMap id="BaseResultMap3" type="entity.TOrder"> <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="tUser" javaType="entity.TUser"> <id column="user_id" property="id"/> <result column="name" property="name"/> </association> </resultMap>
关键部分association内容配置,property:实体类的级联属性,javaType:属性的全类名称。
子标签,column:sql查询出来的字段名,property:级联类的属性。
<association property="tUser" javaType="entity.TUser"> <id column="user_id" property="id"/> <result column="name" property="name"/> </association>
sql语句:
<select id="selectOrderAndUserInfoById" parameterType="java.lang.Integer" resultMap="BaseResultMap3"> select t.id, t.user_id, t.create_time, t.up_time, u.name from t_order t, t_user u where t.user_id = u.id and t.id = #{id,jdbcType=INTEGER} </select>
test方法运行结果:
3、先按照订单id查询订单数据,然后在通过订单中user_id
去用户表查询用户数据,通过两次查询,组合成目标结果(单个参数传递)。
TUserDao的sql语句
<select id="selectById" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from t_user where id = #{id,jdbcType=INTEGER} </select>
resultMap结果集配置:select为二次查询的sql,colimn的值为传递到select赋予SQL的参数,是第一次查出出来的字段。property为TOrder中级联的属性。
<resultMap id="BaseResultMap4" type="entity.TOrder"> <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="tUser" select="dao.TUserDao.selectById" javaType="entity.TUser" column="user_id"/> </resultMap>
test方法
@Test public void test11(){ SqlSession sqlSession = sqlSessionFactory.openSession(true); TOrderDao orderDao = sqlSession.getMapper(TOrderDao.class); TOrder order = orderDao.selectById(2); log.info("数据库查询结果为:{}", order); sqlSession.close(); }
执行结果
4、二次查询多个参数传递。
TUserDao.xml文件下下创建一个接收多个参数的sql
<select id="selectById2" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from t_user where id = #{uid1} and id = #{uid2} </select>
TUserDao接口层方法:
TUser selectById2(@Param("uid1") Integer id, @Param("uid2")Integer id2);
TOrderDao.xml中增加resultMap的配置:同样是在association 标签里面配置,多个参数在colimn属性里面换成{},字段之间用逗号分隔。
<resultMap id="BaseResultMap5" type="entity.TOrder"> <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="tUser" select="dao.TUserDao.selectById2" javaType="entity.TUser" column="{uid1=user_id, uid2=user_id}"/> </resultMap>
TOrderDao中增加sql语句:
<select id="selectById2" parameterType="java.lang.Integer" resultMap="BaseResultMap5"> select t.id, t.user_id, t.create_time, t.up_time from t_order t where id = #{id,jdbcType=INTEGER} </select>
test方法运行结果:
三、一对多查询的多种方式(使用collection标签)
实体类代码:
public class TOrder implements Serializable { private static final long serialVersionUID = 6718825777769667204L; private Integer id; private Integer userId; private Long createTime; private Long upTime; //用户信息(一对一关联) // private UserModel userModel; private TUser tUser; // 订单详情信息 private List<TOrderDetail> orderDetailList; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public Long getCreateTime() { return createTime; } public void setCreateTime(Long createTime) { this.createTime = createTime; } public Long getUpTime() { return upTime; } public void setUpTime(Long upTime) { this.upTime = upTime; } public TUser gettUser() { return tUser; } public void settUser(TUser tUser) { this.tUser = tUser; } public List<TOrderDetail> getOrderDetailList() { return orderDetailList; } public void setOrderDetailList(List<TOrderDetail> orderDetailList) { this.orderDetailList = orderDetailList; } public TOrder() { } @Override public String toString() { return "TOrder{" + "id=" + id + ", userId=" + userId + ", createTime=" + createTime + ", upTime=" + upTime + ", tUser=" + tUser + ", orderDetailList=" + orderDetailList + '}'; } }
1、直接查询多条结果,使用collection标签根据关联id进行解析
xml文件的resultMap标签
<resultMap id="BaseResultMap6" type="entity.TOrder"> <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="tUser" javaType="entity.TUser"> <id column="user_id" property="id"/> <result column="name" property="name"/> </association> <collection property="orderDetailList" ofType="entity.TOrderDetail"> <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>
xml文件的sql语句,如果缺少标红的第二个user_id,mybatis进行结果集类型转换的时候会报错。增加了之后可以正常运行。
<select id="selectOrderAllInfoById" parameterType="java.lang.Integer" resultMap="BaseResultMap6"> select t.id, t.user_id, t.create_time, t.up_time, t.user_id, u.name, d.id AS orderDetailId, d.order_id, d.goods_id, d.num, d.total_price from t_order t, t_user u, t_order_detail d where t.user_id = u.id AND d.order_id = t.id and t.id = #{id,jdbcType=INTEGER} </select>
test方法执行结果:
2、多次查询获取结果集
xml文件的resultMap结果集更改:
<resultMap id="BaseResultMap7" type="entity.TOrder"> <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="tUser" javaType="entity.TUser" column="user_id" select="dao.TUserDao.selectById"/> <collection property="orderDetailList" ofType="entity.TOrderDetail" column="id" select="dao.TOrderDetailDao.selectByOrderid"/> </resultMap>
TOrderDao的sql:
<select id="selectOrderAllInfoById2" parameterType="java.lang.Integer" resultMap="BaseResultMap7"> select t.id, t.user_id, t.create_time, t.up_time from t_order t where t.id = #{id,jdbcType=INTEGER} </select>
TUserDao的sql:
<select id="selectById" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from t_user where id = #{id,jdbcType=INTEGER} </select>
TOrderDetailDao的sql:
<select id="selectByOrderid" parameterType="integer" resultMap="BaseResultMap"> SELECT id, order_id, goods_id, num, total_price from t_order_detail WHERE order_id = #{orderId,jdbcType=INTEGER} </select>
test方法运行结果: