MyBatis 动态SQL

本文详细介绍了MyBatis的动态SQL,包括输入映射和输出映射的配置,如parameterType和resultType的使用,以及resultMap在字段名与属性不一致时的映射。在动态SQL部分,讲解了If、Where、Sql片段和Foreach标签的运用。此外,还讨论了一对一和一对多关联查询的实现,结合resultType和resultMap来处理关联数据。

MyBatis 动态SQL

1.输入映射和输出映射

Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是MyBatis的核心。

a)输入参数映射

parameterType(输入类型)
1.传递简单类型

使用#{}占位符,或者${}进行sql拼接

2.传递pojo对象

MyBatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。

3.传递pojo包装对象

开发中通过使用pojo传递查询条件

查询条件可能是综合的查询条件,不仅包括用户查询条件还包括其他查询条件,这是就需要使用包装对象传递输入参数。

包装对象:pojo类中的一个属性是另外一个pojo。

QueryVo.java

package com.nikehu.mybatis.pojo;

/**
 * 包装的pojo
 * @author 猪猪
 *
 */
public class QueryVo {
	private User user;

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}
}

UserMapper.xml

	<!-- 包装的pojo -->
	<insert id="insertQueryVo" parameterType="QueryVo">
		INSERT INTO `mybatis01`.`user` (
		  `username`,
		  `birthday`,
		  `sex`,
		  `address`
		) 
		VALUES
		  (
		    #{ user.username },
		    #{ user.birthday },
		    #{ user.sex },
		    #{ user.address }
		  ) ;	
	</insert>

b)返回值映射

resultType(输出类型)
1.输出简单类型
	<!-- 查询用户总记录数 -->
	<select id="getUserCount" resultType="int">
		SELECT COUNT(1) FROM `user`;
	</select>
2.输出pojo类型
3.输出pojo列表
resultMap

resultType可以指定成功查询结果映射为pojo,但需要pojo属性名和sql查询的列名一致方可映射成功。

如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名做一个对应关系,resultMap实质上还需要将查询结果映射到pojo对象中。

resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询

如果sql查询字段名和pojo的属性名不一致:

解决方案1:取别名

	<select id="getOrderList" resultType="order">
		SELECT 
		  `id`,
		  `user_id` `userId`,
		  `number`,
		  `createtime`,
		  `note` 
		FROM
		  `order`
	</select>

解决方案2:resultMap解决字段名与属性不一致的问题

	<!-- 定义resultMap -->
	<resultMap type="order" id="order_list_map">
		<!-- <id/>用于映射主键 -->
		<id property="id" column="id"/>
		<!-- <result/> 用于映射其他字段 -->
		<result property="userId" column="user_id"/>
		<result property="number" column="number"/>
		<result property="createtime" column="createtime"/>
		<result property="note" column="note"/>
	</resultMap>
	<!-- 使用resultMap -->
	<select id="getOrderListMap" resultMap="order_list_map">
		SELECT 
		  `id`,
		  `user_id`,
		  `number`,
		  `createtime`,
		  `note` 
		FROM
		  `order`
	</select>

当pojo中部分属性名和数据库表中字段名一致时,可以不用配置,但是type属性必须写对,大小写不区分

2.动态SQL

a)If标签

	<!-- if标签 -->
	<select id="getUserByPojo" parameterType="user" resultType="user">
		SELECT 
		  `id`,
		  `username`,
		  `birthday`,
		  `sex`,
		  `address` 
		FROM
		  `mybatis01`.`user` 
		<!-- WHERE username LIKE #{name} -->
		WHERE 1=1
		<if test="username != null and username != ''">
			and username LIKE '%${username}%'
		</if>
		<if test="sex != null and sex != ''">
			and sex = #{sex}
		</if>
		
	</select>
	@Test
	public void testGetUserByPojo(){
		SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);
		User u = new User();
		u.setUsername("小");
		u.setSex("1");
		List<User> users = mapper.getUserByPojo(u);
		for (User user : users) {
			System.out.println(user);
		}
		sqlSession.close();
	}

