spring中的关联映射

  • mybatis的映射关系
  • 一对一
  • 加载关联对象的两种方式
  • 代码
  • IdCard
  • Person
  • IdCardMapper.xml
  • PersonMapper.xml
  • MyBatisUtils
  • mybatis-config.xml
  • Test
  • Test1
  • 数据库的表
  • 一对多的关联映射
  • 数据库中的表
  • User
  • Orders
  • UserMapper.xml
  • mybatis-config.xml
  • Test2
  • 多对多
  • 数据库
  • Orders
  • Product
  • OrdersMapper.xml
  • ProductMapper.xml
  • Test3
  • mybatis-config.xml


mybatis的映射关系

  • 在开发中对数据库操作经常用到多张表,这在面向对象中涉及到对象与对象之间的关联关系,而mybatis提供了关联映射,通过关联映射就可以很好的处理对象与对象之间的关联关系,
  • 在关系型数据库中,多表之间存在着三种关联关系,分别为一对一,一对多,多对多,
  • 在java中,通过对象也可以进行关联关系描述,如下图所示,

一对一

在mybatis中怎末解决一对一的问题呢,在resultMpa元素中包含一个assocation的子元素,通过它可以处理一对一的关联关系

  • associatin元素中属性
  • property:指定映射到实体类对象属性,与表字段一一对应。
  • column:指定表中对应的字段
  • javaType:指定映射到实体对象属性的类型
  • select:指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询
  • fetchType:指定在关联查询时是否启用延迟加载,该属性由lazy和eager两个属性值,默认值时lazy(即默认关联映射延迟加载)

加载关联对象的两种方式

  • 嵌套查询和嵌套结果

代码

IdCard

package com.yzb.chapter09;

public class IdCard {
    private Integer id;
    private String code;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public String toString() {
        return "IdCard{" +
                "id=" + id +
                ", code='" + code + '\'' +
                '}';
    }
}

Person

package com.yzb.chapter09;

public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private String sex;
    private IdCard card;//个人关联的证件

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
         = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public IdCard getCard() {
        return card;
    }

    public void setCard(IdCard card) {
        this.card = card;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                ", card=" + card +
                '}';
    }
}

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">
<!-- namespace表示命名空间 -->
<mapper namespace="com.yzb.chapter09.IdCardMapper">
    <!--根据id查询证件信息-->
    <select id="findCodeById" parameterType="Integer" resultType="com.yzb.chapter09.IdCard">
        select * from tb_idcard where id = #{id}
    </select>
</mapper>

PersonMapper.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.yzb.chapter09.PersonMapper">
    <!--嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型-->
   <select id="findPersonById" parameterType="Integer" resultMap="IdCardWithPersonResult">
       select * from tb_person where id= #{id}
   </select>
    <resultMap id="IdCardWithPersonResult" type="com.yzb.chapter09.Person">
        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <!--使用一对一:assocation使用select属性引入另一条SQL语句-->
        <!--property指定的是Person类中定义的IdCard类型的属性名,column是定义在与person对应的数据库表中的IdCard的引入的主键 javaType对应的是映射的IdCard类的-->
        <association property="card" column="card_id" javaType="com.yzb.chapter09.IdCard" select="com.yzb.chapter09.IdCardMapper.findCodeById">
        </association>
    </resultMap>


    <!--嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集-->
    <select id="findPersonById2" parameterType="Integer" resultMap="IdCardWithPersonResult2">
        select p.*,idcard.code from tb_person p ,tb_idcard idcard where p.card_id =  and  = #{id}
    </select>
    <resultMap id="IdCardWithPersonResult2" type="com.yzb.chapter09.Person">
        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <association property="card" javaType="com.yzb.chapter09.IdCard">
            <id property="id" column="card_id"/>
            <result property="code" column="code"/>
        </association>
    </resultMap>

</mapper>

MyBatisUtils

