MyBatis学习_2_MyBatis的关联映射

最后都变了- 提交于 2020-02-06 18:12:30

一对一关联映射

举个例子,一个人对应一个身份证,人和身份证就是一对一关系
使用MyBatis框架处理他们之间一对一关联关系的步骤如下:
1.创建两张数据表用来做测试

USE eshop
#创建数据表idcard
`idcard`
#插入测试数据
INSERT INTO idcard(cno) VALUES(320100197001010001);
INSERT INTO idcard(cno) VALUES(320100197001010002);
INSERT INTO idcard(cno) VALUES(320100197001010003);
#创建数据表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)
);`person`
#插入测试数据
INSERT INTO person(NAME,age,sex,cid) VALUES('zhangsan',22,'男',1);
INSERT INTO person(NAME,age,sex,cid) VALUES('lili',21,'女',2);
INSERT INTO person(NAME,age,sex,cid) VALUES('wangwu',22,'男',3);

2.创建项目mybatis4,在com.mybatis.pojo中新建两个实体类

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 + "]";
	}
	
}

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 + "]";
	}
	
}

3.在com.mybatis.mapper包中创建IdcardMapper.xml和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.IdcardMapper">
 	<!--根据idcard的id查询身份证信息  -->
 	<select id="findIdcardById" parameterType="int" resultType="Idcard">
 		select * from idcard where id=#{id}
 	</select>
 </mapper>
<?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">
 	<!--根据personid查询个人信息  -->
 	<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"></association>
 	</resultMap>
 </mapper>

4.引用映射文件

<?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" />
	</typeAliases>
	<!-- 配置environment环境 -->
	<environments default="development">
		<!-- 配置一个id为development的环境 -->
		<environment id="development">
			<!-- 使用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>
		<mapper resource="com/mybatis/mapper/UserInfoMapper.xml" />
		<mapper resource="com/mybatis/mapper/IdcardMapper.xml" />
		<mapper resource="com/mybatis/mapper/PersonMapper.xml" />
	</mappers>
</configuration>

5.创建Mapper接口
要求上一章入门有

package com.mybatis.mapper;

import com.mybatis.pojo.Person;

public interface PersonMapper {
	Person findPersonById(int id);
}

6.编写测试文件

package com.mybatis.test;


import java.io.IOException;
import java.io.InputStream;


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);
			// 通过工厂得到SqlSession
			sqlSession = sqlSessionFactory.openSession();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	//测试一对一关联映射
	@Test
	public void testFindPersonById() {
		// TODO Auto-generated method stub
		PersonMapper pm=sqlSession.getMapper(PersonMapper.class);//获取PersonMapper接口的代理对象
		Person person = pm.findPersonById(1);
		System.out.println(person);
	}
	
	@After
	public void destory() {
		//提交事务
		sqlSession.commit();
		//关闭sqlSession
		sqlSession.close();
	}
}

在src下创建log4j.xml文件,入门中有代码
运行结果
在这里插入图片描述
我觉得其实就是把两个步骤封装到一块了,我记得我做过这个东西,我是分了两步,先通过id找到这个人,再根据他们的关联属性,也就是这里的cid找到另一张表里的内容,不过输出就没他这么从容了,挺麻烦的。
其实核心流程,关键步骤我觉得是这个
在这里插入图片描述

一对多关联映射

数据查询

嵌套查询

举个例子:订单与订单明细就是一对多关系,一个订单对应多个订单明细,一个订单明细对应一个订单
步骤:
1.还是新建数据表,上一张有个eshop的数据库,我把sql代码也放在上一章入门里了,复制粘贴直接用就行,这次用到的两张表长这样
type表
在这里插入图片描述
product_info表
在这里插入图片描述
这个tid应该就是对应的type表中的id,数据库学的有点早了,都忘了他俩的关系叫啥了,改天复习下。其实我依稀记得一对多好像也可以用一张表解决,只有多对对要两张表。(学数据库的时候还没开始写博客,悔啊),比如我PHP课程设计中用到的商品类别举个例子就是:类别里面直接写:热饮,而不是把种类新开一张表。,当然,感觉他这样新开一张表可能更好一点,种类的规定更加严密

