MyBatis学习笔记(五)一对一或多对一的关联查询

首发于我的博客 和尚的博客
本文讲解,mybatis中一对一、多对一的关联查询,类名的别名方式应用


源码获取github

1.关系型数据库中表和表之间的关系

  • 一对一:外键唯一
  • 一对多和多对一:只是站在角度不同而已,但是外键一定在多方
    • 自身一对多和多对一
  • 外键:
    • 逻辑关联
    • 物理关联
  • 多对多:一定是通过中间表维护

2.java类中如何表示上述几种关系

UML:依赖/关联/组合

eg:用户和角色的关系

一个用户对应一个角色,一个角色可以多个用户

用户ID 用户 角色ID
100 悟空 999
200 八戒 999

1. 查询100的用户信息,那么它一定对 一个角色信息
2. List

public class User{
//关联对象 
public Role role;//一对一,多对一 
}
public class Role{
    private List<User> userList;    //一个角色里可以对应很多用户
}

3.三种方式

  1. 传统模式:两个SQL语句,先在一个表查出数据,然后把其中的id作为另外一个表的where,再查数据
  2. select方式:在映射文件中,一个查出的结果集中,调用另外一个select语句实现查询
  3. 连接查询:也就是SQL语句连接查询(个人还是喜欢这种)

4.知识小点

  1. 配置关联对象用<association>这样查出来的就是一个对象
  2. 配置集合就用<collection>

5.目录结构

6.数据库属性文件

jdbc.properties

代码同上篇

7.核心配置文件

mybatis-config.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"/>
    <!--自定义设置类型的别名,也就是resultMap里的type,避免包名已修改,在映射文件里修改多处地方-->
    <typeAliases>
        <!-- 方式一、com.hs.model.Skill这个类设置了别名hs,之后要用这个的话,直接写hs -->
        <!--<typeAlias type="com.hs.model.Skill" alias="hs"/> -->
        <!-- 方式二、com.hs.model这个包下的类,要用的时候直接写类名,比如用com.hs.model.Skill,直接写Skill -->
        <package name="com.hs.model"/>
    </typeAliases>
    <!--配置数据库的环境-->
    <environments default="development">
        <environment id="development">
            <!--事务管理器:保证数据的完整性和一致性   关键信息  -->
            <!--框架:默认情况下CUD操作需要  手动提交事务
            (如同在Navicat中表中输入了数据,没有点那个小√,就是没有提交事务,
            但是输入insert语句,就自动提交事务了)  -->
            <transactionManager type="JDBC" />
            <!--使用的是连接池:百度java如何实行连接池的原理?  -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.mysql.driver}" />  <!--获取值,${属性文件里的变量名},也可以直接写值-->
                <property name="url" value="${jdbc.mysql.url}" />  <!--获取值,${属性文件里的变量名},也可以直接写值-->
                <property name="username" value="${jdbc.mysql.username}" /> <!--获取值,${属性文件里的变量名},也可以直接写值-->
                <property name="password" value="${jdbc.mysql.password}" /> <!--获取值,${属性文件里的变量名},也可以直接写值-->
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件 ,也就是含sql语句的文件-->
    <mappers>
         <!--告知映射文件方式1,一个一个的配置-->
        <mapper resource="com/hs/model/UserMapper.xml"/>
        <mapper resource="com/hs/model/RoleMapper.xml"/>
        <!-- 告知映射文件方式2,自动扫描包内的Mapper接口与配置文件 -->
        <!--<package name="com.hs.model"/>-->
    </mappers>
</configuration>

8.封装好的工具类

MyBatisUtils.java

同上篇

9.持久化类

Role.java

package com.hs.model;

public class Role {

    private Integer role_id;
    private String role_name;
    private String role_key;
    private Integer status;

    public Integer getRole_id() {
        return role_id;
    }

    public void setRole_id(Integer role_id) {
        this.role_id = role_id;
    }

    public String getRole_name() {
        return role_name;
    }

    public void setRole_name(String role_name) {
        this.role_name = role_name;
    }

    public String getRole_key() {
        return role_key;
    }