package com.yzb.chapter09;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/*
* 工具类
* */
public class MyBatisUtils {
    /*
    * 初始化sqlSessionFactory对象
    * */
    private static SqlSessionFactory sqlSessionFactory = null;
    static {
        try {
            //使用mybatis提供resources类加载MyBatis的配置文件
            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
            //创建SqlSessionFactory工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获取SqlSession对象的方法
    public static SqlSession getSession(){
        return sqlSessionFactory.openSession();
    }
}

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>
    <settings>
        <!--打开延迟加载的开关-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--将积极加载改为延迟加载,即按需加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <!--1.配置环境 ,默认的环境id为mysql-->
    <environments default="mysql">
        <!--1.2.配置id为mysql的数据库环境 -->
        <environment id="mysql">
            <!-- 使用JDBC的事务管理 -->
            <transactionManager type="JDBC" />
            <!--数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url"
                          value="jdbc:mysql://localhost:3306/spring" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
    <!--2.配置Mapper的位置 -->
    <mappers>
        <mapper resource="com/yzb/chapter09/IdCardMapper.xml" />
        <mapper resource="com/yzb/chapter09/PersonMapper.xml"/>
    </mappers>
</configuration>

Test

package com.yzb.chapter09;

import org.apache.ibatis.session.SqlSession;

/*
* MyBatis关联查询映射测试类
* */
public class Test {
    /*
    * 嵌套查询
    * */
    public static void main(String[] args) {
        //通过工具类生成sqlSession对象
        SqlSession session = MyBatisUtils.getSession();
        //执行查询
        Person p =  session.selectOne("com.yzb.chapter09.PersonMapper.findPersonById",1);
        System.out.println(p);
        /*当开启延迟加载的时候,这时只需要加载Person的数据库的SQL语句查询就可以了*/
        System.out.println(p.getName());
        //关闭SqlSession对象
        session.close();
    }
}

Test1

package com.yzb.chapter09;

import org.apache.ibatis.session.SqlSession;

/*
* MyBatis关联查询映射测试类
* */
public class Test1 {
    /*
    * 嵌套结果
    * */
    public static void main(String[] args) {
        //通过工具类生成sqlSession对象
        SqlSession session = MyBatisUtils.getSession();
        //执行查询
        Person p =  session.selectOne("com.yzb.chapter09.PersonMapper.findPersonById2",1);
        System.out.println(p);
        //关闭SqlSession对象
        session.close();
    }
}

数据库的表

tb_person

java 字段映射排除 字段映射关系_java


tb_IcCard

java 字段映射排除 字段映射关系_java_02

一对多的关联映射

在resultMap元素中使用collection的子元素,使用collection元素完成一对多的关联映射,子元素与association元素相同,但ofType与javaType属性相对应。它用于指定实体对象中集合类型属性包含的元素类型。

java 字段映射排除 字段映射关系_关联映射_03

数据库中的表

tb_User

java 字段映射排除 字段映射关系_xml_04


tb_orders

java 字段映射排除 字段映射关系_java 字段映射排除_05

User

package com.yzb.chapter09.example;

import java.util.List;

public class User {
    private Integer id;
    private String username;
    private String address;
    private List<Orders> ordersList;//用户关联的订单

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                ", ordersList=" + ordersList +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }
}

Orders

package com.yzb.chapter09.example;

public class Orders {
    private Integer id;
    private String number;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return "Orders{" +
                "id=" + id +
                ", number='" + number + '\'' +
                '}';
    }
}

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.yzb.chapter09.example.UserMapper">
    <!--一对多,查看某一用户及其关联的订单信息-->
    <!--当关联出来的列名相同时,需要使用别名来区分-->
    <select id="findUserWithOrders"  resultMap="UserWithOrdersResult" parameterType="Integer">
        select u.* ,  as order_id ,o.number from tb_user u,tb_orders o where u.id=o.user_id and u.id =#{id}
    </select>
    <resultMap id="UserWithOrdersResult" type="com.yzb.chapter09.example.User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="address" column="address"/>
        <!--一对多关联映射,collection
        ofType表示属性集合元素的类型,List<Orders>属性即Orders类-->
        <collection property="ordersList" ofType="com.yzb.chapter09.example.Orders">
            <id property="id" column="order_id"></id>
            <result property="number" column="number"></result>
        </collection>
    </resultMap>
</mapper>

mybatis-config.xml

<!--2.配置Mapper的位置 -->
    <mappers>
        <mapper resource="com/yzb/chapter09/IdCardMapper.xml" />
        <mapper resource="com/yzb/chapter09/PersonMapper.xml"/>
        <mapper resource="com/yzb/chapter09/example/UserMapper.xml"/>
    </mappers>

Test2

package com.yzb.chapter09.example;

import com.yzb.chapter09.MyBatisUtils;
import com.yzb.chapter09.Person;
import org.apache.ibatis.session.SqlSession;

/*
* MyBatis关联查询映射测试类
* */
public class Test2 {
    /*
    * 嵌套查询
    * */
    public static void main(String[] args) {
        //通过工具类生成sqlSession对象
        SqlSession session = MyBatisUtils.getSession();
        //执行查询
       User user=  session.selectOne("com.yzb.chapter09.example.UserMapper.findUserWithOrders",1);
        System.out.println(user);
        //关闭SqlSession对象
        session.close();
    }
}

多对多

数据库

CREATE TABLE tb_product (
id INT(32) PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR (32),
price DOUBLE
);
INSERT INTO tb_product VALUES('1','Java基础入门','11.0');
INSERT INTO tb_product VALUES('2','Spring','45.0');
INSERT INTO tb_product VALUES('3','JavaWeb','78.0');
CREATE TABLE tb_ordersitem (
id INT(32) PRIMARY KEY AUTO_INCREMENT,
orders_id INT(32),
product_id INT (32),
FOREIGN KEY(orders_id) REFERENCES tb_orders(id),
FOREIGN KEY(product_id) REFERENCES tb_product(id),
)
INSERT INTO tb_ordersitem VALUES('1','1','1');
INSERT INTO tb_ordersitem VALUES('2','1','3');
INSERT INTO tb_ordersitem VALUES('2','3','3');

Orders

package com.yzb.chapter09.example;

import java.util.List;

public class Orders {
    private Integer id;
    private String number;
    private List<Product> productList;

    public List<Product> getProductList() {
        return productList;
    }

    public void setProductList(List<Product> productList) {
        this.productList = productList;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return "Orders{" +
                "id=" + id +
                ", number='" + number + '\'' +
                ", productList=" + productList +
                '}';
    }
}

Product

package com.yzb.chapter09.example;

import java.util.List;

/*
* 商品持久层
* */
public class Product {
    private Integer id;
    private String name;
    private Double price;
    private List<Orders> orders;

    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", orders=" + orders +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
         = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public List<Orders> getOrders() {
        return orders;
    }

    public void setOrders(List<Orders> orders) {
        this.orders = orders;
    }
}

OrdersMapper.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.yzb.chapter09.example.OrdersMapper">
    <!--多对多镶嵌查询:通过执行另一条SQL映射语句来返回预期的特殊类型-->
    <select id="findOrdersWithProduct" parameterType="Integer" resultMap="OrdersWithProductResult">
        select * from tb_orders where id= #{id}
    </select>
    <resultMap id="OrdersWithProductResult" type="com.yzb.chapter09.example.Orders">
        <id property="id" column="id"></id>
        <result column="number" property="number"></result>
        <collection property="productList" column="id" ofType="com.yzb.chapter09.example.Product" select="com.yzb.chapter09.example.UserMapper.findProductById">

        </collection>
    </resultMap>
    <!--多对多镶嵌结果:通过执行另一条SQL映射语句来返回预期的特殊类型-->
    <select id="findOrdersWithProduct1" parameterType="Integer" resultMap="OrdersWithProductResult1">
        select o.*, as pid,,p.price,form tb_orders o,tb_product p ,tb_ordersitem oi where oi.orders_id =  and oi.product_id= and  =#{id}
    </select>
    <!--自定义手动映射类型-->
    <resultMap id="OrdersWithProductResult1" type="com.yzb.chapter09.example.Orders">
        <id property="id" column="id"></id>
        <result column="number" property="number"></result>
        <!--多对多关联映射:collection-->
        <collection property="productList"  ofType="com.yzb.chapter09.example.Product" >
            <id property="id" column="pid"/>
            <result property="name" column="name"/>
            <result property="price" column="price"/>
        </collection>
    </resultMap>
</mapper>

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">
<!-- namespace表示命名空间 -->
<mapper namespace="com.yzb.chapter09.example.UserMapper">
    <!--多对多镶嵌查询-->
    <select id="findProductById" parameterType="Integer" resultType="com.yzb.chapter09.example.Product">
        select * from tb_product where id in (select product_id from tb_ordersitem where orders_id =#{id})
    </select>
</mapper>

Test3

package com.yzb.chapter09.example;

import com.yzb.chapter09.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;

/*
* MyBatis关联查询映射测试类
* */
public class Test3 {
    /*
    * 嵌套查询
    * */
    public static void main(String[] args) {
        //通过工具类生成sqlSession对象
        SqlSession session = MyBatisUtils.getSession();
        //执行查询
       Orders orders =  session.selectOne("com.yzb.chapter09.example.OrdersMapper.findOrdersWithProduct",1);
        System.out.println(orders);
        //关闭SqlSession对象
        session.close();
    }
}

mybatis-config.xml

<mappers>
        <mapper resource="com/yzb/chapter09/IdCardMapper.xml" />
        <mapper resource="com/yzb/chapter09/PersonMapper.xml"/>
        <mapper resource="com/yzb/chapter09/example/UserMapper.xml"/>
        <mapper resource="com/yzb/chapter09/example/ProductMapper.xml"/>
        <mapper resource="com/yzb/chapter09/example/OrdersMapper.xml"/>
    </mappers>