Mybatis关联映射介绍及应用

Mybatis关联映射

  1. 一对一关联映射
  2. 一对多关联映射
  3. 多对多关联映射

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:可以被设置为 BEFOREAFTER ,如果先设置为 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中,添加了一个 idaddProductInfoinsert 元素,定义了一个向数据表 product_info 插入记录的 insert 语句。由于这条 insert 语句有多个参数且实体类中的属性和数据库中的字段不对应,因此通过 parameterMap 属性指定传入 insert 语句的参数,这里设置为 ProductInfoMap, 即引用当前映射文件中一个 idProductInfoMapparameterMap 元素。
  • 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 为 deleteTypeByIddelete 元素中,定义了两条 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 文件中,定义了一个 idfindFunctionsByAidselect 元素,根据管理员 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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值