mybatis的关联关系
mybatis的关联关系有三种
----->1.一对一
----->2.一对多
----->3.多对多
表现在pojo中是单个引用还是多个引用,从示例上看,朝代可以有多个皇上,朝代就是多的一方。皇帝只能有一个朝代,皇帝就是一的一方。
多的一方看
pojo king
import java.util.Date;
/**
* 皇上的pojo
*
* @author TeaBig
*/
public class ADemoKing
{
private int id;
private int dynastyId;
private String name;
private String content;
private String miaoHao;
private String nianHao;
private byte age;
private byte status;
private Date createTime;
private Date updateTime;
private Date pubTime;
/* 关联关系:自定义引用 */
/* 只能有一个朝代,所以是单个引用 */
private ADemoDynasty dynasty ;
Set/get方法
@Override
public String toString()
{
return "ADemoKing [id=" + id + ", dynastyId=" + dynastyId + ", name=" + name + ", content=" + content
+ ", miaoHao=" + miaoHao + ", nianHao=" + nianHao + ", age=" + age + ", status=" + status
+ ", createTime=" + createTime + ", updateTime=" + updateTime + ", pubTime=" + pubTime + "]";
}
mapper.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">
<!-- namespace不能为空
mapper:相当于java里面的类
namespace:相当于java里面的包名
-->
<mapper namespace="king">
<!-- ===========延迟加载===============
延迟:懒惰,积极;
积极一点:
懒惰一点:
延迟加载:
查询a对象,期望使用到关联对象b的时候再查询b,而不是马上就查询b
-->
<!--
查询所有的朝代记录
select标签可以发送select语句
id:唯一标识,当前的mapper文件中,id不能重复
resultType:结果类型;
如果查询的是单条,那返回值的类型就是resultType;
如果查询的是多条,那么返回值的类型是List,List里面放的是resultType
-->
<select id="selectList" resultType="com.jinghangzz.mybatis.data.pojo.ADemoKing">
select * from a_demo_king
</select>
<!-- resultMap -->
<!-- 要发送两条sql语句,
先查询皇上,
拿着dynastyId(朝代Id要去朝代表查询朝代)
-->
<resultMap type="com.jinghangzz.mybatis.data.pojo.ADemoKing" id="resultMap">
<!-- 如果配置了关联关系,那关联字段必须手动赋值 -->
<result column="dynastyId" property="dynastyId"/>
<!-- 联合:
property:pojo的属性名
column:数据库的列名;为dynasty赋值的时候,需要用到皇上表的哪列?
javaType:dynasty到底是哪个类型(java里面的); 包名+类名
select:拿着column执行哪个sql语句,应该可以查询到dynasty;执行sql语句的id;
sql语句的id,应该是namespace+sql语句的id(如果sql语句的就在当前文件中,那namespace可以忽略)
fetchType:抓取策略;lazy:延迟加载;eager:默认就是积极加载;
如果全局开头木有打开,只能此标签才会起作用,其它的标签不起作用;
建议:(延迟加载开关都打开)
延迟加载只能在一个JVM里面生效;微服务编程:(dubbo,SPringCloud,延迟加载不起作用)
-->
<association property="dynasty" column="dynastyId" javaType="com.jinghangzz.mybatis.data.pojo.ADemoDynasty"
select="dynasty.selectRelaOne" />
</resultMap>
<!-- 查询一条记录
resultType:指定的皇上,里面有一个朝代的引用,sql语句查询的结果木有存储,
那应该拿着dynastyId再去朝代表里面查询一次(sql语句要写到一个地,并且要用resultmap来赋值)
-->
<select id="selectOne" resultMap="resultMap">
select * from a_demo_king where id = #{id}
</select>
<!-- 拿着皇上表的dynastyId(朝代Id)查询朝代表的记录
paramterType:它是被忽略的,自动的判断是哪个类型;根据值来判断;
值就是association标签中的column(数据库的列)
column是int,基本数据类型,#{可以随便写}
这明明是皇上的Mapper文件,为啥要写朝代呢?
-->
<!-- <select id="selectRelaOne" resultType="com.jinghangzz.mybatis.data.pojo.ADemoDynasty">
select * from a_demo_dynasty where id = #{asdfasfasf}
</select> -->
<!-- 使用联合查询,一次性把结果查询出来
加上autoMapping=true
我们使用的是自动映射;
如果sql语句执行完以后,列名要是相同,会出现值一样的问题
(如何解决重复,要把所有重复的字段起一个别名)
-->
<resultMap type="com.jinghangzz.mybatis.data.pojo.ADemoKing" id="resultMapJoin" autoMapping="true">
<!-- 如果配置了关联关系,那关联字段必须手动赋值 -->
<result column="dynastyId" property="dynastyId"/>
<!-- 为朝代赋值 -->
<association property="dynasty" column="dynastyId" autoMapping="true"
javaType="com.jinghangzz.mybatis.data.pojo.ADemoDynasty">
<!-- 为重复的字段赋值
column:sql语句执行的结果,要的是别名(因为重复)
-->
<result column="dynaName" property="name"/>
</association>
</resultMap>
<!-- 关联查询 -->
<select id="selectJoin" resultMap="resultMapJoin">
select ak.*,ad.*,ad.name as dynaName from a_demo_king ak, a_demo_dynasty ad where ak.dynastyId = ad.id and
ak.id = #{asdfasfa}
</select>
<!-- 查询多个引用(关联关系) -->
<select id="selectRelaList" resultType="com.jinghangzz.mybatis.data.pojo.ADemoKing">
select * from a_demo_king where dynastyId = #{dynastyId}
</select>
</mapper>
测试代码
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import com.jinghangzz.mybatis.data.pojo.ADemoDynasty;
import com.jinghangzz.mybatis.data.pojo.ADemoKing;
import com.jinghangzz.mybatis.data.test.BaseTest;
/**
* 查询皇上操作
* @author TeaBig
*/
public class ADemoKingTest extends BaseTest
{
/**
* 查询一条记录
*/
@Test
public void selectOne()
{
/* 获取链接 */
SqlSession session = this.sqlSessionFactory.openSession(true);
/**
* 查询一条记录
*/
ADemoKing demoKing = session.selectOne("king.selectOne",2);
this.logger.info("皇上:id:{},朝代Id:{},name:{},miaoHao:{},createTime:{}",
demoKing.getId(),demoKing.getDynastyId(),demoKing.getName(),demoKing.getMiaoHao(),demoKing.getCreateTime().toLocaleString());
/* 需求:一个皇上有一个朝代
* 期望可以通过皇上把朝代查询出来;
* ~pojo
* ~
* */
// ADemoDynasty dynasty = demoKing.getDynasty() ;
// this.logger.info("朝代:id:{},name:{},首都:{},createTime:{}",
// dynasty.getId(),dynasty.getName(),dynasty.getCapital(),dynasty.getCreateTime().toLocaleString());
/* 关闭链接 */
if(session != null)
{
session.close();
session = null ;
}
}
/**
* 查询一条记录
*/
@Test
public void selectJoin()
{
/* 获取链接 */
SqlSession session = this.sqlSessionFactory.openSession(true);
/**
* 查询一条记录
*/
ADemoKing demoKing = session.selectOne("king.selectJoin",2);
this.logger.info("皇上:id:{},朝代Id:{},name:{},miaoHao:{},createTime:{}",
demoKing.getId(),demoKing.getDynastyId(),demoKing.getName(),demoKing.getMiaoHao(),demoKing.getCreateTime().toLocaleString());
/* 需求:一个皇上有一个朝代
* 期望可以通过皇上把朝代查询出来;
* ~pojo
* ~
* */
ADemoDynasty dynasty = demoKing.getDynasty() ;
this.logger.info("朝代:id:{},name:{},首都:{},createTime:{}",
dynasty.getId(),dynasty.getName(),dynasty.getCapital(),dynasty.getCreateTime().toLocaleString());
/* 关闭链接 */
if(session != null)
{
session.close();
session = null ;
}
}
}
一的一方看
pojo dynasty
import java.util.Date;
import java.util.List;
/**
* 朝代的POJO
* pojo的类名和表名一样(把_去掉,注意驼峰标识)
* pojo的属性名和表的类名一样
* pojo的对象和表的记录一样;
* @author TeaBig
*/
public class ADemoDynasty
{
private int id;
private String name;
private String content;
private int stYear;
private int edYear;
private int guoZuo;
private String capital;
private byte status;
private Date createTime;
private Date updateTime;
private Date pubTime;
/* 持有多个引用 */
private List<ADemoKing> kingList;
读写器
@Override
public String toString()
{
return "ADemoDynasty [id=" + id + ", name=" + name + ", content=" + content + ", stYear=" + stYear + ", edYear="
+ edYear + ", guoZuo=" + guoZuo + ", capital=" + capital + ", status=" + status + ", createTime="
+ createTime + ", updateTime=" + updateTime + ", pubTime=" + pubTime + "]";
}
}
mapper.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">
<!-- namespace不能为空
mapper:相当于java里面的类
namespace:相当于java里面的包名
-->
<mapper namespace="dynasty">
<!--
查询所有的朝代记录
select标签可以发送select语句
id:唯一标识,当前的mapper文件中,id不能重复
resultType:结果类型;
如果查询的是单条,那返回值的类型就是resultType;
如果查询的是多条,那么返回值的类型是List,List里面放的是resultType
-->
<select id="selectList" resultType="com.jinghangzz.mybatis.data.pojo.ADemoDynasty">
select * from a_demo_dynasty
</select>
<!-- resultMap -->
<resultMap type="com.jinghangzz.mybatis.data.pojo.ADemoDynasty" id="resultMap">
<!-- 关联字段,需要重新赋值,此次的关联字段是id(主键) -->
<id column="id" property="id"/>
<!-- 为皇上集合赋值
在朝代表里面,根据哪个字段可以查询皇上集合
select:根据关联字段,查询皇上的sql语句
如果是当前mapper文件,namespace可以忽略,否则不能忽略
在collection中要使用ofType(指的是包名+类名)
association:要使用javaType(指的是包名+类名)
-->
<collection property="kingList" column="id" ofType="com.jinghangzz.mybatis.data.pojo.ADemoKing"
select="king.selectRelaList"/>
</resultMap>
<select id="selectOne" parameterType="map" resultMap="resultMap">
select * from a_demo_dynasty where id = #{id}
</select>
<!-- 为联合查询赋值 -->
<resultMap type="com.jinghangzz.mybatis.data.pojo.ADemoDynasty" id="resultMapJoin" autoMapping="true">
<!-- 关联字段需要额外赋值 -->
<id column="id" property="id"/>
<result column="dynaName" property="name"/>
<!-- 如果sql语句查询的列别名有重复的,需要起别名 -->
<!-- 为皇上集合赋值
在朝代表里面,根据哪个字段可以查询皇上集合
select:根据关联字段,查询皇上的sql语句
如果是当前mapper文件,namespace可以忽略,否则不能忽略
在collection中要使用ofType(指的是包名+类名)
association:要使用javaType(指的是包名+类名)
-->
<collection property="kingList" column="id" ofType="com.jinghangzz.mybatis.data.pojo.ADemoKing" autoMapping="true">
<id column="akId" property="id"/>
<!-- 重复的列,要起别名 -->
<result property="name" column="akName"/>
</collection>
</resultMap>
<!-- 使用联合查询来实现 -->
<select id="selectJoin" resultMap="resultMapJoin">
select ad.*,ak.*,ad.name as dynaName,ak.name as akName,ak.id as akId from a_demo_king ak, a_demo_dynasty ad where ak.dynastyId = ad.id and
ad.id = #{id} ;
</select>
<!-- 拿着皇上表的dynastyId(朝代Id)查询朝代表的记录
paramterType:它是被忽略的,自动的判断是哪个类型;根据值来判断;
值就是association标签中的column(数据库的列)
column是int,基本数据类型,#{可以随便写}
这明明是皇上的Mapper文件,为啥要写朝代呢?
-->
<select id="selectRelaOne" resultType="com.jinghangzz.mybatis.data.pojo.ADemoDynasty">
select * from a_demo_dynasty where id = #{asdfasfasf}
</select>
</mapper>
测试代码
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import com.jinghangzz.mybatis.data.pojo.ADemoDynasty;
import com.jinghangzz.mybatis.data.pojo.ADemoKing;
import com.jinghangzz.mybatis.data.test.BaseTest;
/**
* 测试朝代的一方
* @author TeaBig
*
*/
public class ADemoDynastyTest extends BaseTest
{
/**
* 查询一条记录
*/
@Test
public void selectOne()
{
/* 获取链接 */
SqlSession session = this.sqlSessionFactory.openSession(true);
/**
* 查询一条记录
*/
ADemoDynasty dynasty = session.selectOne("dynasty.selectOne",10);
this.logger.info("朝代:id:{},name:{},首都:{},createTime:{}",
dynasty.getId(),dynasty.getName(),dynasty.getCapital(),dynasty.getCreateTime().toLocaleString());
/* 需求:一个朝代有多个皇上
* 期望可以通过皇上把朝代查询出来;
* ~pojo
* ~
* */
List<ADemoKing> kingList = dynasty.getKingList() ;
kingList.forEach( demoKing ->
{
this.logger.info("皇上:id:{},朝代Id:{},name:{},miaoHao:{},createTime:{}",
demoKing.getId(),demoKing.getDynastyId(),demoKing.getName(),demoKing.getMiaoHao(),demoKing.getCreateTime().toLocaleString());
});
/* 关闭链接 */
if(session != null)
{
session.close();
session = null ;
}
}
/**
* 查询一条记录
*/
@Test
public void selectJoin()
{
/* 获取链接 */
SqlSession session = this.sqlSessionFactory.openSession(true);
List<ADemoDynasty> dynastyList = session.selectList("dynasty.selectJoin",10);
dynastyList.forEach( dynasty -> {
this.logger.info("朝代:id:{},name:{},首都:{},createTime:{}",
dynasty.getId(),dynasty.getName(),dynasty.getCapital(),dynasty.getCreateTime().toLocaleString());
/* 需求:一个朝代有多个皇上
* 期望可以通过皇上把朝代查询出来;
* ~pojo
* ~
* */
List<ADemoKing> kingList = dynasty.getKingList() ;
kingList.forEach( demoKing ->
{
this.logger.info("皇上:id:{},朝代Id:{},name:{},miaoHao:{},createTime:{}",
demoKing.getId(),demoKing.getDynastyId(),demoKing.getName(),demoKing.getMiaoHao(),demoKing.getCreateTime().toLocaleString());
});
});
/* 关闭链接 */
if(session != null)
{
session.close();
session = null ;
}
}
}
mybatis.cfg.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>
<!-- 全局的开关,设置的意思 -->
<settings>
<!-- 打开延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 都关闭,按需要加载;不管是哪处版本,都是false,3,4,1以前,默认值为true,之后是false -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!-- 配置了一堆环境;jdbc的环境
default:默认的环境,配置environment的id
-->
<environments default="my">
<!-- 配置一个单数 -->
<environment id="my">
<!-- 事务管理器:专门用来管理事务的 -->
<transactionManager type="JDBC"/>
<!-- 数据源
pooled:连接池;放的是一个一个的Connection;
数据源包含了java连接数据库的各种信息
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 一定一定一定要把映射文件包含起来 -->
<mappers>
<!-- 映射文件的路径,classpath -->
<mapper resource="com/jinghangzz/mybatis/data/pojo/ADemoDynastyMapper.xml"/>
<mapper resource="com/jinghangzz/mybatis/data/pojo/ADemoKingMapper.xml"/>
</mappers>
</configuration>
总结:查询多张表(此例2张表)要考虑是使用联合查询(一条sql语句),还是通过关联字段(多条sql语句)进行查询,两种方法都需要一个resultMap
一的一方
通过关联字段进行查询
<!-- resultMap -->
<!-- 通过关联字段进行查询 -->
<!-- 要发送两条sql语句,
先查询皇上,
拿着dynastyId(朝代Id要去朝代表查询朝代)
-->
<!-- 查询一条记录
resultType:指定的皇上,里面有一个朝代的引用,sql语句查询的结果木有存储,
那应该拿着dynastyId再去朝代表里面查询一次(sql语句要写到一个地,并且要用resultmap来赋值)
-->
<!-- 1、通过id查找皇上 -->
<select id="selectOne" resultMap="resultMap">
select * from a_demo_king where id = #{id}
</select>
<!-- 2、关联字段赋值 -->
<resultMap type="com.jinghangzz.mybatis.data.pojo.ADemoKing" id="resultMap">
<!-- 如果配置了关联关系,那关联字段必须手动赋值 -->
<result column="dynastyId" property="dynastyId"/>
<!-- 联合:
property:pojo的属性名
column:数据库的列名;为dynasty赋值的时候,需要用到皇上表的哪列?
javaType:dynasty到底是哪个类型(java里面的); 包名+类名
select:拿着column执行哪个sql语句,应该可以查询到dynasty;执行sql语句的id;
sql语句的id,应该是namespace+sql语句的id(如果sql语句的就在当前文件中,那namespace可以忽略)
fetchType:抓取策略;lazy:延迟加载;eager:默认就是积极加载;
如果全局开头木有打开,只能此标签才会起作用,其它的标签不起作用;
建议:(延迟加载开关都打开)
延迟加载只能在一个JVM里面生效;微服务编程:(dubbo,SPringCloud,延迟加载不起作用)
-->
<association property="dynasty" column="dynastyId" javaType="com.jinghangzz.mybatis.data.pojo.ADemoDynasty"
select="dynasty.selectRelaOne" />
</resultMap>
<!-- 3、通过关联字段查找朝代 -->
<select id="selectRelaOne" resultType="com.jinghangzz.mybatis.data.pojo.ADemoDynasty">
select * from a_demo_dynasty where id = #{asdfasfasf}
</select>
通过联合查询进行查询
<!-- 2、使用联合查询,一次性把结果查询出来
加上autoMapping=true
我们使用的是自动映射;
如果sql语句执行完以后,列名要是相同,会出现值一样的问题
(如何解决重复,要把所有重复的字段起一个别名,或者在数据库中创建表单时就硬性要求,表单的字段不能重复)
-->
<resultMap type="com.jinghangzz.mybatis.data.pojo.ADemoKing" id="resultMapJoin" autoMapping="true">
<!-- 如果配置了关联关系,那关联字段必须手动赋值 -->
<result column="dynastyId" property="dynastyId"/>
<!-- 为朝代赋值 -->
<association property="dynasty" column="dynastyId" autoMapping="true"
javaType="com.jinghangzz.mybatis.data.pojo.ADemoDynasty">
<!-- 为重复的字段赋值
column:sql语句执行的结果,要的是别名(因为重复)
-->
<result column="dynaName" property="name"/>
</association>
</resultMap>
<!-- 1、关联查询 -->
<select id="selectJoin" resultMap="resultMapJoin">
select ak.*,ad.*,ad.name as dynaName from a_demo_king ak, a_demo_dynasty ad where ak.dynastyId = ad.id and
ak.id = #{asdfasfa}
</select>
多的一方
通过关联字段进行查询
<!-- 1、查询朝代 -->
<select id="selectOne" parameterType="map" resultMap="resultMap">
select * from a_demo_dynasty where id = #{id}
</select>
<!-- 2、关联字段赋值 时集合的话使用collection -->
<resultMap type="com.jinghangzz.mybatis.data.pojo.ADemoDynasty" id="resultMap">
<!-- 关联字段,需要重新赋值,此次的关联字段是id(主键) -->
<id column="id" property="id"/>
<!-- 为皇上集合赋值
在朝代表里面,根据哪个字段可以查询皇上集合
select:根据关联字段,查询皇上的sql语句
如果是当前mapper文件,namespace可以忽略,否则不能忽略
在collection中要使用ofType(指的是包名+类名)
association:要使用javaType(指的是包名+类名)
-->
<collection property="kingList" column="id" ofType="com.jinghangzz.mybatis.data.pojo.ADemoKing"
select="king.selectRelaList"/>
</resultMap>
<!-- 3、通过关联字段进行查询 -->
<!-- 查询多个引用(关联关系) -->
<select id="selectRelaList" resultType="com.jinghangzz.mybatis.data.pojo.ADemoKing">
select * from a_demo_king where dynastyId = #{dynastyId}
</select>
通过联合查询进行查询
<!-- 1、使用联合查询来实现 -->
<select id="selectJoin" resultMap="resultMapJoin">
select ad.*,ak.*,ad.name as dynaName,ak.name as akName,ak.id as akId from a_demo_king ak, a_demo_dynasty ad where ak.dynastyId = ad.id and
ad.id = #{id} ;
</select>
<!-- 2、为联合查询赋值 -->
<resultMap type="com.jinghangzz.mybatis.data.pojo.ADemoDynasty" id="resultMapJoin" autoMapping="true">
<!-- 关联字段需要额外赋值 -->
<id column="id" property="id"/>
<result column="dynaName" property="name"/>
<!-- 如果sql语句查询的列别名有重复的,需要起别名 -->
<!-- 为皇上集合赋值
在朝代表里面,根据哪个字段可以查询皇上集合
select:根据关联字段,查询皇上的sql语句
如果是当前mapper文件,namespace可以忽略,否则不能忽略
在collection中要使用ofType(指的是包名+类名)
association:要使用javaType(指的是包名+类名)
-->
<collection property="kingList" column="id" ofType="com.jinghangzz.mybatis.data.pojo.ADemoKing" autoMapping="true">
<id column="akId" property="id"/>
<!-- 重复的列,要起别名 -->
<result property="name" column="akName"/>
</collection>
</resultMap>