MyBatis中并没有实现多对多,这是因为多对多级联可以通过两个一对多级联进行替换。在实际生活中,一个订单可以有多种商品,一种商品可以对应多个订单,订单与商品就是多对多的关系。同样的,一个人可以有多种身份,一个身份也可以被多个人所拥有。MyBatis想要实现多对多,就需要使用一个中间表将多对多转换成两个一对多的关系。本篇中的案例将使用人和身份的关系来实现多对多。
(1)创建数据库表以及中间表。
CREATE TABLE `t_people` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`address` varchar(100) DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `t_people` VALUES (1,'tom','北京'),(2,'jerry','天津'),(3,'李承','湖南');
CREATE TABLE `t_role` (
`rid` int(11) NOT NULL AUTO_INCREMENT,
`act` varchar(20) DEFAULT NULL,
PRIMARY KEY (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
INSERT INTO `t_role` VALUES (1,'教师'),(2,'公务员'),(3,'大将军'),(4,'市长');
CREATE TABLE `t_peoplerole` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pid` int(11) DEFAULT NULL,
`rid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
INSERT INTO `t_peoplerole` VALUES (1,1,3),(2,2,2),(3,2,4),(4,3,3),(5,1,1),(6,1,4);
(2)创建People类和Role类
People类:
public class People {
private Integer id;
private String name;
private String address;
private List<Role> roleList;
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Role> getRoleList() {
return roleList;
}
public void setRoleList(List<Role> roleList) {
this.roleList = roleList;
}
@Override
public String toString() {
return "People{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
", roleList=" + roleList +
'}';
}
}
Role类:
public class Role {
private Integer id;
private String act;
private List<People> peopleList;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAct() {
return act;
}
public void setAct(String act) {
this.act = act;
}
public List<People> getPeopleList() {
return peopleList;
}
public void setPeopleList(List<People> peopleList) {
this.peopleList = peopleList;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", act='" + act + '\'' +
", peopleList=" + peopleList +
'}';
}
}
(3)创建IPeopleDao类
public interface IPeopleDao {
List<People> findAllPeople();
}
(4)创建peopleMapper.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">
<!--namespace:指定了唯一的命名空间-->
<mapper namespace="com.day1.dao.IPeopleDao">
<resultMap id="peopleRole" type="com.day1.entity.People">
<id property="id" column="pid"></id>
<result property="name" column="name"></result>
<result property="address" column="address"></result>
<collection property="roleList" ofType="com.day1.entity.Role" resultMap="role"></collection>
</resultMap>
<resultMap id="role" type="com.day1.entity.Role">
<id property="id" column="rid"></id>
<result property="act" column="act"></result>
</resultMap>
<select id="findAllPeople" resultMap="peopleRole">
select p.*, r.* from t_people p, t_role r, t_peoplerole pr where p.pid = pr.pid and pr.rid = r.rid;
</select>
</mapper>
(5)在SqlMapperConfig.xml中配置peopleMapper.xml文件
<mapper resource="com/day1/peopleMapper.xml"></mapper>
(6)进行测试
@Test
public void testSelect() throws IOException {
//1、读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapperConfig.xml");
//2、创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3、使用工厂生产SqlSession对象
SqlSession sqlSession = factory.openSession();
//4、使用SqlSession创建dao接口的代理对象
IPeopleDao peopleDao= sqlSession.getMapper(IPeopleDao.class);
//5、使用代理对象执行方案
List<People> peopleList = peopleDao.findAllPeople();
for(People people : peopleList){
System.out.println(people);
}
//6、释放资源
sqlSession.close();
in.close();
}
关于多对多查询中只出现一条数据的原因还是我在上一篇中提到的两张表的主键名称一致所导致的问题(t_people和t_role的主键名称均为id),这是一个需要注意的地方。当主键名称不一致时,就不会出现这个问题,即:t_people的主键为pid,t_role的主键为rid。