b)Where标签

	<!-- where标签 -->
	<select id="getUserByPojo" parameterType="user" resultType="user">
		SELECT 
		  `id`,
		  `username`,
		  `birthday`,
		  `sex`,
		  `address` 
		FROM
		  `mybatis01`.`user` 
		<!-- WHERE username LIKE #{name} -->
        <!-- where标签 自动补上where关键字,同时处理多余的and关键字 -->
		<where>
			<if test="username != null and username != ''">
				and username LIKE '%${username}%'
			</if>
			<if test="sex != null and sex != ''">
				and sex = #{sex}
			</if>
		</where>
		
	</select>

使用where标签,就不能再手动的加上where关键字。

c)Sql片段

sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql复用的目的

	<!-- 使用sql标签将重复的sql片段抽取出来 -->
	<sql id="user_sql"> 
		  `id`,
		  `username`,
		  `birthday`,
		  `sex`,
		  `address` 
	</sql>
	<select id="getUserById" parameterType="int" resultType="user">
		SELECT 
		  <include refid="user_sql"></include>
		FROM
		  `mybatis01`.`user` 
		WHERE id = #{id}
	</select>
	<select id="getUserByPojo" parameterType="user" resultType="user">
		SELECT
			<!-- 使用include标签引入sql片段 --> 
		  <include refid="user_sql"></include>
		FROM
		  `mybatis01`.`user` 
		<!-- WHERE username LIKE #{name} -->
		<where>
			<if test="username != null and username != ''">
				and username LIKE '%${username}%'
			</if>
			<if test="sex != null and sex != ''">
				and sex = #{sex}
			</if>
		</where>
		
	</select>

d)Foreach标签

场景1:Sql 中in关键字的使用

	<select id="getUsersByIds" parameterType="QueryVo" resultType="user">
		SELECT 
		  <include refid="user_sql"/>
		  `uuid2` 
		FROM
		  `user`
		<where>
			<!-- foreach循环标签的使用 
				id  IN(1,25,29,30,40)
				collection:要遍历的集合;
				open:循环开始时加上的片段;
				close:循环结束时加上的片段;
				seseparator:每一次循环的分隔符;
				item:每一次循环的元素变量。
			-->
			<foreach collection="ids" open="id  IN(" item="uid" separator="," close=")">
				#{uid}
			</foreach>
		</where> 	
	</select>
package com.nikehu.mybatis.pojo;

import java.util.List;

/**
 * 包装的pojo
 * @author 猪猪
 *
 */
public class QueryVo {
	private User user;
	private List<Integer> ids;
	
	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public List<Integer> getIds() {
		return ids;
	}

	public void setIds(List<Integer> ids) {
		this.ids = ids;
	}
}
	@Test
	public void testGetUsersByIds(){
		SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);
		QueryVo vo = new QueryVo();
		ArrayList<Integer> ids = new ArrayList<Integer>();
		ids.add(1);
		ids.add(2);
		ids.add(29);
		ids.add(30);
		ids.add(40);
		vo.setIds(ids);
		List<User> users = mapper.getUsersByIds(vo);
		for (User user : users) {
			System.out.println(user);
		}	
	}

简写:构建ids列表

vo.setIds(Arrays.asList(1,25,29,30,40));

3.关联查询

a)一对一关联

一个订单只能有一个用户

一个用户可以有多个用户

使用resultType

关联查询使用resultType必须要有与数据库关系一致的pojo

OrderMapper.xml

	<!-- 一对一关联查询使用resultType
		查询订单关联用户 
	-->
	<select id="getOrderUser" resultType="OrderUser">
		SELECT 
		  o.`id`,
		  o.`user_id` userId,
		  o.`number`,
		  o.`createtime`,
		  o.`note`,
		  u.`username`,
		  u.`address`
		FROM
		  `order` o
		LEFT JOIN `user` u ON u.`id` = o.`user_id`	
	</select>

OrderUser.java

package com.nikehu.mybatis.pojo;

/**
 * 订单关联用户信息的pojo
 * @author 猪猪
 *
 */
public class OrderUser extends Order {
	private String username;
	private String address;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "OrderUser [username=" + username + ", address=" + address
				+ ", getId()=" + getId() + ", getUserId()=" + getUserId()
				+ ", getNumber()=" + getNumber() + ", getCreatetime()="
				+ getCreatetime() + ", getNote()=" + getNote() + "]";
	}
}
使用resultMap