这里要达到的效果是,查询商品类型id,然后不止展现出改id对应的type名,还要展示出该type下的商品
2.新建实体类
在这里插入图片描述
在这里插入图片描述
3.创建映射文件

<?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="findProductInfoById" parameterType="int" resultType="ProductInfo">
 		select * from product_info where tid=#{id}
 	</select>
 </mapper>
<?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="pis" 
 		select="com.mybatis.mapper.ProductInfoMapper.findProductInfoById"
 		column="id">
 		
 		</collection>
 	</resultMap>
 </mapper>

4.引用映射文件(部分代码,除了这点,其余的跟上面那个一样)

<!-- 引用映射文件 -->
	<mappers>
		<mapper resource="com/mybatis/mapper/UserInfoMapper.xml" />
		<mapper resource="com/mybatis/mapper/ProductInfoMapper.xml" />
		<mapper resource="com/mybatis/mapper/TypeMapper.xml" />
	</mappers>

5.创建Mapper接口

package com.mybatis.mapper;

import com.mybatis.pojo.Type;

public interface TypeMapper {
	Type findTypeById(int id);
}

6.写test方法

@Test
	public void testFindTypeById() {
		//获取接口的代理对象
		TypeMapper tm = sqlSession.getMapper(TypeMapper.class);
		//System.out.println("111111");
		//调用接口中的方法
		Type type = tm.findTypeById(1);
		
		System.out.println(type.toString());
	}

运行结果
他不会自动换行,我只有这样展示了~。
Type [id=1, name=电脑, pis=[ProductInfo [id=1, code=1378538, name=AppleMJVE2CH/A], ProductInfo [id=2, code=1309456, name=ThinkPadE450C(20EH0001CD)], ProductInfo [id=3, code=1999938, name=联想小新300经典版], ProductInfo [id=4, code=1466274, name=华硕FX50JX], ProductInfo [id=5, code=1981672, name=华硕FL5800], ProductInfo [id=6, code=1904696, name=联想G50-70M]]]

嵌套结果

嵌套查询是引用外部定义好的sql语句块,相当于是先查一层,再查第二层。
结果嵌套给我的感觉像是把两张表拼接成一张表,用一句sql语句chaxun
步骤如下
修改TypeMapper.xml映射文件,添加以下代码

<!--使用嵌套结果查询方式实现一对多关联查询,根据类型编号来获取商品类型信息  -->
 	<select id="findTypeById2" parameterType="int" resultMap="typeMap2">
 		select t.id tid,t.name tname,pi.* 
 		from type t,product_info pi where pi.tid=t.id and t.id=#{id}
 	</select>
 	<resultMap type="Type" id="typeMap2">
 		<id property="id" column="tid"/>
 		<result property="name" column="tname"/>
 		<collection property="pis" ofType="ProductInfo">
 			<id property="id" column="id"/>
 			<result property="name" column="name"/>
 			<result property="code" column="code"/>
 		</collection>
 	</resultMap>

分析图:
在这里插入图片描述
修改mapper接口
在这里插入图片描述
新增测试方法
在这里插入图片描述
运行结果:
Type [id=1, name=电脑, pis=[ProductInfo [id=1, code=1378538, name=AppleMJVE2CH/A], ProductInfo [id=2, code=1309456, name=ThinkPadE450C(20EH0001CD)], ProductInfo [id=3, code=1999938, name=联想小新300经典版], ProductInfo [id=4, code=1466274, name=华硕FX50JX], ProductInfo [id=5, code=1981672, name=华硕FL5800], ProductInfo [id=6, code=1904696, name=联想G50-70M]]]

数据插入

在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>

