第9章 MyBatis的关系映射

在实际开发中,对数据库的操作通常涉及多张表,涉及了对象和对象之间的关联关系。针对多表之间的操作,MyBatis提供了关联映射,通过关联映射就可以很好的处理对象与对象之间的关联关系

9.1 关联关系概述

一对一:在任意一方引入对方主键作为外键。

一对多:在“多”的一方,添加“一“的一方的主键作为外键。(连着多条线的一方是“多”)

多对多:产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键。

用Java对象描述

class A{
    B b;
}
class B{
    A a;
}
//一对一:在本类中定义对方类型的对象,如A类中定义B类类型的属性b,B类中定义A类类型的属性a
class A{
    List<B>b;
}
class B{
    A a;
}
//一对多:就是一个A类类型中对应多个B类类型的情况,需要在A类中以集合的方式引入B类类型的对象,在B类中定义A类类型的属性a
class A{
    List<B> b;
}
class B{
    List<A> a;
}
//多对多:在A类中定义B类类型的集合,在B类中定义A类类型的集合

一对一:用<association>元素处理

a)、property:指定映射到的实体类对象中的属性,与表字段一一对应。

b)、column:指定数据库表中对应的字段。

c)、javaType:指定映射到实体对象属性的类型。

d)、select:指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询。

e)、fetchType:指定在关联查询时是否启用延迟加载。该属性有lazy和eager两个属性值,默认值为lazy(即默认关联映射延迟加载)。

MyBatis加载关联关系对象主要通过两种方式:嵌套查询和嵌套结果。

问题:虽然使用嵌套查询的方式比较简单,但是嵌套查询的方式要执行多条SQL语句,这对于大型数据集合和列表展示不是很好,因为这样可能会导致成百上千条关联的SQL语句被执行,从而极大的消耗数据库性能并且会降低查询效率。类似暴力for循环吧。

解决:MyBatis延迟加载的配置。使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis默认没有开启延迟加载,需要在核心配置文件中的<settings>元素内进行配置,具体配置方式如下:

<settings>
       <setting name="lazyLoadingEnabled" value="true" />
       <setting name="aggressiveLazyLoading" value="false"/>
</settings>

在映射文件中,<association>元素和<collection>元素中都已默认配置了延迟加载属性,即默认属性fetchType="lazy"(属性fetchType="eager"表示立即加载),所以在配置文件中开启延迟加载后,无需在映射文件中再做配置。

举例:以个人和身份证之间的一对一关联关系

创建两个表tb_idcard和tb_person

USE mybatis;
CREATE TABLE tb_idcard(
    id INT PRIMARY KEY AUTO_INCREMENT,
    CODE VARCHAR(18)
);
INSERT INTO tb_idcard(CODE) VALUE(‘152221198711020624‘);
INSERT INTO tb_idcard(CODE) VALUE(‘152201199008150317‘);

CREATE TABLE tb_person(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(32),
    age INT,
    sex VARCHAR(8),
    card_id INT UNIQUE,
    FOREIGN KEY(card_id) REFERENCES tb_idcard(id)
);
INSERT INTO tb_person(NAME,age,sex,card_id) VALUE(‘Rose‘,29,‘女‘,1);
INSERT INTO tb_person(NAME,age,sex,card_id) VALUE(‘tom‘,27,‘男‘,2);

此时表内数据:

创建持久化类IdCard和Person

package com.itheima.po;
/**
 * 证件持久化类
 */
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 + "]";
    }
}

IdCard

package com.itheima.po;
/**
 * 个人持久化类
 */
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) {
        this.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 + "]";
    }
}

Person

嵌套查询:

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">
<mapper namespace="com.itheima.mapper.IdCardMapper">

  <!-- 根据id查询证件信息,最普通的配置信息 -->
  <select id="findCodeById" parameterType="Integer" resultType="IdCard">
      SELECT * from tb_idcard where id=#{id}
  </select>

</mapper>

PersonMapper.xml映射文件:

<!-- 嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型 -->
    <select id="findPersonById" parameterType="Integer"
                                      resultMap="IdCardWithPersonResult123">
        SELECT * from tb_person where id=#{id}
    </select>

     <!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo -->
    <resultMap type="Person" id="IdCardWithPersonResult123">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="sex" column="sex" />

        <!-- 一对一:association使用select属性引入另外一条SQL语句,是另一个映射文件的select元素id -->
        <association property="card" column="card_id" javaType="IdCard"
            select="com.itheima.mapper.IdCardMapper.findCodeById" />
    </resultMap>

测试方法:

    /**
     * 嵌套查询
     */
    @Test
    public void findPersonByIdTest() {
        // 1、通过工具类生成SqlSession对象
        SqlSession session = MybatisUtils.getSession();
        // 2.使用MyBatis嵌套查询的方式查询id为1的人的信息
        Person person = session.selectOne("com.itheima.mapper."
                                   + "PersonMapper.findPersonById", 1);
        // 3、输出查询结果信息
        System.out.println(person);
        // 4、关闭SqlSession
        session.close();
    }

findPersonByIdTest()

运行结果:执行了多条简单的SQL语句

嵌套结果:

<!-- 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集 -->
    <select id="findPersonById2" parameterType="Integer"
                                       resultMap="IdCardWithPersonResult2">
        SELECT p.*,idcard.code
        from tb_person p,tb_idcard idcard
        where p.card_id=idcard.id
        and p.id= #{id}
    </select>

    <resultMap type="Person" id="IdCardWithPersonResult2">
        <id property="id" column="id" /><!-- 声明主键,id是关联查询对象的唯一标识符 -->
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="sex" column="sex" />
        <association property="card" javaType="IdCard">
            <id property="id" column="card_id" />
            <result property="code" column="code" />
        </association>
    </resultMap>

PersonMapper.xml映射文件

    /**
     * 嵌套结果
     */
    @Test
    public void findPersonByIdTest2() {
        // 1、通过工具类生成SqlSession对象
        SqlSession session = MybatisUtils.getSession();
        // 2.使用MyBatis嵌套结果的方法查询id为1的人的信息
        Person person = session.selectOne("com.itheima.mapper."
                                   + "PersonMapper.findPersonById2", 1);
        // 3、输出查询结果信息
        System.out.println(person);
        // 4、关闭SqlSession
        session.close();
    }

测试方法

测试结果:只执行了一条复杂的SQL语句。

DEBUG [main] - ==> Preparing: SELECT p.*,idcard.code from tb_person p,tb_idcard idcard where p.card_id=idcard.id and p.id= ?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
Person [id=1, name=Rose, age=29, sex=女, card=IdCard [id=1, code=152221198711020624]]

select p.*,idcard.code from tb_person p,tb_idcard idcard where p.card_id=idcard.id and p.id = #{id}

这里的p是tb_person的别名,因为别名容易写,第二个tb_person后接空格再加p是格式,如果不用别名就是:

select tb_person.*,tb_idcard.code from tb_person,tb_idcard where tb_person.card_id=tb_idcard.id and tb_person.id = #{id}

一对一关系配置模板:

9.3 一对多

<resultMap>元素中,包含一个子元素<collection>元素,属性大部分和<association>元素相同,但有一个特殊属性ofType,这个属性和javaType属性对应,用于指定实体对象中集合类属性所包含的元素类型。

<collection>元素的使用模板:

1.在MySQL中建表tb_user和tb_orders,并插入几条数据

USE mybatis;

CREATE TABLE tb_user(
    id INT(32) PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(32),
    address VARCHAR(256)
);
INSERT INTO tb_user VALUES(‘1‘,‘詹姆斯‘,‘克利夫兰‘);
INSERT INTO tb_user VALUES(‘2‘,‘科比‘,‘洛杉矶‘);
INSERT INTO tb_user VALUES(‘3‘,‘保罗‘,‘洛杉矶‘);

USER mybatis;
CREATE TABLE tb_orders(
    id INT(32) PRIMARY KEY AUTO_INCREMENT,
    number VARCHAR(32) NOT NULL,
    user_id INT(32) NOT NULL,
    FOREIGN KEY(user_id) REFERENCES tb_user(id)
);
INSERT INTO tb_orders VALUES(‘1‘,‘1000011‘,‘1‘);
INSERT INTO tb_orders VALUES(‘2‘,‘1000012‘,‘1‘);
INSERT INTO tb_orders VALUES(‘3‘,‘1000013‘,‘2‘);

结果:

2.创建持久化类Orders和User

package com.itheima.po;
import java.util.List;
/**
 * 用户持久化类
 */
public class User {
    private Integer id;                 // 用户编号
    private String username;           // 用户姓名
    private String address;            // 用户地址
    private List<Orders> 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;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", address="
                + address + ", ordersList=" + ordersList + "]";
    }
}

User.java

package com.itheima.po;

import java.util.List;

/**
 * 订单持久化类
 */
public class Orders {
    private Integer id;    //订单id
    private String number;//订单编号
    //关联商品集合信息
    private List<Product> 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 + "]";
//    }
    public List<Product> getProductList() {
        return productList;
    }
    public void setProductList(List<Product> productList) {
        this.productList = productList;
    }
    @Override
    public String toString() {
        return "Orders [id=" + id + ", number=" + number + ", productList=" + productList + "]";
    }

}

Orders.java

3.创建映射文件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.itheima.mapper.UserMapper">

    <!-- 一对多:查看某一用户及其关联的订单信息
          注意:当关联查询出的列名相同,则需要使用别名区分 -->
    <select id="findUserWithOrders123" parameterType="Integer"
                           resultMap="UserWithOrdersResult123">
        SELECT u.*,o.id as orders_id,o.number
        from tb_user u,tb_orders o
        WHERE u.id=o.user_id
         and u.id=#{id}
    </select>

    <resultMap type="User" id="UserWithOrdersResult123">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="address" column="address"/>

        <!-- 一对多关联映射:collection
            ofType表示属性集合中元素的类型,List<Orders>属性即Orders类 -->
        <collection property="ordersList" ofType="Orders">
            <id property="id" column="orders_id"/>
            <result property="number" column="number"/>
        </collection>

    </resultMap>
</mapper>

4.测试方法:

/**
     * 一对多
     */
    @Test
    public void findUserTest() {
        // 1、通过工具类生成SqlSession对象
        SqlSession session = MybatisUtils.getSession();
        // 2、查询id为1的用户信息
        User user = session.selectOne("com.itheima.mapper."
                                + "UserMapper.findUserWithOrders123", 1);
        // 3、输出查询结果信息
        System.out.println(user);
        // 4、关闭SqlSession
        session.close();
    }

findUserTest

5.查询结果:

DEBUG [main] - ==> Preparing: SELECT u.*,o.id as orders_id,o.number from tb_user u,tb_orders o WHERE u.id=o.user_id and u.id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 2
User [id=1, username=詹姆斯, address=克利夫兰, ordersList=[Orders [id=1, number=1000011, productList=null], Orders [id=2, number=1000012, productList=null]]]

9.4 多对多

以商品和订单为例,一个订单可以包含多个商品,一个商品可以属于多个订单,数据库中的多对多联系通常使用一个中间表来维护,中间表中的订单id作为外键参照订单表的id,商品id作为外键参照商品表的id。

(外键:这个表的某一属性是别的表的主键,可以有重复,可以有多个,可以为空)

1.建表:tb_product和tb_ordersitem

USE mybatis;

CREATE TABLE tb_product(
    id INT(32) PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(32),
    price DOUBLE
);
INSERT INTO tb_product VALUES(‘1‘,‘Java基础入门‘,‘44.5‘);
INSERT INTO tb_product VALUES(‘2‘,‘Java Web程序开发入门‘,‘38.5‘);
INSERT INTO tb_product VALUES(‘3‘,‘SSM框架整合实战‘,‘50‘);

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(‘3‘,‘3‘,‘3‘);

