目录
一开始学习mybatis时,我们做的实例都是对一个表的操作,而且表的字段名和类的属性名都是一致的,在进行多表查询、对表字段名和实体类的属性名不同是就需要用上mybatis的关联映射了。
1、关联映射概述
先来简单的了解一下关联映射吧,关联映射关系有一对一、一对多、多对多的关系,在开发中都会使用到,一对多其实比较多用。
这些关联查询mybatis又可以使用两种方式来实现,分别为嵌套查询、嵌套结果。
两者区别:
嵌套查询:
嵌套查询其实是查询SQL语句后再进行一个(子查询),会执行多条SQL语句,SQL语句编写比较简单,查询效率低,要多查一轮。
嵌套结果:
嵌套结果是一个多表查询的SQL语句,只有一条复杂的SQL语句(多表连接),SQL语句编写较为复杂,但是效率高。
对于为了减轻数据库的压力原则,接下来注重对嵌套结果进行解释和案例演示。
2、一对一查找
一对一的关联映射可以理解为一个人只有一个身份证号,一个身份证号只属于一个人。
一对一关联查询我的理解:人对应的身份证号,人作为关联查询的主体,而身份证是被关联查询的对象。被关联对象查询起来比较简单(身份证号信息),难的是关联查询的主体(人的信息)。
Class A{
B b;
}
Class B{
A a;
}
在mybatis中,通过<association>元素来处理 一对一关联关系。
<association>元素是<resultMapper>的子元素,<association>有两种配置方式:嵌套查询、嵌套结果。
2.1、嵌套查询
创建项目和导入依赖坐标我就不多说了。
(1)数据库中有两张表,tb_person表和tb_card表
(2)两个实体类作为表映射的两个实体类
连接数据库配置信息db.properties文件
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/mybatis
db.username=root
db.password=123456
mybatis核心配置类
<?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>
<!--
mybatis可以使用properties来引入外部properties配置文件的内容
resource引入类路径下的配置文件,
url引入网络路径或磁盘路径下的资源
-->
<properties resource="db.properties"></properties>
<!--
typeAliases标签可以定义pojo类的别名,有了这一步,在mapper.xml文件中的增删改查标签中定义返回类型resultType和传入参数类型parameterType时,可以省去把包全路径都写,只写类名即可
typeAliases标签中很重要的两个子标签,package和typeAlias:
package:可以以表路径来定义类的别名,不用每个类都来定义一个别名,比较实用
typeAlias:要每个类都要定义一个别名,比较繁琐,不推荐
-->
<typeAliases>
<package name="com.ltc.pojo"></package>
</typeAliases>
<!-- environments标签中就是 用来定义数据库的连接信息了,这里 是通过上面的properties标签加载进来的db.properties文件,在从文件中获取文件信息配置到property属性中去
这个标签内可以定义多个数据库连接,default属性是指定默认使用
-->
<environments default="development">
<!-- environment标签就是我们真正的定义数据库连接信息了,id就是表示命名空空,environments标签中的default属性就是用来指定这个id的值,来指定我们要使用那个数据库连接 -->
<environment id="development">
<!-- transactionManager是定义事务管理方式,这里用的是jdbc的事务管理方式 ,也可以使用其他的,自己学习去吧 -->
<transactionManager type="JDBC"/>
<!-- dataSource这个标签是指定使用的数据源,我觉得也可以说是数据库连接池,不知道这样理解是否合理,数据库连接池 国货之光 德鲁伊连接池,建议学学 -->
<dataSource type="POOLED">
<property name="driver" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
<!-- mapper标签主要是将定义的mapper.xml文件注册到核心配置文件中,让程序运行时能通过这里能找到定义的映射文件
如果没有这一步,则会报错,慎重!
-->
<mappers>
<mapper resource="com/ltc/mapper/IdCardMapper.xml"/>
<mapper resource="com/ltc/mapper/PersonMapper.xml"/>
</mappers>
</configuration>
要求:要把tb_person数据和tb_card数据关联查询
为了方便,写一个工具类来获取SqlSession对象
public class SqlSessionUtil {
private static SqlSessionFactory sessionFactory=null;
static {
try {
Reader resourceAsReader = Resources.getResourceAsReader("mybatis-config.xml");
sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsReader);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static SqlSession getSqlSession(){
return sessionFactory.openSession(true);
}
}
(3)在resources文件下创建com.ltc.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.ltc.mapper.IdCardMapper">
<!--定义接口方法对应的 SQL 语句-->
<select id="findIdCardById" resultType="IdCard" parameterType="int">
select * from tb_card where id=#{id}
</select>
</mapper>
在被关联查询的数据使用嵌套查询其实很简单,只需要正常的查询出来就可以。
注意<select>元素中的id命名空间是提供给关联查询tb_card表的提供的,要作为调用时查找到这个sql语句使用的。
(4)在resources文件下创建com.ltc.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.ltc.mapper.PersonMapper">
<!-- 嵌套查询-->
<select id="findPersonById" resultMap="personByCard" parameterType="int">
select * from tb_person where id=#{id}
</select>
<resultMap id="personByCard" type="person" >
<association property="idCard" column="idCard" javaType="IdCard" select="com.ltc.mapper.IdCardMapper.findIdCardById"></association>
</resultMap>
</mapper>
<association>元素是作为一对一关联查询用的,它是<resultMap>元素的子元素,它的主要的属性有property、column、JavaType、select。
(5)作为以上步骤就可以测试一下了
public class Test {
@org.junit.Test
public void fandPersonAndCard(){
//使用工具类获取sqlSession 对象
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
List<Person> person = sqlSession.selectList("com.ltc.mapper.PersonMapper.findPersonById",1);
System.out.println(person);
sqlSession.close();
}
}
结果:
2.2、嵌套结果
创建项目、映入依赖坐标、连接数据库、核心配置类、创建数据库表和实体类和上面将的嵌套查询一样,就不多说了
主要理解mapper文件。
嵌套结果,主要是通过一条sql(通过表连接把两个表关联查询)查询出结果通过<resultMap>元素和它的子元素<association>来对属性映射和对两个表的嵌套结果关联查询。
<?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.ltc.mapper.PersonMapper">
<!-- 嵌套结果-->
<select id="findPersonById01" resultMap="person01Card" parameterType="int">
select p.*,c.* from tb_person as p,tb_card as c where p.idCard=c.id and p.id=#{id}
</select>
<resultMap id="person01Card" type="person">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="age" column="age"></result>
<result property="set" column="set"></result>
<association property="idCard" javaType="IdCard">
<id property="id" column="id"></id>
<result property="code" column="code"></result>
</association>
</resultMap>
</mapper>
理解和解释:
<select id="findPersonById01" resultMap="person01Card" parameterType="int">
select p.*,c.* from tb_person as p,tb_card as c where p.idCard=c.id and p.id=#{id}
</select>
通过一句sql把两个表连接查询出结果,这时其实已经从数据库中到我们想要的数据了,就差把数据映射到实体类中去了。
<resultMap id="person01Card" type="person">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="age" column="age"></result>
<result property="set" column="set"></result>
<association property="idCard" javaType="IdCard">
<id property="id" column="id"></id>
<result property="code" column="code"></result>
</association>
</resultMap>
大家在学习前面的知识也到大概的知道了<resultMap>元素是拿来做表的字段名和实体类属性名不一致的情况,在这里的嵌套查询就起到了很重要的作用了,它的作用也是把我们从数据库中查询到的数据依次的映射到实体类中去。
<resultMap>的子元素<association>元素,它是将内部的实体类对象做映射的(如:IdCard类就是人Person类的内部的实体类,IdCard类对象作为Person类的属性)
<association>元素作为内部类对象的映射,框起来的这两个属性的值,则是要标记这个内部类在外部类内的属性名称和类型的,元素内的子元素id和result就可以把从数据库中查到的值映射到内部类的属性中去。
3、一对多查找
一对多是在编程过程中遇到最多的情况,在现象生活中也有很多这种关系,如购物时,一个人可以有很多个订单,人和订单之间就是一对多的关系。
在mybatis关联查询中一对多查询也是分为两种:嵌套查询和嵌套结果。
接下来通过一个案例对一对多的嵌套结果查询方式进行介绍。
在此之前就是提前工作了。
1、创建项目、引入依赖坐标、工具类编写、连接数据库、mybatis核心配置文件等都是前面大家学习搭建mybatis项目学过的,我就不多介绍了
2、准备数据库表order表和user表
3、创建表所对应的实体类
1、嵌套结果
1、创建UserMapper.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.ltc.mapper.UserMapper">
<select id="findUserAndOrdersById" resultMap="selectUserAndOrder" parameterType="int">
SELECT u.*,o.id as order_id,o.number as order_number FROM user as u,orders as o WHERE u.id=o.user_id and u.id=#{id}
</select>
<resultMap id="selectUserAndOrder" type="Users" >
<id property="id" column="id"></id>
<result property="username" column="username" ></result>
<result property="address" column="address"></result>
<collection property="orderList" ofType="Orders">
<id property="id" column="order_id"></id>
<result property="number" column="order_number"></result>
</collection>
</resultMap>
</mapper>
3、在test.java文件中创建一个测试类,一下就是测试类的测试方法:
@org.junit.Test
public void fandPersonAndCard1(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
List<Person> person = sqlSession.selectList("com.ltc.mapper.UserMapper.findUserAndOrdersById",3);
System.out.println(person);
sqlSession.close();
}
4、多对多查找
嵌套结果
在开发中,多对多关联查询的情况也是常常遇到的,如:购物时的订单和商品的关系,一个商品可以存在多个订单中,一个订单可以有多个商品。
对数据库的多对多的实现:对于多对多的关系在数据库中的实现是通过增加一个中间表来做关联的,也称为中间表,中间表中的字段分别存放两个表的主键作为外键来连接两个表。
对java实体类表现多对多的关系:分别在两个类中添加类外的类的集合类型的实体类对象。
class A{
List<B> b;
}
class B{
List<A> a;
}
接下来通过一个案例来了解和巩固mybatis操作多对多的查询。
还是一样的准备工作的就不多做解释了,直接上关键代码了。
1、创建3表,分别是商品表、订单表和做连接的中间表。
订单order表
商品product表
中间表product_order表
2、创建映射实体类
商品类Product
订单类Orders
3、创建ProductMapper.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.ltc.mapper.ProductMapper">
<select id="findProductById" parameterType="int" resultMap="findProduct">
select * from product where id in (select p_id from product_order where id=#{id})
</select>
<resultMap id="findProduct" type="Product" >
<id property="id" column="id"></id>
<result property="pName" column="p_name"></result>
</resultMap>
</mapper>
4、创建OrdertMapper.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.ltc.mapper.OrderMapper">
<select id="findOrderById01" parameterType="int" resultMap="OrderWithProduct">
select * from orders where id=#{id}
</select>
<resultMap id="OrderWithProduct" type="Orders" >
<id property="id" column="id"></id>
<result property="number" column="number"></result>
<collection property="products" column="id" ofType="Product" select="com.ltc.mapper.ProductMapper.findProductById">
<id property="id" column="id"></id>
<result property="pName" column="p_name"></result>
<result property="price" column="price"></result>
</collection>
</resultMap>
</mapper>
5、测试
public class UserAndOrderTest {
@Test
public void findUserByIdTest(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
List<Users> user = sqlSession.selectList("com.ltc.mapper.UserMapper.findUserById", 2);
sqlSession.close();
System.out.println(user);
}
}