1、动态sql
(1)动态sql是通过表达式来进行判断,对sql进行灵活的拼接、组装!
如;
<select id="findById" resultType="cn.melo.bean.User">
sql语句
<if test="条件">sql语句</if>
<if test="条件">sql语句</if>
</select>
(2)sql片段:就是将动态sql代码块抽取出来,组成一个sql片段,在statement中就可以引用sql片段,方便开发:
如:
<mapper namespace="cn.melo.mapper.UserMapper">
<sql id="sql片段的唯一标识">
sql语句
<if test="条件">sql语句</if>
</sql>
<select id="findById" resultType="cn.melo.bean.User">
select * from user
<!-- 如果引用的片段不在本配置文件中,那么refid的值就是namespace值.sql片段id值 -->
<include refid="sql片段的id值"></include>
</select>
</mapper>
(3)常用的动态sql:
A、if:表示如果,放在标签中可以让where自动忽略sql语句where后的第一个and!
如:
映射配置文件:
<select id="findUser" resultType="cn.melo.bean.User">
select * from user
<where>
<if test="username != null">and username = #{username}</if>
<if test="username == null">and username = 'wade'</if>
</where>
</select>
接口:
public User findUser(User user);
测试代码1:
User user = userMapper.findUser(new User(1, "Anthony", null));
System.out.println(user);
测试结果1:
测试代码2:
User user = userMapper.findUser(new User(1, null, null));
System.out.println(user);
测试结果2:
B、choose, when, otherwise: choose 元素,它有点像 Java 中的 switch 语句
如:
映射配置文件:
<select id="findUser" resultType="cn.melo.bean.User">
select * from user
<where>
<choose>
<when test="username != null">and id=#{id}</when>
<otherwise>and id = 3</otherwise>
</choose>
</where>
</select>
接口:
public User findUser(User user);
测试代码1:
User user = userMapper.findUser(new User(1, "Anthony", null));
System.out.println(user);
测试结果1:
测试代码2:
User user = userMapper.findUser(new User(1, null, null));
System.out.println(user);
测试结果2:
C、trim, set:
trim语法:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。
类似的用于动态更新语句的解决方案叫做 set。set 元素可以用于动态包含需要更新的列,而舍去其它的。
set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。
如:
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
C、foreach:
元素是一个循环语句,它的作用是遍历集合,它能够很好地支持数组和List、Set接口的集合,对此提供遍历功能。它往往用于SQL中的in关键字。
如:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。
2、一对一查询
如一夫对应一妻:
需求:根据丈夫的id查出丈夫的信息以及妻子的信息
husband表:
wife表:
实体类:
Husband.java:
package cn.melo.bean;
import java.io.Serializable;
public class Husband implements Serializable {
private Integer hid;
private String hname;
private Integer hage;
private Wife wife;
public Integer getHid() {
return hid;
}
public void setHid(Integer hid) {
this.hid = hid;
}
public String getHname() {
return hname;
}
public void setHname(String hname) {
this.hname = hname;
}
public Integer getHage() {
return hage;
}
public void setHage(Integer hage) {
this.hage = hage;
}
public Wife getWife() {
return wife;
}
public void setWife(Wife wife) {
this.wife = wife;
}
@Override
public String toString() {
return "Husband{" +
"hid=" + hid +
", hname='" + hname + '\'' +
", hage=" + hage +
", wife=" + wife +
'}';
}
}
Wife.java
package cn.melo.bean;
import java.io.Serializable;
public class Wife implements Serializable {
private Integer wid;
private String wname;
private Integer wage;
public Integer getWid() {
return wid;
}
public void setWid(Integer wid) {
this.wid = wid;
}
public String getWname() {
return wname;
}
public void setWname(String wname){
this.wname = wname;
}
public Integer getWage() {
return wage;
}
public void setWage(Integer wage) {
this.wage = wage;
}
@Override
public String toString() {
return "Wife{" +
"wid=" + wid +
", wname='" + wname + '\'' +
", wage=" + wage +
'}';
}
}
在映射配置文件中写sql语句和定义结果集:
<?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="cn.melo.mapper.HusbandMapper">
<!--id是唯一标识,type是查询的结果类型!-->
<resultMap id="husbandAndWife" type="cn.melo.bean.Husband">
<!--property是bean的属性名,column是属性名对应的字段名-->
<!--id是表的主键,唯一的字段-->
<id property="hid" column="hid"/>
<!--result是表的普通字段-->
<result property="hname" column="hname"/>
<result property="hage" column="hage"/>
<!--association是一对一对应的bean属性-->
<association property="wife" javaType="cn.melo.bean.Wife">
<id property="wid" column="wid"/>
<result property="wname" column="wname"/>
<result property="wage" column="wage"/>
</association>
</resultMap>
<select id="findByHusbandId" resultMap="husbandAndWife">
select h.*,w.* from husband h,wife w where h.wid=w.wid and h.hid=#{id}
</select>
</mapper>
测试代码:
//得到代理对象
HusbandMapper husbandMapper = session.getMapper(HusbandMapper.class);
//调用方法
Husband husband = husbandMapper.findByHusbandId(1);
System.out.println(husband);
结果:
3、一对多查询
如一个老师对应多个学生:
需求:根据老师的id查出老师的信息以及所有该老师的学生的信息
teacher表:
stu表:
实体类:
Teacher.java
package cn.melo.bean;
import java.util.List;
public class Teacher {
private Integer tid;
private String tname;
private Integer tage;
List<Stu> stus;
public Integer getTid() {
return tid;
}
public void setTid(Integer tid) {
this.tid = tid;
}
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
public Integer getTage() {
return tage;
}
public void setTage(Integer tage) {
this.tage = tage;
}
public List<Stu> getStus() {
return stus;
}
public void setStus(List<Stu> stus) {
this.stus = stus;
}
@Override
public String toString() {
return "Teacher{" +
"tid=" + tid +
", tname='" + tname + '\'' +
", tage=" + tage +
", stus=" + stus +
'}';
}
}
Stu.java
package cn.melo.bean;
public class Stu {
private Integer sid;
private String sname;
private Integer sage;
private Integer tid;
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Integer getSage() {
return sage;
}
public void setSage(Integer sage) {
this.sage = sage;
}
public Integer getTid() {
return tid;
}
public void setTid(Integer tid) {
this.tid = tid;
}
@Override
public String toString() {
return "Stu{" +
"sid=" + sid +
", sname='" + sname + '\'' +
", sage=" + sage +
", tid=" + tid +
'}';
}
}
映射配置文件(TeacherMapper.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="cn.melo.mapper.TeacherMapper">
<!--id是唯一标识,type是查询的结果类型!-->
<resultMap id="teacherAndStudents" type="cn.melo.bean.Teacher">
<!--property是bean的属性名,column是属性名对应的字段名-->
<!--id是表的主键,唯一的字段-->
<id property="tid" column="tid"/>
<!--result是表的普通字段-->
<result property="tname" column="tname"/>
<result property="tage" column="tage"/>
<!--collection是一对多对应的bean属性-->
<collection property="stus" ofType="cn.melo.bean.Stu">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<result property="sage" column="sage"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
<select id="findByTeacherId" resultMap="teacherAndStudents">
SELECT t.*,s.* FROM teacher t,stu s WHERE t.tid=s.tid AND t.tid = #{id}
</select>
</mapper>
接口:略
测试代码:
//得到代理对象
TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
//调用方法
Teacher teacher = teacherMapper.findByTeacherId(1);
System.out.println(teacher);
结果:
Teacher{tid=1, tname='Kerr', tage=50, stus=[Stu{sid=1, sname='Curry', sage=14, tid=1}, Stu{sid=2, sname='Green', sage=12, tid=1}]}
3、多对多查询
如订单和商品,一个订单可以对应多个商品,一个商品也可以对应多个订单,多对多其实就是一对多的一种特殊体现,只是它需要通过中间表来完成关联!
需求:查询某个订单下的所有商品
表orders:
表product:
中间表orders_product:
实体类:
Orders.java
package cn.melo.bean;
import java.util.List;
public class Orders {
private Integer oid;
private String oname;
private Double oprice;
private List<Orders_Product> orders_products;
public Integer getOid() {
return oid;
}
public void setOid(Integer oid) {
this.oid = oid;
}
public String getOname() {
return oname;
}
public void setOname(String oname) {
this.oname = oname;
}
public Double getOprice() {
return oprice;
}
public void setOprice(Double oprice) {
this.oprice = oprice;
}
public List<Orders_Product> getOrders_products() {
return orders_products;
}
public void setOrders_products(List<Orders_Product> orders_products) {
this.orders_products = orders_products;
}
@Override
public String toString() {
return "Orders{" +
"oid=" + oid +
", oname='" + oname + '\'' +
", oprice=" + oprice +
", orders_products=" + orders_products +
'}';
}
}
Product.java
package cn.melo.bean;
public class Product {
private Integer prid;
private String prname;
private Double prprice;
public Integer getPrid() {
return prid;
}
public void setPrid(Integer prid) {
this.prid = prid;
}
public String getPrname() {
return prname;
}
public void setPrname(String prname) {
this.prname = prname;
}
public Double getPrprice() {
return prprice;
}
public void setPrprice(Double prprice) {
this.prprice = prprice;
}
@Override
public String toString() {
return "Product{" +
"prid=" + prid +
", prname='" + prname + '\'' +
", prprice=" + prprice +
'}';
}
}
Orders_Product.java
package cn.melo.bean;
import java.util.List;
public class Orders_Product {
private Integer oid;
private Integer prid;
private List<Product> products;
public Integer getOid() {
return oid;
}
public void setOid(Integer oid) {
this.oid = oid;
}
public Integer getPrid() {
return prid;
}
public void setPrid(Integer prid) {
this.prid = prid;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
@Override
public String toString() {
return "Orders_Product{" +
"oid=" + oid +
", prid=" + prid +
", products=" + products +
'}';
}
}
映射文件(OrdersMapper.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="cn.melo.mapper.OrdersMapper">
<!--id是唯一标识,type是查询的结果类型!-->
<resultMap id="ordersAndProducts" type="cn.melo.bean.Orders">
<!--property是bean的属性名,column是属性名对应的字段名-->
<!--id是表的主键,唯一的字段-->
<id property="oid" column="oid"/>
<!--result是表的普通字段-->
<result property="oname" column="oname"/>
<result property="oprice" column="oprice"/>
<collection property="orders_products" ofType="cn.melo.bean.Orders_Product">
<result property="oid" column="oid"></result>
<result property="prid" column="prid"></result>
<collection property="products" ofType="cn.melo.bean.Product">
<id property="prid" column="prid"/>
<result property="prname" column="prname"/>
<result property="prprice" column="prprice"/>
</collection>
</collection>
</resultMap>
<select id="findByOrdersId" resultMap="ordersAndProducts">
SELECT o.*,pr.* FROM product pr,orders o,orders_product op
WHERE op.`oid`=o.`oid` AND pr.`prid`=op.`prid` AND o.oid=1
</select>
</mapper>
接口:略
测试代码:
//得到代理对象
OrdersMapper ordersMapper = session.getMapper(OrdersMapper.class);
//调用方法
Orders orders = ordersMapper.findByOrdersId(1);
System.out.println("订单信息:编号:"+orders.getOid()+",订单名:"+orders.getOname()
+",订单总价:"+orders.getOprice());
System.out.println("该订单下的信息:");
for (Orders_Product op : orders.getOrders_products()) {
for (Product pro : op.getProducts()) {
System.out.println("商品id:"+pro.getPrid()+",商品名称:"+pro.getPrname()
+",商品价格:"+pro.getPrprice());
}
}
结果: