Mybatis中的多表查询 多对一,一对多

示例:用户和账户
  一个用户可以有多个账户
  一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
  1、建立两张表:用户表,账户表
    让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
  2、建立两个实体类:用户实体类和账户实体类
    让用户和账户的实体类能体现出来一对多的关系
  3、建立两个配置文件
    用户的配置文件
    账户的配置文件
  4、实现配置:
    当我们查询用户时,可以同时得到用户下所包含的账户信息
    当我们查询账户时,可以同时得到账户的所属用户信息

定义账户信息的实体类Account 

public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    
    /*get  set toString*/
}

User

public class User implements Serializable {

    private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;
  /*get  set toString*/
}

用户的持久层接口IuserDao:

public interface IUserDao {
    List<User> findAll();
    User findUserById (Integer userId);
}

IAccountDao:

public interface IAccountDao {
    /**
     * 查询所有账户
     * @return
     */
    List<Account> findAll();
}

映射配置文件IUserDao.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.mkl.dao.IUserDao">

    <!-- 查询所有 -->
    <select id="findAll" resultType="user">
        select * from user;
    </select>

    <!-- 根据id查询用户 -->
    <select id="findUserById" parameterType="int" resultType="user">
        select * from user where id = #{uid}
    </select>

</mapper>

IAccountDao.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.mkl.dao.IAccountDao">
    <!-- 查询所有账户信息-->
    <select id="findAll" resultType="Account">
        select * from account;
    </select>
</mapper>

主配置文件:

<?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-->
    <properties resource="jdbcConfig.properties"></properties>

    <!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
    <typeAliases>
        <package name="com.mkl.domain"></package>
    </typeAliases>

    <!--配置环境-->
    <environments default="mysql">
        <!-- 配置mysql的环境-->
        <environment id="mysql">
            <!-- 配置事务 -->
            <transactionManager type="JDBC"></transactionManager>

            <!--配置连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </dataSource>
        </environment>
    </environments>
    <!-- 配置映射文件的位置 -->
    <mappers>
        <package name="com.mkl.dao"></package>
    </mappers>
</configuration>

一对一查询(多对一) 

需求 :

查询所有账户信息,关联查询对应用户信息。 

注意: 

因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询

如果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。 

方式一 :

编写 Sql 语句 

实现查询账户信息时,也要查询账户所对应的用户信息。 

SELECT    account.*,   user.username,   user.address   

FROM   account,   user   

WHERE  account.uid = user.id ;

查询结果

 定义 AccountUser 类 

为了能够封装上面 SQL 语句的查询结果,定义 AccountCustomer 类中要包含账户信息同时还要包含用户信息

所以我们要在定义 AccountUser 类时可以继承Account 类。 

public class AccountUser extends Account implements Serializable {
    /*继承了Account中的信息*/
    private  String username;
    private  String address;
    
    /*get set super.toString+toString*/
}

账户的持久层接口 IAccountDao中添加方法

    /**
     * 查询所有账户 同时获取到当前账户的所属用户信息: 用户名称  地址
     * @return
     */
    List<AccountUser> findAllEnhance();

在 IAccountDao.xml 文件中添加相应的的查询配置信息 

 <!--增强的查询所有账户信息, 包含账户信息, 用户名称 地址-->
 <select id="findAllEnhance" resultType="AccountUser">
     select account.*, user.username as username,user.address as address 
   from account,user
   where user.id=account.uid;
</select>

添加测试方法

   /**
     * 测试增强的查询所有账户信息, 包含账户信息, 用户名称 地址
     */
    @Test
    public void testFindAllAccountEnhance(){
        List<AccountUser> accountUsers=accountDao.findAllEnhance ();
        System.out.println (accountUsers);
    }

 方式二(常用):

让用户和账户的实体类能体现出来一对多的关系

使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。 

一对一的关系映射 使用association标签

在从表实体类Account中添加主表实体的对象引用

从表实体应该包含一个主表实体的对象引用

        //从表实体应该包含一个主表实体的对象引用
        private User user;

        /*get set*/

IAccountDao 接口中的方法 

   /**
     * 查询所有账户  同时获取账户的所属用户信息
     * @return
     */
    List<Account> findAll();

修改IAccountDao.xml 文件 

<!--定义封装account和user的resultMap-->
    <resultMap id="accountUserMap" type="account">
        <id column="aid" property="id"></id>
        <result column="uid" property="uid"></result>
        <result column="money" property="money"></result>
        <!--一对一的关系映射, 配置封装User的内容-->
        <association property="user" javaType="user">
            <id column="id" property="id"></id>
            <result column="username" property="username"></result>
            <result column="sex" property="sex"></result>
            <result column="birthday" property="birthday"></result>
            <result column="address" property="address"></result>
        </association>
    </resultMap>

    <!-- 查询所有账户信息-->  
    <select id="findAll" resultMap="accountUserMap">
        select user.*,account.id as aid, account.uid ,account.money
        from account,user
        where user.id=account.uid;
    </select>

一对多查询 

需求:

查询所有用户信息及用户关联的账户信息。 

分析: 

用户信息和他的账户信息为一对多关系

并且查询过程中如果用户没有账户信息,此时也要将用户信息查询出来,我们想到了 左外连接查询 比较合适。 

编写 SQL 语句 :

SELECT user.*, account.id AS aid,account.uid,account.money
FROM USER
LEFT JOIN account
ON user.id = account.uid ;

User 类加入 List<Account> 

一对多关系映射, 主表实体应该包含从表实体的集合引用

private List<Account> accounts;

/*get set*/

持久层接口IUserDao中的查询方法 

/** 
 * 查询所有用户,同时获取出每个用户下的所有账户信息  
*
@return */
List<User> findAll();

修改持久层接口的映射配置文件IUserDao.xml

  <resultMap id="userMap" type="user">
    <id column="id" property="id"></id>
    <result column="username" property="username"/>
    <result column="address" property="address"/>
    <result column="sex" property="sex"/>
    <result column="birthday" property="birthday"/>
    <!--封装该用户下的账户信息到List-->
    <!--collection是用于建立一对多中集合属性的对应关系, ofType用于指定集合元素的数据类型-->
    <collection property="accounts" ofType="account">
      <id column="aid" property="id"/>
      <result column="uid" property="uid"/>
      <result column="money" property="money"/>
    </collection>
  </resultMap>

<!-- 查询所有 --> <!--<select id="findAll" resultType="user">--> <select id="findAll" resultMap="userMap"> SELECT user.*, account.id AS aid,account.uid,account.money FROM USER LEFT JOIN account ON user.id = account.uid ; </select>

collection   用于建立一对多中集合属性的对应关系  表示关联查询结果集 

  property="accounts"  关联查询的结果集存储在 User 对象的上哪个属性。 

  ofType="account"   指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。  

原文地址:https://www.cnblogs.com/mkl7/p/10755218.html