1.4(Mybatis学习笔记)关联映射
一、一对一
mybatis处理一对一主要通过<resultMap>中的<association>元素来处理。
<association>元素主要使用方方式有两种:
<!--方式一 嵌套查询-->
<association property = "card" column = "card_id" javaType = "com.mybatis.associateMapping.IdCard"
select = "com.mybatis.mapper.IdCardMapper.findCodeById" />
<!--方式二 嵌套结果-->
<association property = "card" javaType = "com.mybatis.associateMapping.IdCard">
<id property = "id" column = "card_id"/>
<property = "code" column = "code"/>
</association>
首先我们构建两张表,表结构如下:
tb_idcard
tb_person
建表语句:
CREATE TABLE `tb_idcard` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(18) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
CREATE TABLE `tb_person` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`sex` varchar(8) DEFAULT NULL,
`card_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `card_id` (`card_id`),
CONSTRAINT `tb_person_ibfk_1` FOREIGN KEY (`card_id`) REFERENCES `tb_idcard` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
tb_person表中的card_id与tb_card的id关联起来。
现在通过id查询person信息,同时使用这个id查询对应card信息。
IdCard.java
public class IdCard {
private Integer id;
private String code;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return "IdCard [id=" + id + ", code=" + code + "]";
}
}
Person.java
public class Person {
private Integer id;
private String name;
private Integer age;
private String sex;
private IdCard card;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public IdCard getCard() {
return card;
}
public void setCard(IdCard card) {
this.card = card;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex + ", card=" + card + "]";
} }
IdCardMapper.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.mybatis.mapper.IdCardMapper" >
<select id = "findCodeById" parameterType = "Integer" resultType = "com.mybatis.associateMapping.IdCard">
select * from tb_idcard where id = #{id}
</select>
</mapper>
PersonMapper.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.mybatis.mapper.PersonMapper" >
<select id = "findPersonById" parameterType = "Integer" resultMap = "IdCardWithPersonResult">
select * from tb_person where id = #{id}
</select> <resultMap type="com.mybatis.associateMapping.Person" id = "IdCardWithPersonResult">
<id property="id" column="id" />
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<association property = "card" column = "card_id" javaType = "com.mybatis.associateMapping.IdCard"
select = "com.mybatis.mapper.IdCardMapper.findCodeById" />
</resultMap>
</mapper>
通过id查询的同时,resultMap中有一个嵌套查询会根据id查询idCard同时将查询的结果绑定到Person类的card属性上。 mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource = "db.properties">
</properties>
<!-- 采用扫描包定义别名 -->
<typeAliases>
<package name="com.mybatis.associateMapping"/>
</typeAliases> <!-- 配置默认环境为mysql -->
<environments default = "mysql">
<!-- 配置id为SQL的数据库环境 -->
<environment id = "my">
<!-- 设置事务管理类型为JDBC -->
<transactionManager type = "JDBC"/>
<!-- 设置数据源 -->
<dataSource type = "POOLED">
<property name = "driver" value = "${jdbc.driver}" />
<property name = "url" value = "${jdbc.url}" />
<property name = "username" value = "${jdbc.username}" />
<property name = "password" value = "${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 设置映射文件 -->
<mappers>
<!-- 测试mybatis -->
<mapper resource = "com/mybatis/mapper/CustomerMapper.xml"/>
<!-- mybatis关联映射 -->
<mapper resource = "com/mybatis/mapper/IdCardMapper.xml"/>
<mapper resource = "com/mybatis/mapper/PersonMapper.xml"/>
</mappers>
</configuration>
MyBatisSessionFactory.java (工具类,用于获取SqlSessionFactory)
import java.io.IOException;
import java.io.InputStream; import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MyBatisSessionFactory {
public static SqlSessionFactory getSqlSessionFactory(String sourceFile) throws IOException {
String resource = sourceFile;
//获取配置文件输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//通过配置文件输入流构建sqlSessionFactory,
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"my");
return sqlSessionFactory;
}
}
测试:
import java.io.IOException; import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory; import com.my.util.MyBatisSessionFactory; public class TestMapper {
public static void main(String[] args) throws IOException {
SqlSessionFactory sqlSessionFactory = MyBatisSessionFactory.getSqlSessionFactory("mybatis-config.xml");
SqlSession sqlSession = sqlSessionFactory.openSession();
Person person = sqlSession.selectOne("com.mybatis.mapper.PersonMapper.findPersonById",1);
System.out.println(person);
sqlSession.commit();
sqlSession.close();
}
}
通过id查询person后,通过resultMap建立返回映射时,使用id查询code同时将返回的IdCard绑定到Person中的card属性上。
上例是采用嵌套查询来实现的,下面我们使用第二种方法嵌套结果来实现。
只需修改PersonMapper.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.mybatis.mapper.PersonMapper" >
<select id = "findPersonById" parameterType = "Integer" resultMap = "IdCardWithPersonResult">
<!-- select * from tb_person where id = #{id} -->
select p.*, idcard.code <!-- 查询语句 -->
from tb_person p,tb_idcard idcard
where p.card_id = idcard.id and p.id = #{id}
</select> <resultMap type="com.mybatis.associateMapping.Person" id = "IdCardWithPersonResult">
<id property="id" column="id" />
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<!-- <association property = "card" column = "card_id" javaType = "com.mybatis.associateMapping.IdCard"
select = "com.mybatis.mapper.IdCardMapper.findCodeById" /> -->
<association property = "card" javaType = "IdCard">
<id property = "id" column = "id"/> <!-- 嵌套结果-->
<result property = "code" column = "code" />
</association>
</resultMap>
</mapper>
二、一对多
mybatis处理一对一主要通过<resultMap>中的<collection>元素来处理。
<collection>元素主要使用方方式有两种:
<!-- 嵌套结果-->
<collection property = "orderList" ofType = "com.mybatis.oneN.Order">
<id property = "id" column = "orders_id"/>
<result property = "number" column = "number" />
</collection>
首先创建两张表
tb_user
tb_orders
建表语句:
CREATE TABLE `tb_user` (
`id` int(32) NOT NULL AUTO_INCREMENT,
`username` varchar(32) DEFAULT NULL,
`address` varchar(256) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
CREATE TABLE `tb_orders` (
`id` int(32) NOT NULL AUTO_INCREMENT,
`number` varchar(32) NOT NULL,
`user_id` int(32) NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
CONSTRAINT `tb_orders_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `tb_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
orders中关联了用户id,即代表该商品被某一用户购买。
Order.java
public class Order {
private Integer id;
private String number;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public String toString() {
return "Order [id=" + id + ", number=" + number + "]";
}
}
User.java
import java.util.List; public class User {
private Integer id;
private String username;
private String address;
private List<Order> orderList; //用户购物清单 public User() {
super();
// TODO Auto-generated constructor stub
} public User(Integer id, String username, String address, List<Order> orderList) {
super();
this.id = id;
this.username = username;
this.address = address;
this.orderList = orderList;
} 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 getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Order> getOrderList() {
return orderList;
} public void setOrderList(List<Order> orderList) {
this.orderList = orderList;
} @Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", address=" + address + ", orderList=" + orderList + "]";
} }
UserMapper.xml (mybatis-config.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.mybatis.mapper.UserMapper" >
<select id = "findUserWithOrders" parameterType = "Integer" resultMap = "OrdersWithUserResult">
<!-- select * from tb_person where id = #{id} -->
select u.*, o.id as orders_id,o.number
from tb_user u,tb_orders o
where u.id = o.user_id and u.id = #{id}
</select> <resultMap type="com.mybatis.oneN.User" id = "OrdersWithUserResult">
<id property="id" column="id" />
<result property="username" column="username"/>
<result property="address" column="address"/>
<collection property = "orderList" ofType = "com.mybatis.oneN.Order">
<id property = "id" column = "orders_id"/>
<result property = "number" column = "number" />
</collection>
</resultMap>
</mapper>
将嵌套结果修改为嵌套调用
UserMapper.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.mybatis.mapper.UserMapper" >
<select id = "findUserWithOrders" parameterType = "Integer" resultMap = "OrdersWithUserResult">
select * from tb_user where id = #{id}
</select> <resultMap type="com.mybatis.oneN.User" id = "OrdersWithUserResult">
<id property="id" column="id" />
<result property="username" column="username"/>
<result property="address" column="address"/>
<collection property = "orderList" column = "id" ofType = "com.mybatis.oneN.Order"
select = "com.mybatis.mapper.OrdersMapper.findOrderByUserId"
/>
</resultMap>
</mapper>
OrdersMapper.xml
<!-- 一对多 订单表与com.mybatis.oneN.Order映射 -->
<resultMap type="com.mybatis.oneN.Order" id="OrderOneNResult" >
<id property = "id" column = "id"/>
<result property = "number" column="nuber"/>
</resultMap> <!-- 通过用户id查询订单 -->
<select id = "findOrderByUserId" parameterType = "Integer" resultMap = "OrderOneNResult">
select * from tb_orders where user_id = #{id}
</select>
三、多对多
一个订单可以包含多个商品,同样一个商品也可以被多个订单包含。
这种多对多关系一般需要一个中间表,用于关联两者。
如上图所示,1号订单中有1,3号商品。3号商品被1,3号订单预定。两者之间通过一个中间表联系起来。
现在我们想通过输入订单id查询该订单所包含的商品信息。例如查询一号商品订单。
由于有一个中间表,所以我们先需要通过订单id查询中间表中Order_id为1对应的Product_id的值(1,3)
然后通过Product_id中的(1,3)查询商品表中id为(1,3)的商品的详细信息。
Product.java (商品类,一个商品可以和多个订单关联)
import java.util.List; public class Product {
private Integer id; //商品ID
private String name; //商品名称
private Double price; //商品价格
private List<Order> orders; //一个商品中可包含多个订单
public Product() {
// TODO Auto-generated constructor stub
} public Product(Integer id, String name, Double price, List<Order> orders) {
super();
this.id = id;
this.name = name;
this.price = price;
this.orders = orders;
} public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public List<Order> getOrders() {
return orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
} @Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", price=" + price + "]";
}
}
Order.java(订单类,一个订单可以关联多个商品)
import java.util.List; public class Order {
private Integer id; //订单id
private String number;//订单编号
private List<Product> products; //一个订单关联多个商品 public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public String toString() {
return "Order [id=" + id + ", number=" + number + ", 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 = "com.mybatis.mapper.OrdersMapper"> <resultMap type="com.mybatis.MN.Order" id="OrdersWithProdecutResult">
<!-- 映射指定订单id查询到的订单id及订单编号 -->
<id property = "id" column = "id"/>
<result property = "number" column = "number" />
<!-- 嵌套查询,通过指定订单id查询关联商品 -->
<!-- column=id代表将id作为查询语句参数,查询中间表中order_id为1的product_id,并将product_id作为参数查询商品表 -->
<collection property = "products" column = "id"
ofType="com.mybatis.MN.Product"
select = "com.mybatis.mapper.ProductMapper.findProductById">
</collection>
</resultMap> <!-- 通过订单id查询该订单 -->
<select id="findOrdersWithProduct" parameterType = "Integer"
resultMap = "OrdersWithProdecutResult">
select * from tb_orders where id = #{id}
</select> </mapper>
该文件将订单id所对应的订单相关详细查询出来,并通过resultMap映射到Order类中,
Order对象中的 List<Product> products通过调用com.mybatis.mapper.ProductMapper.findProductById(ProductMapper.xml中)进行查询填充。
ProductMapper.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.mybatis.mapper.ProductMapper">
<select id="findProductById" parameterType = "Integer"
resultType = "com.mybatis.MN.Product">
<!-- 通过商品id查询对应商品详细信息 -->
select * from tb_product where id in (
<!-- 通过订单id在中间表中查询与其关联的商品id -->
select product_id from tb_ordersitem where order_id = #{id}
)
</select> </mapper>
该文件将订单id作为查询参数,查询中间表中order_id为1所对应的product_id。(例如订单id为1,查询商品id为1,3)
然后将查询的product_id(1,3)作为参数,查询tb_orders中对应商品详细信息。
这样就通过订单id查询到了该订单对应商品的id,并将商品填充到Order类中的List<Product> products属性中。
测试:
import java.io.IOException;
import java.util.List; import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory; import com.my.util.MyBatisSessionFactory; public class TestMapper {
public static void main(String[] args) throws IOException {
SqlSessionFactory sessionFactory = MyBatisSessionFactory.getSqlSessionFactory("mybatis-config.xml");
SqlSession sqlSession = sessionFactory.openSession();
Order order = sqlSession.selectOne("com.mybatis.mapper.OrdersMapper.findOrdersWithProduct", 1);
System.out.println(order);
sqlSession.commit();
sqlSession.close();
}
}
使用嵌套结果方式:
OrdersMapper.xml
<resultMap type="com.mybatis.MN.Order" id="OrdersWithProdecutResult">
<!-- 映射指定订单id查询到的订单id及订单编号 -->
<id property = "id" column = "id"/>
<result property = "number" column = "number" />
<!-- 嵌套查询,通过指定订单id查询关联商品 -->
<!-- column=id代表将id作为查询语句参数 -->
<collection property = "products" ofType="com.mybatis.MN.Product">
<id property = "id" column = "pid"/>
<result property = "name" column = "name"/>
<result property = "price" column = "price"/>
</collection>
</resultMap> <!-- 通过订单id查询该订单商品 -->
<select id="findOrdersWithProduct" parameterType = "Integer"
resultMap = "OrdersWithProdecutResult">
select o.*,p.id as pid,p.name,p.price
from tb_orders o, tb_product p, tb_ordersitem oi
where oi.order_id = o.id
and oi.product_id = p.id
and o.id = #{id}
</select>
1.4(Mybatis学习笔记)关联映射的更多相关文章
- MyBatis:学习笔记(3)——关联查询
MyBatis:学习笔记(3)--关联查询 关联查询 理解联结 SQL最强大的功能之一在于我们可以在数据查询的执行中可以使用联结,来将多个表中的数据作为整体进行筛选. 模拟一个简单的在线商品购物系统, ...
- mybatis学习笔记(四)-- 为实体类定义别名两种方法(基于xml映射)
下面示例在mybatis学习笔记(二)-- 使用mybatisUtil工具类体验基于xml和注解实现 Demo的基础上进行优化 以新增一个用户为例子,原UserMapper.xml配置如下: < ...
- mybatis学习笔记(7)-输出映射
mybatis学习笔记(7)-输出映射 标签: mybatis mybatis学习笔记7-输出映射 resultType 输出简单类型 输出pojo对象和pojo列表 resultMap result ...
- Mybatis学习笔记二
本篇内容,紧接上一篇内容Mybatis学习笔记一 输入映射和输出映射 传递简单类型和pojo类型上篇已介绍过,下面介绍一下包装类型. 传递pojo包装对象 开发中通过可以使用pojo传递查询条件.查询 ...
- Mybatis学习笔记之二(动态mapper开发和spring-mybatis整合)
一.输入映射和输出映射 1.1 parameterType(输入类型) [传递简单类型] 详情参考Mybatis学习笔记之一(环境搭建和入门案例介绍) 使用#{}占位符,或者${}进行sql拼接. [ ...
- mybatis 学习笔记(一):mybatis 初认识
mybatis 学习笔记(一):mybatis 初认识 简介 MyBatis是一个Java持久层框架,它通过XML描述符或注解把对象与存储过程或SQL语句关联起来.mybatis 可以将 prepar ...
- mybatis学习笔记(10)-一对一查询
mybatis学习笔记(10)-一对一查询 标签: mybatis mybatis学习笔记10-一对一查询 resultType实现 resultMap实现 resultType和resultMap实 ...
- mybatis学习笔记之基础复习(3)
mybatis学习笔记之基础复习(3) mybatis是什么? mybatis是一个持久层框架,mybatis是一个不完全的ORM框架.sql语句需要程序员自己编写, 但是mybatis也是有映射(输 ...
- 【MyBatis学习笔记】
[MyBatis学习笔记]系列之预备篇一:ant的下载与安装 [MyBatis学习笔记]系列之预备篇二:ant入门示例 [MyBatis学习笔记]系列之一:MyBatis入门示例 [MyBatis学习 ...
- Mybatis学习笔记(二) 之实现数据库的增删改查
开发环境搭建 mybatis 的开发环境搭建,选择: eclipse j2ee 版本,mysql 5.1 ,jdk 1.7,mybatis3.2.0.jar包.这些软件工具均可以到各自的官方网站上下载 ...
随机推荐
- 普通table表格样式及代码大全
普通table表格样式及代码大全(全)(一) 单实线边框表格 <table style="border-collapse: collapse" borderColor=#0 ...
- JS向右弹出DIV,点击可向左隐藏。我用jquery可以从左下角像右上角隐藏,怎么从做向右隐藏呢?
弹出的DIV如果是绝对定位,就用right固定位子,如果不是就用float:right:Jquery中有个函数animate是自定义动画效果,$("#shou").click(fu ...
- Java输入输出流备忘
重要博客: http://blog.csdn.net/hguisu/article/details/7418161 File dir = new File("\\root"); ...
- linux认证上网
公司上网需要认证,linux命令行模式:curl -d "opr=pwdLogin&userName=用户名&pwd=密码&rememberPwd=1" h ...
- codevs3304 水果姐逛水果街Ⅰ
题目描述 Description 水果姐今天心情不错,来到了水果街. 水果街有n家水果店,呈直线结构,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样. 学过oi的水果姐迅速发现了 ...
- (转)Git冲突:commit your changes or stash them before you can merge. 解决办法
用git pull来更新代码的时候,遇到了下面的问题: error: Your local changes to the following files would be overwritten by ...
- linux察看安装包有那些
rpm -ql zsh |more 安装完之后,产生那些内容 which zsh rpm -qpl /mnt/packages/ rpm -Uvh /mnt/packages/lrzsz-0.2. ...
- shell整数加法
http://blog.csdn.net/ll_0520/article/details/5959577 #plus #!/bin/sh let a=$1+$2 b=$[$1+$2] ((c=$1+$ ...
- Invalidation queue with "bit-sliceability"
BACKGROUND, FEATURES In a computer system having more than one memory storage facility, a special da ...
- 无法解析的DNS服务地址
如果DNS服务器地址设置不当,可能会导致网速慢.出现弹窗广告.网址打不开.打开不是自己想要的网站等一系列问题. 请参考: DNS的作用是什么,怎样设置DNS? https://jingyan.baid ...