在之前的博客当中都是单表的增删改查操作,现在考虑一个稍微复杂一点也更贴近真实情况的问题。关联查询。关联查询分为四种情况:
- 一对一关联查询
- 一对多关联查询
- 多对一关联查询
- 多对多关联查询
本篇博客先考虑一种情况,一对多关联查询。以国家和部长之间的一对多关系进行演示。先看整个项目的目录结构:
1、定义实体
在定义实体的时候,若定义的是双向关联,也就是说双方的属性中都有对象的属性作为域属性出现,那么在定义各自的toString()方法时候需要注意,只让一方可以输出为另外一方即可,否则的话会形成递归调用。这种情况可以参考博客:
https://blog.csdn.net/SDDDLLL/article/details/83268054
我们知道一个国家当中会有很多个部长,所以国家和部长之间的关系是一对多关系。
首先是国家类:
public class Country {
private Integer cid;
private String cname;
//关联属性
private Set<Minister> ministers;
//getter和serter方法
//toString方法
}
然后是部长类:
public class Minister {
private Integer mid;
private String mname;
//getter和seter
//toString方法
}
2、定义数据库表
首先是国家表:country
其次是部长表:minister
3、定义ICountryDao接口
我们通过国家的id选出这个国家,以及这个国家的部长。
import com.test.beans.Country;
public interface ICountryDao {
Country selectCountryById(int cid);
}
4、定义测试类
public class MyTest {
//由于增删改查都需要ICountryDao ,所以将其设置2全局变量。
private ICountryDao dao ;
private SqlSession sqlSession;
@Before
public void testBefore(){
sqlSession = MybatisUtil.getSqlSession();
dao = sqlSession.getMapper(ICountryDao.class);
}
@After
public void after(){
if(sqlSession!=null){
sqlSession.close();
}
}
@Test
public void testSelectStuByCondition() {
Integer a=new Integer(2);
Country country=dao.selectCountryById(a);
System.out.println(country);
}
}
5、定义映射文件
A:多表链接查询方式
<?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.test.dao.ICountryDao">
<resultMap type="Country" id="countryMapper">
<id column="cid" property="cid"/>
<result column="cname" property="cname"/>
<collection property="ministers" ofType="Minister">
<id column="mid" property="mid"/>
<result column="mname" property="mname"/>
</collection>
</resultMap>
<select id="selectCountryById" resultMap="countryMapper">
select cid,cname,mid,mname
from country,minister
where
countryid = cid and cid = #{xxx}
</select>
</mapper>
注意:1、由于此时返回的结果是部长集合,resultMap要单独处理
2、此时即使字段名与属性名字相同,在<resultMap/>也要写出他们的映射关系。因为框架是根据这个<resultMap/>封装对象的。
3、在映射文件中使用<collection/>标签体现出两个实体对象间的关联关系。这两个属性的意义是:
- property:指定关联属性,也就是country类中的集合属性,类中的字段名
- ofType:集合属性的泛型类型(也就是minister类)
B:多表单独查询方式
多表连接查询方式是将多张表进行连接,链接为一张表后进行查询。其查询的本质是一张表。多表单独查询方式是多张表各自查询各自的相关内容,需要多张表的联合数据了,则将主表的查询结果联合其他表的查询结果,封装为一个对象。
当然,这多个查询是可以跨越多个映射文件的,也就是跨越多个namespace的。在使用其他namespace的查询时,添加上其所在的namespace即可。
<?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.test.dao.ICountryDao">
<select id="selectMinisterById" resultType="Minister">
select mid,mname
from minister
where
countryid=#{ooo}
</select>
<resultMap type="Country" id="countryMapper">
<id column="cid" property="cid"/>
<result column="cname" property="cname"/>
<collection
property="ministers"
ofType="Minister"
select="selectMinisterById"
column="cid"/>
</resultMap>
<select id="selectCountryById" resultMap="countryMapper">
select cid,cname
from country
where
cid = #{xxx}
</select>
</mapper>
我们可以看到我们在<collection/>中又进行了一次查询,其属性的数据来自于另一个查询<selectMinisterById>(不是根据图,根据代码)。而该查询的动态参数country=#{ooo}的值来自于查询<selectCountryById/>的查询结果cid
6、其他类中的代码
1、MybatisUtil
public class MybatisUtil {
//单例模式创建sqlSession.要设置成静态的
public static SqlSession getSqlSession(){
SqlSessionFactory factory = null;
try {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
if(factory==null){
factory=new SqlSessionFactoryBuilder().build(is);
}
SqlSession sqlSession = factory.openSession();
return sqlSession;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
2、mybatis.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="jdbc.properties"/>
<!-- 别名的定义 -->
<typeAliases>
<!-- 将保内的所有类的名字作为别名 -->
<package name="com.test.beans"/>
</typeAliases>
<!-- 配置运行环境 -->
<environments default="testEM">
<environment id="testEM">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 注册映射文件 -->
<mappers>
<mapper resource="com/test/dao/mapper.xml"/>
</mappers>
</configuration>
3、jdbc.properties
jdbc.driver= com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test1
jdbc.user=root
jdbc.password=root
4、log4j.properties
##define an appender named console
log4j.appender.console=org.apache.log4j.ConsoleAppender
#The Target value is System.out or System.err
log4j.appender.console.Target=System.out
#set the layout type of the apperder
log4j.appender.console.layout=org.apache.log4j.PatternLayout
#set the layout format pattern
log4j.appender.console.layout.ConversionPattern=[%-5p] %m%n
##define a logger
##.test is mybatis.xml namespace
log4j.logger.com.test.dao.ICountryDao=debug,console