在接口中新增方法
在这里插入图片描述
在映射文件ProductionMapper.xml中,编写将数据插入数据表product_info的配置
在这里插入图片描述
新建ProductInfoMapper接口
在这里插入图片描述
写test方法

@Test
	public void testAddType() {
		//创建Type对象
		Type type = new Type();
		type.setName("打印机");
		//获得TypeMapper接口的代理对象
		TypeMapper tMapper = sqlSession.getMapper(TypeMapper.class);
		//直接调用接口的方法,保存Type对象
		tMapper.addType(type);
		//创建两个ProductInfo对象
		ProductInfo pi1 = new ProductInfo();
		ProductInfo pi2 = new ProductInfo();
		pi1.setCode("1111111111");
		pi1.setName("pi1");
		pi2.setCode("2222222222");
		pi2.setName("pi2");
		//设置关联属性
		pi1.setType(type);
		pi2.setType(type);
		// 获得ProductInfoMapper接口的代理对象
		ProductInfoMapper pm = sqlSession.getMapper(ProductInfoMapper.class);
		// 直接调用接口的方法,保存两个ProductInfo对象
		pm.addProductInfo(pi1);
		pm.addProductInfo(pi2);
	}

运行
在这里插入图片描述
在这里插入图片描述

数据删除

1.在TypeMapper.xml映射文件中加入删除的语句

<!--删除数据  -->
 	<delete id="deleteTypeById" parameterType="int">
 		delete from product_info where tid=#{id};
 		delete from type where id=#{id}
 	</delete>

2.这是连续两条sql语句,必须要去开启批量执行的开关
在db.properties中加上红框内的内容
在这里插入图片描述
3.在接口中添加方法
在这里插入图片描述
4.写测试方法

//删除数据
	@Test
	public void testDeleteTypeById() {
		TypeMapper tMapper = sqlSession.getMapper(TypeMapper.class);
		int result = tMapper.deleteTypeById(6);
		if (result>0) {
			System.out.println("成功删除"+result+"行");
		}else {
			System.out.println("删除失败");
		}
	}

运行检查结果,确实都删掉了
在这里插入图片描述

多对多关联映射

我觉得其实这个是最重要的,前面的两个我都用过,这个我好像光数据库的课上听过有这么个东西,但好像没在项目中用到过
在实际开发中,多对多关联关系也比较常见。例如,订单与商品之间就是多对多关系。一个订单可以包含多个商品,一个商品可以属于多个订单。同样,管理员与系统功能之间也是多对多关系。一个管理员可以拥有多个功能权限,一个系统功能可以属于多个用户。(fine,我好像只做到了购物车,还没有做订单,而且后台管理员只有一个,没有功能分发,我说我怎么没用到过)
0.数据库的建立,还用的是eshop,这次用到这三张表
在这里插入图片描述
1.新建实体类
在这里插入图片描述
2.写两个映射文件

<?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 f where id in (
 		select fid from powers where aid = #{id}
 		)
 	</select>
 </mapper>
<?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>

3.配置引用映射文件
在这里插入图片描述
4.写两个接口调用这两个映射方法(我其实也不知道可不可以这么说,但我感觉就是这么回事)
在这里插入图片描述
在这里插入图片描述
5.写测试方法
在这里插入图片描述
运行
AdminInfo [id=1, name=admin, fs=[Functions [id=1, name=电子商城管理后台], Functions [id=2, name=商品管理], Functions [id=3, name=商品列表], Functions [id=4, name=商品类型列表], Functions [id=5, name=订单管理], Functions [id=6, name=查询订单], Functions [id=7, name=创建订单], Functions [id=8, name=用户管理], Functions [id=9, name=用户列表], Functions [id=11, name=退出系统]]]
我纠错的时候画了下流程
在这里插入图片描述
我发现没
在这里插入图片描述

这个接口啥事啊
于是我把他这个方法注释掉
发现运行结果是一样的,所以我没搞明白书上写这个接口是干啥的

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!