建表后:

2.创建持久化类Product表示商品,订单用以前的Order

package com.itheima.po;
import java.util.List;
/**
 * 商品持久化类
 */
public class Product {
    private Integer id;  //商品id
    private String name; //商品名称
    private Double price;//商品单价
    private List<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) {
        this.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;
    }
    @Override
    public String toString() {
        return "Product [id=" + id + ", name=" + name
                           + ", price=" + price + "]";
    }
}

Product.java

3.创建订单实体映射文件OrdersMapper.xml和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">
<mapper namespace="com.itheima.mapper.OrdersMapper">

    <!-- 多对多嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型
    定义了一个id为findOrdersWithPorduct的select语句来查询订单及其关联的商品信息-->
    <select id="findOrdersWithPorduct" parameterType="Integer"
              resultMap="OrdersWithProductResult">
        select * from tb_orders WHERE id=#{id}
    </select>

    <resultMap type="Orders" id="OrdersWithProductResult">
        <id property="id" column="id" />
        <result property="number" column="number" />

        <!-- property属性表示订单持久化类中的商品属性,ofType属性表示集合中的数据为Product类型,而column的
        属性值会作为参数执行ProductMapper中定义的id为findProductById的执行语句来查询订单中的商品信息-->
        <collection property="productList" column="id" ofType="Product"
             select="com.itheima.mapper.ProductMapper.findProductById">
        </collection>

    </resultMap>

    <!-- 多对多嵌套结果查询:查询某订单及其关联的商品详情 -->
    <select id="findOrdersWithPorduct2" parameterType="Integer"
             resultMap="OrdersWithPorductResult2">
        select o.*,p.id as pid,p.name,p.price
        from tb_orders o,tb_product p,tb_ordersitem  oi
        WHERE oi.orders_id=o.id
        and oi.product_id=p.id
        and o.id=#{id}
    </select>

    <!-- 自定义手动映射类型 -->
    <resultMap type="Orders" id="OrdersWithPorductResult2">
        <id property="id" column="id" />
        <result property="number" column="number" />
        <!-- 多对多关联映射:collection -->
        <collection property="productList" ofType="Product">
            <id property="id" column="pid" />
            <result property="name" column="name" />
            <result property="price" column="price" />
        </collection>
    </resultMap>

</mapper>

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">
<mapper namespace="com.itheima.mapper.ProductMapper">
    <select id="findProductById" parameterType="Integer"
                                       resultType="Product">
        SELECT * from tb_product where id IN(
           SELECT product_id FROM tb_ordersitem  WHERE orders_id = #{id}
        )
    </select>
</mapper>

ProductMapper.xml

4.测试方法:

    /**
     * 多对多
     */
    @Test
    public void findOrdersTest(){
        // 1、通过工具类生成SqlSession对象
        SqlSession session = MybatisUtils.getSession();
        // 2、查询id为1的订单中的商品信息
        Orders orders = session.selectOne("com.itheima.mapper."
                               + "OrdersMapper.findOrdersWithPorduct", 1);
        // 3、输出查询结果信息
        System.out.println(orders);
        // 4、关闭SqlSession
        session.close();
    }

findOrdersTest()

5.测试结果:

DEBUG [main] - ==> Preparing: select * from tb_orders WHERE id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
DEBUG [main] - ==> Preparing: SELECT * from tb_product where id IN( SELECT product_id FROM tb_ordersitem WHERE orders_id = ? )
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 2
Orders [id=1, number=1000011, productList=[Product [id=1, name=Java基础入门, price=44.5], Product [id=3, name=SSM框架整合实战, price=50.0]]]

原文地址:https://www.cnblogs.com/shoulinniao/p/10988828.html

时间: 2024-08-06 11:41:01

第9章 MyBatis的关系映射的相关文章

Mybatis框架中实现一对多关系映射