在Order类里面封装一个User类对象,在使用resultMap查询(更符合面向对象的思想)

Order.java

package com.nikehu.mybatis.pojo;

/**
 * 订单关联用户信息的pojo
 * @author 猪猪
 *
 */
public class OrderUser extends Order {
	private String username;
	private String address;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "OrderUser [username=" + username + ", address=" + address
				+ ", getId()=" + getId() + ", getUserId()=" + getUserId()
				+ ", getNumber()=" + getNumber() + ", getCreatetime()="
				+ getCreatetime() + ", getNote()=" + getNote() + "]";
	}
}

OrderMapper.xml

	<!-- 一对一关联查询使用resultMap
		查询订单关联用户 
	-->
	<resultMap type="order" id="order_user_map">
		<!-- <id/>用于映射主键 -->
		<id property="id" column="id"/>
		<!-- <result/> 用于映射其他字段 -->
		<result property="userId" column="user_id"/>
		<result property="number" column="number"/>
		<result property="createtime" column="createtime"/>
		<result property="note" column="note"/>
		<!-- user属性的映射 -->
		<!-- association用于配置一对一关系;
			property:order里面的user属性
			javaType:指定property的Java类型,可以用别名
		 -->
		<association property="user" javaType="User">
			<id column="user_id" property="id"/>
			<result column="sex" property="sex"/>
			<result column="birthday" property="birthday"/>
			<result column="username" property="username"/>
			<result column="address" property="address"/>
		</association>
	</resultMap>
	<select id="getOrderUserList" resultMap="order_user_map">
		SELECT 
		  o.`id`,
		  o.`user_id`,
		  o.`number`,
		  o.`createtime`,
		  o.`note`,
		  u.`sex`,
		  u.`birthday`,
		  u.`username`,
		  u.`address`
		FROM
		  `order` o
		LEFT JOIN `user` u ON u.`id` = o.`user_id`	
	</select>

b)一对多关联

User.java

package com.nikehu.mybatis.pojo;

import java.util.Date;
import java.util.List;

public class User {

	private Integer id;
	private String username;// 用户姓名
	private String sex;// 性别
	private Date birthday;// 生日
	private String address;// 地址
	private String uuid2;
	private List<Order> orders;
	
	public List<Order> getOrders() {
		return orders;
	}

	public void setOrders(List<Order> orders) {
		this.orders = orders;
	}

	public String getUuid2() {
		return uuid2;
	}

	public void setUuid2(String uuid2) {
		this.uuid2 = uuid2;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", sex=" + sex
				+ ", birthday=" + birthday + ", address=" + address
				+ ", uuid2=" + uuid2 + "]";
	}
}
	<resultMap type="user" id="user_order_map">
		<id column="id" property="id"/>
		<result column="sex" property="sex"/>
		<result column="birthday" property="birthday"/>
		<result column="username" property="username"/>
		<result column="address" property="address"/>
		<result column="uuid2" property="uuid2"/>
		<!-- collection用于配置一对多关联
			property:User中的订单列表orders属性;
			ofType:property值的Java类型,支持别名
		 -->
		<collection property="orders" ofType="Order">
			<id property="id" column="oid"/>
			<!-- <result/> 用于映射其他字段 -->
			<result property="userId" column="id"/>
			<result property="number" column="number"/>
			<result property="createtime" column="createtime"/>
			<result property="note" column="note"/>
		</collection>
	</resultMap>
	<select id="getUserOrderMap" resultMap="user_order_map">
		SELECT 
		  u.`id`,
		  u.`username`,
		  u.`birthday`,
		  u.`sex`,
		  u.`address`,
		  u.`uuid2`,
		  o.`id` oid, 
		  o.`number`,
		  o.`createtime`,
		  o.`note`
		FROM
		  `user` u
		LEFT JOIN `order` o
		ON o.`user_id` = u.`id`
	
	</select>
	@Test
	public void testGetUserOrderMap() {
		SqlSession sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);
		List<User> users = mapper.getUserOrderMap();
		for (User user : users) {
			System.out.println(users);
			System.out.println("该用户的订单有:");
			for (Order order : user.getOrders()) {
				System.out.println(order);
			}
		}
		sqlSession.close();
	}

多对多可拆分成两个一对多查询

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值