一对一关联映射
举个例子,一个人对应一个身份证,人和身份证就是一对一关系
使用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=退出系统]]]
我纠错的时候画了下流程
我发现没
这个接口啥事啊
于是我把他这个方法注释掉
发现运行结果是一样的,所以我没搞明白书上写这个接口是干啥的
来源:CSDN
作者:stu_fan_151
链接:https://blog.csdn.net/qq_42542609/article/details/104180745