学习过Hibernate框架的伙伴们很容易就能简单的配置各种映射关系(Hibernate框架的映射关系在我的blogs中也有详细的讲解),但是在Mybatis框架中我们又如何去实现 一对多的关系映射呢? 其实很简单 首先我们照常先准备前期的环境(具体解释请  参考初识Mybatis进行增.删.改.查 blogs )这里我就直接上代码了 主配置文件:Configuration.xml <?xml version="1.0" encoding="UTF-8" ?&

mybatis中树形结构的bean的关系映射

最近用mybatis写一个小程序,涉及到树形结构的关系映射,比如一个分类,本身具有多对一的关系,那么它是如何映射呢?直接贴代码: Cate.java @Table(name="cate") public class Cate extends AbstractModel { /** * */ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTI

Mybatis关系映射

一.一对一关系映射 使用resultType+包装类实现 1.假设问题背景是要求在某一个购物平台的后台程序中添加一个这样的功能:查询某个订单的信息和下该订单的用户信息.首先我们可以知道,一般这样的平台上面,某一笔订单只属于某一个用户,从这个角度来看,可以作为一对一的参考模型 ①首先创建数据表user(用户表) CREATE TABLE `user` ( `uid` INT(11) NOT NULL AUTO_INCREMENT, `username` VARCHAR(255) DEFAULT N

MyBatis的对象关系映射---一对多N+1策略★★★★★

在实际开发中,一个业务可能涉及到多个数据表的查询,那么多表查询就涉及连接查询(等值连接), 等值连接 表与表之间有一个外键关键,但是程序中最终获取的表封装的对象, 对象与对象之间是没有外键关系的,对象和对象之间只有依赖关系: 对象之间关系主要是四种: 一对一 关系一个人对应身份证id,一个QQ号对应一个QQ空间 一对多 关系 一个部门对应多个员工 多对一 关系 多个员工对应一个部门 多对多 关系 多个学生对应多个老师,多个学生对应多个课程 什么关系应该从哪个对象作为中心点来看 一对多, 以one

mybatis 一对一,一对多,多对多关系映射查询操作

定义两个类(对应数据库内两张表) User ,Account,每个Account属于一个User User类 及其 对应的IUserDao package com.itheima.domain; import java.io.Serializable; import java.util.Date; import java.util.List; public class User implements Serializable { private Integer id; private Strin

mybatis 多对多映射关系

xml映射文件:一个用户对应多个订单,一个订单对应多个订单明细,一个订单明细对应一个商品 可以推断出用户和商品是多对多的关系用户和商品的关系分析 可以发现一层套一层... <!-- #######################################多对多的关系映射####################################################### --> <resultMap type="cn.itcast.domain.User"

mybatis中一对一关系映射

一对一关系中普通的配置方式 一.多表连接查询语句: <select id="selectStudentWithAddress" parameterType="int" resultMap="StudentWithAddressResult"> select s.stud_id, s.name, s.email,s.dob,s.phone, a.addr_id, a.street, a.city, a.state, a.zip,a.co

170905-MyBatis中的关系映射

===关系映射=== 参考文档复习:1对1,1对多,多对多 1.映射(多)对一.(一)对一的关联关系 1).使用列的别名 ①.若不关联数据表,则可以得到关联对象的id属性 ②.若还希望得到关联对象的其它属性.则必须关联其它的数据表 1.创建表: 员工表: DROP TABLE IF EXISTS `tbl_employee`; CREATE TABLE `tbl_employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_name` varch

ASP.NET5实践02:EF7迁移-连接字符串读取-增删改查-关系映射

1.概述 本章重点本应该先从实体关系映射介绍,就像做网页设计先从整体布局开始一样. 最好先基本搞明白实体关系映射到数据表关联关系之后,再研究实体属性或表字段细节. EF7.x和EF6.x区别是很大的.EF7为了迎合NoSql,与以前单一处理关系型数据库映射有一些不同的理念. 在讲这之前,我们先学习EF7迁移和数据库字符串配置读写. 这算准备工作,虽然有些啰嗦,但这是写这篇博客的思路.既然是实践系列,就边体验便写博客! 2.手动迁移 实体类: public class Role { public