Mybatis关联映射
- 一对一关联映射
- 一对多关联映射
- 多对多关联映射
1. 一对一关联映射
在现实生活中,一个人只能有一个身份证,一个身份证只能对应一个人,人和身份证之间就是一对一关系。以人和身份证为例,使用MyBatis框架处理它们之间的一对一关联关系的步骤如下所示。
实现步骤:
1)创建数据表person 和 idcard
#创建数据表idcard
create table idcard(
id int PRIMARY key auto_increment,
cno varchar(18)
);
#插入测试数据
insert into idcard(cno) values('20200919');
insert into idcard(cno) values('20200920');
insert into idcard(cno) values('20200921');
#创建数据表Person
create table person(
id int primary key auto_increment,
name varchar(20),
age int,
sex varchar(2),
cid int,
FOREIGN key(cid) REFERENCES idcard(id)
);
#插入测试数据
insert into person(name,age,sex,cid) values('zhuge',22,'男',1);
insert into person(name,age,sex,cid) values('zhenji',17,'女',1);
insert into person(name,age,sex,cid) values('zhangfei',22,'男',1);
(2) 创建mybatis4,导入jar包
(3) 创建实体类 Person.java 和 Idcard.java
Person.java
package com.mybatis.pojo;
public class Person {
private int id;
private String name;
private int age;
private String sex;
//关联属性
private Idcard idcard;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Idcard getIdcard() {
return idcard;
}
public void setIdcard(Idcard idcard) {
this.idcard = idcard;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex + ", idcard=" + idcard + "]";
}
}
Idcard.java
package com.mybatis.pojo;
public class Idcard {
private int id;
private String cno;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCno() {
return cno;
}
public void setCno(String cno) {
this.cno = cno;
}
@Override
public String toString() {
return "Idcard [id=" + id + ", cno=" + cno + "]";
}
}
(4) 创建MyBatis映射文件
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">
<!-- 根据id查询个人信息 -->
<select id="findPersonById" parameterType="int" resultMap="personMap">
select *from person where id=#{id}
</select>
<resultMap type="Person" id="personMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<!-- 实现一对一的关联映射 -->
<association property="idcard"
select="com.mybatis.mapper.IdcardMapper.findIdcardById"
column="cid"/>
</resultMap>
</mapper>
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="findIdcardById" parameterType="int" resultType="Idcard">
select *from idcard where id=#{id}
</select>
</mapper>
(5) 创建Mapper接口
PersonMapper.java
package com.mybatis.mapper;
import com.mybatis.pojo.Person;
public interface PersonMapper {
//通过id查询用户信息
public Person findPersonById(int id);
}
IdcardMapper.java
package com.mybatis.mapper;
import com.mybatis.pojo.Idcard;
public interface IdcardMapper {
//通过id查询身份证信息
public Idcard findIdcardById(int id);
}
(6) 引用映射文件
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.pojo"></package>
</typeAliases>
<!-- 配置环境 -->
<environments default="development">
<environment id="development">
<!-- 使用JDBC事务 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 指定数据源 POOLED数据库连接池 -->
<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>
<mapper resource="com/mybatis/mapper/PersonMapper.xml"></mapper>
<mapper resource="com/mybatis/mapper/IdcardMapper.xml"></mapper>
</mappers>
</configuration>
(7) 测试一对一关联映射
package com.mybatis.test;
import static org.junit.jupiter.api.Assertions.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.mybatis.mapper.PersonMapper;
import com.mybatis.pojo.Person;
public class MybatisTest {
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
//初始化方法
@Before
public void init() {
//读取mybatis配置文件
String resource="mybatis-config.xml";
InputStream inputStream;
try {
//得到配置文件流
inputStream=Resources.getResourceAsStream(resource);
//根据配置文件信息,创建会话工厂
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到session
sqlSession=sqlSessionFactory.openSession();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@After
public void destroy() {
//提交事务
sqlSession.commit();
//关闭sqlSession
sqlSession.close();
}
//测试一对一关联映射
@Test
public void testFindPersonById() {
PersonMapper pm=sqlSession.getMapper(PersonMapper.class);
Person person=pm.findPersonById(1);
System.out.println(person);
}
}
2. 一对多关联映射
在实际开发中,一对多关联关系要比一对一更为常见。例如,订单与订单明细之间就是一对多关系。一个订单有多条明细信息,一条订单明细信息对应一个订单。同样,商品类别与商品之间也是一对多关系。一个商品类别对应有多个商品,一个商品属于一个类别。
以数据库eshop中的商品类别表type和商品表product_info为例,针对数据查询、插入和删除操作,使用MyBatis框架处理它们之间的一对多关联关系。
2.1 数据查询(嵌套查询)
数据查询是根据商品类型编号从数据表type中查询商品类型,并查询关联的商品列表。其具体实现步骤如下。
(1)创建项目mybatis5,导入jar包
(2)创建实体类
Type.java 商品类型表
package com.mybatis.pojo;
import java.util.List;
public class Type {
private int id;
private String name;
//关联集合属性
private List<ProductInfo> prodInfo;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<ProductInfo> getProdInfo() {
return prodInfo;
}
public void setProdInfo(List<ProductInfo> prodInfo) {
this.prodInfo = prodInfo;
}
@Override
public String toString() {
return "Type [id=" + id + ", name=" + name + ", prodInfo=" + prodInfo + "]";
}
}
ProductInfo.java 商品信息表
package com.mybatis.pojo;
public class ProductInfo {
private int id;
private String code;
private String name;
//关联属性
private Type type;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "ProductInfo [id=" + id + ", code=" + code + ", name=" + name + "]";
}
}
(3)创建MyBatis映射文件
ProductInfoMapper.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.ProductInfoMapper">
<!-- 通过商品类型编号查询商品信息 -->
<select id="findProductInfoByTid" parameterType="int" resultType="ProductInfo">
select *from product_info where tid=#{id}
</select>
</mapper>
TypeMapper.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.TypeMapper">
<!-- 根据商品类型编号获取商品类型信息 -->
<select id="findTypeById" parameterType="int" resultMap="typeMap">
select *from type where id=#{id}
</select>
<resultMap type="Type" id="typeMap">
<id property="id" column="id"/>
<result property="name" column="name" />
<!-- 一对多关联映射 -->
<collection property="prodInfo" column="id"
select="com.mybatis.mapper.ProductInfoMapper.findProductInfoByTid">
</collection>
</resultMap>
</mapper>
(4)创建Mapper接口
ProductInfoMapper.java
package com.mybatis.mapper;
import com.mybatis.pojo.ProductInfo;
public interface ProductInfoMapper {
public ProductInfo findProductInfoByTid(int id);
}
TypeMapper.java
package com.mybatis.mapper;
import com.mybatis.pojo.Type;
public interface TypeMapper {
//通过id查询商品类型
public Type findTypeById(int id);
}
(5)引用映射文件
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.pojo"></package>
</typeAliases>
<!-- 配置环境 -->
<environments default="development">
<environment id="development">
<!-- 使用JDBC事务 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 指定数据源 POOLED数据库连接池 -->
<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>
<mapper resource="com/mybatis/mapper/TypeMapper.xml"></mapper>
<mapper resource="com/mybatis/mapper/ProductInfoMapper.xml"></mapper>
</mappers>
</configuration>
(6)测试一对多关联映射
MybatisTest.java
package com.mybatis.test;
import static org.junit.jupiter.api.Assertions.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.mybatis.mapper.TypeMapper;
import com.mybatis.pojo.Type;
public class MybatisTest {
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
//初始化方法
@Before
public void init() {
//读取mybatis配置文件
String resource="mybatis-config.xml";
InputStream inputStream;
try {
//得到配置文件流
inputStream=Resources.getResourceAsStream(resource);
//根据配置文件信息,创建会话工厂
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到session
sqlSession=sqlSessionFactory.openSession();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@After
public void destroy() {
//提交事务
sqlSession.commit();
//关闭sqlSession
sqlSession.close();
}
//测试一对多关联映射
@Test
public void testFindProdInfoById() {
//获取TypeMapper接口的代理对象
TypeMapper typeMapper=sqlSession.getMapper(TypeMapper.class);
Type type=typeMapper.findTypeById(1);
System.out.println(type);
}
}
(7)测试结果如下:
2.2 数据查询(嵌套结果)
在映射文件TypeMapper.xml中,一对多关联映射是通过执行另一个返回预期类型的映射SQL语句,即引用外部定义好的SQL语句块,这种关联映射查询方式也称为嵌套查询。
此外,MyBatis还提供了另一种关联映射查询方式——嵌套结果,它通过嵌套结果映射来处理联接结果集的重复子集。还是以类别表type和商品表product_info的一对多关联查询为例,使用嵌套结果查询方式的步骤如下所示。
(1)在映射文件TypeMapper.xml中,编写使用嵌套结果查询方式进行一对多关联查询的配置。
<!-- 使用嵌套结果查询方式实现一对多关联查询,根据商品类型编号获取商品类型信息 -->
<select id="findTypeById2" parameterType="int" resultMap="typeMap2">
select t.id tid,t.name tname,pi.*
from type t,product_info pi where t.id=pi.tid
and t.id=#{id}
</select>
<resultMap type="Type" id="typeMap2">
<id property="id" column="tid"/>
<result property="name" column="tname"/>
<!-- 一对多关联映射 -->
<collection property="prodInfo" ofType="ProductInfo">
<id property="id" column="id"/>
<result property="code" column="code"/>
<result property="name" column="name"/>
</collection>
</resultMap>
(2)在接口TypeMapper中,添加一个方法findTypeById2。
//通过id查询商品类型
public Type findTypeById2(int id);
(3)添加测试方法。
//测试一对多关联映射(嵌套结果)
@Test
public void testFindProdInfoById2() {
//获取TypeMapper接口的代理对象
TypeMapper tm=sqlSession.getMapper(TypeMapper.class);
Type type=tm.findTypeById2(1);
System.out.println(type);
}
(4)测试结果如下:
2.3 数据插入
数据插入操作要实现将数据同时插入数据表type和product_info,其具体实现步骤如下。
(1)在映射文件TypeMapper.xml中,编写将数据插入数据表type的配置。
<!-- 向数据表type插入数据 -->
<insert id="addType" parameterType="Type">
<selectKey keyProperty="id" resultType="int" order="AFTER">
select last_insert_id() as id
</selectKey>
insert into type(name) values(#{name})
</insert>
- selectKey:定义了一个获取刚插入的自动增长的 id 值的 SELECT 语句。
- keyProperty:用于指定这个 SELECT 语句的执行结果赋值给 Type 类型对象的那个属性。这里为 id
- resultType:用于指定执行结果类型,这里为 int
- order:可以被设置为 BEFORE 或 AFTER ,如果先设置为 AFTER ,则先执行插入语句,
然后设置 keyProperty,如果先设置为 BEFORE,则先选择主键,并设置 keyProperty,然后执行插入语句
(2)在接口TypeMapper中,添加一个addType方法。
//添加商品类型
public void addType(Type type);
(3)在映射文件ProductInfoMapper.xml中,编写将数据插入数据表product_info的配置。
<!-- 向product_info表插入数据 -->
<insert id="addProductInfo" parameterMap="ProductInfoMap">
insert into product_info(code,name,tid) values(#{code},#{name},#{type.id})
</insert>
<parameterMap type="ProductInfo" id="ProductInfoMap">
<parameter property="code"/>
<parameter property="name"/>
<parameter property="type.id"/>
</parameterMap>
- 在映射文件ProductInfoMapper.xml中,添加了一个 id 为 addProductInfo 的insert 元素,定义了一个向数据表 product_info 插入记录的 insert 语句。由于这条 insert 语句有多个参数且实体类中的属性和数据库中的字段不对应,因此通过 parameterMap 属性指定传入 insert 语句的参数,这里设置为 ProductInfoMap, 即引用当前映射文件中一个 id 为 ProductInfoMap 的 parameterMap 元素。
- 在 parameterMap 元素中,type 属性指定SQL语句中的参数来自于哪个实体对象,parameter 子元素的 property 属性进一步指定参数来自于实体对象的哪个属性。
(4)在com.mybatis.mapper包中,创建ProductInfoMapper接口,并添加一个addProductInfo方法。
package com.mybatis.mapper;
import com.mybatis.pojo.ProductInfo;
public interface ProductInfoMapper {
public void addProductInfo(ProductInfo pi);
}
(5) 添加测试方法
//测试一对多关联映射添加数据
@Test
public void testAddType() {
//创建type对象
Type type=new Type();
type.setName("打印机");
//获取TypeMapper接口的代理对象
TypeMapper tm=sqlSession.getMapper(TypeMapper.class);
tm.addType(type);
//创建两个ProductInfo对象
ProductInfo pi=new ProductInfo();
pi.setCode("11111");
pi.setName("hp1306");
ProductInfo pi2=new ProductInfo();
pi2.setCode("22222");
pi2.setName("hp1307");
//设置关联属性
pi.setType(type);
pi2.setType(type);
//获取ProductInfoMapper接口的代理对象
ProductInfoMapper pm=sqlSession.getMapper(ProductInfoMapper.class);
//添加商品
pm.addProductInfo(pi);
pm.addProductInfo(pi2);
}
(6) 运行测试方法,执行结果如下:
2.4 数据删除
数据删除操作要实现从数据表type删除记录时,将关联表product_info中的记录也删除,其具体实现步骤如下。
(1)在映射文件TypeMapper.xml中,编写删除数据的配置。
<!-- 删除数据 -->
<delete id="deleteTypeById" parameterType="int">
delete from product_info where tid=#{id};
delete from type where id=#{id};
</delete>
- 在 id 为 deleteTypeById 的 delete 元素中,定义了两条 delete 语句,第一条delete 语句从关联表 product_info 中删除记录,第二条 delete 语句从主表 type 中删除记录。多条SQL语句之间用分号隔开。由于MYSQL默认没有开启批量执行SQL语句的开关,因此无法一次执行多条SQL语句,那么如何开启呢?只需在设置MySQL连接的Url时,加上 allowMultiQueries=true 即可
db.properties
(2)在接口TypeMapper中,添加一个deleteTypeById方法。
//删除商品信息和类型
public int deleteTypeById(int id);
(3)添加测试方法
//删除数据
@Test
public void testDeleteTypeById(){
//获取TypeMapper接口代理对象
TypeMapper tm=sqlSession.getMapper(TypeMapper.class);
int result=tm.deleteTypeById(6);
if(result>0) {
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
}
(4)运行测试方法,结果如下
3 多对多关联映射
- 在实际开发中,多对多关联关系也比较常见。例如,订单与商品之间就是多对多关系。一个订单可以包含多个商品,一个商品可以属于多个订单。同样,管理员与系统功能之间也是多对多关系。一个管理员可以拥有多个功能权限,一个系统功能可以属于多个用户。
- 以数据库eshop中的管理员表admin_info和系统功能表functions为例,它们之间通过中间表powers来关联,这个中间表分别与admin_info和functions构成多对一关联。中间表powers以aid和fid作为联合主键,其中,aid字段作为外键参照admin_info表的id字段,fid字段作为外键参照functions表的id字段。
表SQL
CREATE TABLE `powers` (
`aid` int(4) NOT NULL,
`fid` int(4) NOT NULL,
PRIMARY KEY (`aid`,`fid`),
KEY `fid` (`fid`),
KEY `aid` (`aid`),
CONSTRAINT `powers_ibfk_1` FOREIGN KEY (`aid`) REFERENCES `admin_info` (`id`),
CONSTRAINT `powers_ibfk_2` FOREIGN KEY (`fid`) REFERENCES `functions` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;
/*Data for the table `powers` */
insert into `powers`(`aid`,`fid`)
values (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(1,9),(1,11);
CREATE TABLE `admin_info` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`name` varchar(16) DEFAULT NULL,
`pwd` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=gbk;
/*Data for the table `admin_info` */
insert into `admin_info`(`id`,`name`,`pwd`)
values (1,'admin','123456'),(2,'my','123456'),(3,'sj','123456'),(4,'lxf','123456');
/*Table structure for table `functions` */
DROP TABLE IF EXISTS `functions`;
CREATE TABLE `functions` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL COMMENT '功能菜单',
`parentid` int(4) DEFAULT NULL,
`url` varchar(50) DEFAULT NULL,
`isleaf` bit(1) DEFAULT NULL,
`nodeorder` int(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=gbk;
/*Data for the table `functions` */
insert into `functions`(`id`,`name`,`parentid`,`url`,`isleaf`,`nodeorder`)
values (1,'电子商城管理后台',0,NULL,'\0',0),(2,'商品管理',1,NULL,'\0',1),
(3,'商品列表',2,NULL,'',1),(4,'商品类型列表',2,NULL,'',2),(5,'订单管理',1,NULL,'\0',2),
(6,'查询订单',5,NULL,'',1),(7,'创建订单',5,NULL,'',2),(8,'用户管理',1,NULL,'\0',3),
(9,'用户列表',8,NULL,'',1),(11,'退出系统',1,NULL,'',1);
以数据查询操作为例,使用MyBatis框架处理它们之间的多对多关联关系,其具体实现步骤如下。
(1)新建项目mybatis6,导入jar包
(2)创建实体类 AdminInfo.java,Functions.java
AdminInfo.java
package com.mybatis.pojo;
import java.util.List;
public class AdminInfo {
private int id;
private String name;
//关联的属性
private List<Functions> fs;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Functions> getFs() {
return fs;
}
public void setFs(List<Functions> fs) {
this.fs = fs;
}
@Override
public String toString() {
return "AdminInfo [id=" + id + ", name=" + name + ", fs=" + fs + "]";
}
}
Functions.java
package com.mybatis.pojo;
public class Functions {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Function [id=" + id + ", name=" + name + "]";
}
}
(3)创建MyBatis映射文件
AdminInfoMapper.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.AdminInfoMapper">
<!-- 根据管理员id查询管理员信息 -->
<select id="findAdminInfoById" parameterType="int" resultMap="adminInfoMap">
select *from admin_info where id=#{id}
</select>
<resultMap type="AdminInfo" id="adminInfoMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
<!-- 多对多关联映射 -->
<collection property="fs" ofType="Functions" column="id" select="com.mybatis.mapper.FunctionsMapper.findFunctionsByAid">
</collection>
</resultMap>
</mapper>
FunctionsMapper.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.FunctionsMapper">
<!-- 根据管理员id获取其功能权限列表 -->
<select id="findFunctionsByAid" parameterType="int" resultType="Functions">
select *from functions where id in (
select fid from powers where aid=#{id}
)
</select>
</mapper>
在 FunctionsMapper.xml 文件中,定义了一个 id 为 findFunctionsByAid 的 select 元素,根据管理员 id 获取其功能权限列表。由于管理员和系统功能是多对多关系,数据库中使用了一个中间表powers维护多对多关联关系。此处使用了一个子查询,首先根据管理员id到powers中查询出所有的功能权限id,然后再根据功能权限id到functions表中查询出所有的功能权限信息,并将这些信息封装到Functions对象中
(4)创建Mapper接口
AdminInfoMapper.java
package com.mybatis.mapper;
import com.mybatis.pojo.AdminInfo;
public interface AdminInfoMapper {
public AdminInfo findAdminInfoById(int id);
}
FunctionsMapper
package com.mybatis.mapper;
import com.mybatis.pojo.Functions;
public interface FunctionsMapper {
//根据管理员id获取其功能权限列表
public Functions findFunctionsByAid(int id);
}
(5)引用映射文件
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.pojo"></package>
</typeAliases>
<!-- 配置环境 -->
<environments default="development">
<environment id="development">
<!-- 使用JDBC事务 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 指定数据源 POOLED数据库连接池 -->
<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>
<mapper resource="com/mybatis/mapper/FunctionsMapper.xml"></mapper>
<mapper resource="com/mybatis/mapper/AdminInfoMapper.xml"></mapper>
</mappers>
</configuration>
(6)测试多对多关联映射
package com.mybatis.test;
import static org.junit.jupiter.api.Assertions.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.mybatis.mapper.AdminInfoMapper;
import com.mybatis.pojo.AdminInfo;
public class MybatisTest {
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
//初始化方法
@Before
public void init() {
//读取mybatis配置文件
String resource="mybatis-config.xml";
InputStream inputStream;
try {
//得到配置文件流
inputStream=Resources.getResourceAsStream(resource);
//根据配置文件信息,创建会话工厂
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到session
sqlSession=sqlSessionFactory.openSession();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@After
public void destroy() {
//提交事务
sqlSession.commit();
//关闭sqlSession
sqlSession.close();
}
//测试多对多关联映射
@Test
public void testfindAdminInfoById() {
//通过sqlSession获取AdminMapper接口代理对象
AdminInfoMapper am=sqlSession.getMapper(AdminInfoMapper.class);
AdminInfo ai=am.findAdminInfoById(1);
System.out.println(ai);
}
}
(7)运行测试testfindAdminInfoById