    public void setRole_key(String role_key) {
        this.role_key = role_key;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    @Override
    public String toString() {
        return "Role{" +
                "role_id=" + role_id +
                ", role_name='" + role_name + '\'' +
                ", role_key='" + role_key + '\'' +
                ", status=" + status +
                '}';
    }
}

User.java

package com.hs.model;

import java.util.Date;

public class User {

    private Integer user_id;
    private String account;
    private String password;
    private String user_name;
    private Integer status;
    private Date login_time;
    private String ip;
    private Integer fk_role_id;
    //关联对象 一对一或多对一,一个用户对应一个角色
    private Role role;

    public Integer getUser_id() {
        return user_id;
    }

    public void setUser_id(Integer user_id) {
        this.user_id = user_id;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUser_name() {
        return user_name;
    }

    public void setUser_name(String user_name) {
        this.user_name = user_name;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public Date getLogin_time() {
        return login_time;
    }

    public void setLogin_time(Date login_time) {
        this.login_time = login_time;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public Integer getFk_role_id() {
        return fk_role_id;
    }

    public void setFk_role_id(Integer fk_role_id) {
        this.fk_role_id = fk_role_id;
    }

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

    @Override
    public String toString() {
        return "User{" +
                "user_id=" + user_id +
                ", account='" + account + '\'' +
                ", password='" + password + '\'' +
                ", user_name='" + user_name + '\'' +
                ", status=" + status +
                ", login_time=" + login_time +
                ", ip='" + ip + '\'' +
                ", fk_role_id=" + fk_role_id +
                ", role=" + role +
                '}';
    }
}

10.XML映射文件

RoleMapper.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 namespace="com.hs.dao.RoleDao"><!--命名空间规则
传统模式:(持久化类(实体化Bean)的类名全路径com.hs.Skill)
接口代理模式:接口的全路径r-->
    <!--type直接用的类名别名方式,在核心配置文件里设置了的-->
    <resultMap type="Role" id="BaseResultMapper">
        <id column="role_id" property="role_id"/>
        <result column="role_name" property="role_name"/>
        <result column="role_key"  property="role_key"/>
        <result column="status"  property="status"/>
    </resultMap>
    <sql id="sys_role_columns">
        role_id,role_name,role_key,status
    </sql>
    <sql id="sys_role_columns_alias">
        ${alias}.role_id,${alias}.role_name,${alias}.role_key,${alias}.status
    </sql>
    <select id="getRoleByPk" parameterType="_int" resultMap="BaseResultMapper">
        select <include refid="sys_role_columns"/>
        from sys_role
        where role_id = #{role_id}
    </select>
</mapper>

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">
<!--namespace=命名空间,唯一不重复-->
<mapper namespace="com.hs.dao.UserDao"><!--命名空间规则
传统模式:(持久化类(实体化Bean)的类名全路径com.hs.Skill)
接口代理模式:接口的全路径r-->
    <!--type直接用的类名别名方式,在核心配置文件里设置了的-->
    <resultMap id="BaseResultMapper" type="User">
        <id column="user_id" property="user_id" />
        <result column="account" property="account" />
        <result column="passwrod" property="pasword" />
        <result column="user_name" property="user_name" />
        <result column="status" property="status" />
        <result column="login_time" property="login_time" />
        <result column="ip" property="ip" />
        <result column="fk_role_id" property="fk_role_id" />
    </resultMap>
    <resultMap id="SimpleResultMapper" type="User" extends="BaseResultMapper"> <!-- extends继承了BaseResultMapper,同java继承一样 -->
        <!--配置关联对象-->
        <!--在结果集中找到fk_role_id字段,然后再传值给命名空间com.hs.dao.RoleDao下的getRoleByPk语句进行查询(找到要执行的SQL语句),最后返回role(对象的属性),它的类型是com.hs.model.Role-->
        <association property="role" javaType="Role" column="fk_role_id" select="com.hs.dao.RoleDao.getRoleByPk"/>
        <collection property=""
    </resultMap>
    <sql id="sys_user_colums">
        user_id,account,password,user_name,status,login_time,ip,fk_role_id
    </sql>
    <sql id="sys_user_colums_alias">
        ${alias}.user_id,${alias}.account,${alias}.password,${alias}.user_name,${alias}.status,${alias}.login_time,${alias}.ip,${alias}.fk_role_id
    </sql>

    <select id="getUserByPk01" parameterType="_int" resultMap="BaseResultMapper">
        select <include refid="sys_user_colums"/>
        from sys_user
        where user_id = #{user_id}
    </select>
    <select id="getUserByPk02" parameterType="_int" resultMap="SimpleResultMapper">
        select <include refid="sys_user_colums"/>
        from sys_user
        where user_id = #{user_id}
    </select>
    <resultMap id="JoinResultMapper" type="User" extends="BaseResultMapper">
        <!--关联对象-->
        <!--resultMap引用别人的结果集(命名空间+"."+id),或者自己在下面写结果集处理-->
        <association property="role" javaType="Role" resultMap="com.hs.dao.RoleDao.BaseResultMapper">
            <!-- <id column="role_id" property="role_id"/>
            <result column="role_name" property="role_name"/>
            <result column="role_key" property="role_key"/>
            <result column="status" property="status"/> -->
        </association>
    </resultMap>
    <select id="getUserByLeftJoin" parameterType="_int" resultMap="JoinResultMapper">
        select
            <!-- 调用别名式的SQL代码,给alias赋值为u -->
            <include refid="sys_user_colums_alias">
                <property name="alias" value="u"/>
            </include>
            ,
            <include refid="com.hs.dao.RoleDao.sys_role_columns_alias">
                <property name="alias" value="r"/>
            </include>
        from sys_user u
        left join sys_role r on u.fk_role_id = r.role_id
        where
            u.user_id = #{user_id}
    </select>
</mapper>

11.接口

UserDao.java

package com.hs.dao;

import com.hs.model.User;

public interface UserDao {

    /**
     * 通过id查询user表的所有信息,再用它的外键传递给另外一个表进行查询数据
     * @param user_id
     * @return
     */
    User getUserByPk01(int user_id);

    /**
     * 用关联对象方式、select方式代取传统的模式
     * @param user_id
     * @return
     */
    User getUserByPk02(int user_id);

    /**
     * 在SQL语句写连接方式的查询
     * @param user_id
     * @return
     */
    User getUserByLeftJoin(int user_id);
}

RoleDao.java

package com.hs.dao;

import com.hs.model.Role;

public interface RoleDao {

    /**
     * 通过role_id查询role表信息
     * @param role_id
     * @return
     */
    Role getRoleByPk(int role_id);

}

12.测试类

MyBatisTest.java

package com.hs.test;

import com.hs.dao.RoleDao;
import com.hs.dao.UserDao;
import com.hs.model.Role;
import com.hs.model.User;
import com.hs.util.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

/**
 * 接口代理模式实现操作,在xxDao接口中,定义方法:  sql语句返回的结果类型 sql语句的id(要传的值);
 * 不用写实现类,直接写测试类,具体实现见测试类
 * sql的映射文件的命名空间跟接口的全路径一致
 * 可以根据接口的返回类型自动判断使用selectOne还是selectList eg:返回的是一个对象的为one,返回的是list的就是list,如果是List<Bean>,也是list
 */
public class MyBatisTest {

    /**
     * 一对一的三种方式
     */

    /**
     * 方式一:利用两个SQL语句,先在user查出外键,然后再在role表进行查询
     */
    @Test
    public void getAllByFk01(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlsession();
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            User user = userDao.getUserByPk01(-999);
//          获取对应的外键信息
            if (user.getFk_role_id()!=null) {
                RoleDao roleDao = sqlSession.getMapper(RoleDao.class);
                Role role = roleDao.getRoleByPk(user.getFk_role_id());
                //建立关系
                user.setRole(role);
            }
            System.out.println(user);
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }

    /**
     * 用关联对象方式、select方式代取传统的模式
     */
    @Test
    public void getAllBySelect(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlsession();
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            User user = userDao.getUserByPk02(-999);
            System.out.println(user);
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }

    /**
     * SQL语句连接方式查询
     */
    @Test
    public void getUserByLeftJoin(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlsession();
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            User user = userDao.getUserByLeftJoin(-999);
            System.out.println(user);
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }
}
发布了44 篇原创文章 · 获赞 31 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_39707130/article/details/81459010