Mybatis学习记录(2)级联操作

Mybatis学习(2)级联操作

级联操作 一对多

例,查询学生类时带出班级类

1. 创建数据表

首先,数据表结构

学生表,主键为id,外键为grand,与班级表t_classes 的id绑定。
在这里插入图片描述
班级表,主键为id
在这里插入图片描述

2. 确定查询SQL代码

查询 t_student s、t_classes 两个表,条件为 t_student 表的 id=2的数据

select * from t_student s ,t_classes c  where s.id= 2;

查询结果
在这里插入图片描述
会出现这样的查询结果是因为:
因为只指定了 s.id = 2在执行上述语句时,Mysql会查询表 t_student 中符合条件: id = 2的数据,并与 t_classes 所有数据组合在一起,返回给用户。

若要查询 t_student 中 id=2 的数据,和他 t_classes 表中的班级应当使用:

select * from t_student s ,t_classes c  where s.id= 2 and s.grand =c.id;

查询结果如下,其查询原则为:查询 t_student 中符合条件: id = 2的数据,并与 t_classes 符合 s.grand =c.id 所有数据组合在一起,返回给用户。
在这里插入图片描述
进一步的,由于 grand 和c.id的数据是我们所不需要的,所以我们可以使用下述代码:

select  s.id , s.studentname , c. classname  from t_student s ,t_classes c  where s.id= 2  and s.grand =c.id;

其查询结果如下
在这里插入图片描述

3. 在MyBatis中使用
1 创建与数据表对应的实体类

班级类

@Data
public class Classes {
    private  int id;
    private String classname;
    private List< Student> students;
}

学生类

@Data
public class Student {
    private  int id;
    private String studentname;
    private Classes classes;
}
2 创建方法接口

定义findById(int id) 方法,名称要和配置文件中一致

public interface StudentRepository {
    public Student findById( int id);
}
3 配置xml文件 重点

< id> <> 设置主键
column 列名 跟结果集里的列名映射
property 属性 要把id映射给 实体类的哪个属性

<?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.zi.repository.StudentRepository">

    <resultMap id="studentMap" type="com.zi.entity.Student">
    <id column="id" property="id"></id>  <!-- <id> <>  设置主键    column 列名 跟结果集里的列名映射  property 属性 要把id映射给 实体类的哪个属性-->
    <result column="name" property="name"></result>  <!--其他字段用  <result><>    -->
        <association property="classes" javaType="com.zi.entity.Classes">
            <id column="cid" property="id" ></id>
            <result column="cname" property="classname"></result>
        </association>
    </resultMap>

    <select id="findById" parameterType="int" resultMap="studentMap">
            select s.id , s.studentname  , c.id as cid , c.classname as cname from t_student s,t_classes c
            where s.id = #{id} /*and s.studentname = c.id*/
    </select>

</mapper>
4 在全局配置文件中注册xml文件

在全局配置文件中,注册

  <mapper resource="com/zi/repository/StudentRepository.xml"></mapper>
5 Java语句调用
InputStream inputStream = test2.class.getClassLoader().getResourceAsStream("MyBatisConfig");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new  SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory =  sqlSessionFactoryBuilder.build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取实现接⼝的代理对象

StudentRepository accountRepository = sqlSession.getMapper(StudentRepository.class);
Student student =  accountRepository.findById(2);
System.out.println(student);
通过班级带出学生

和通过学生带出班级相比,在配置xml文件上有区别,因为学生通常不止一个,所以在类中,是通过Student类型的集合来定义班级的学生属性的

  private List< Student> students; 

因此,将上面的 < association>标签换为< collection>标签ofType 中填集合中数据类型,即在此处为Student类型的全类名

 <collection property="students" ofType="com.zi.entity.Student">
        <id column="sid" property="id" ></id>
        <result column="sname" property="studentname"></result>
    </collection>

下面是完整的配置XML文件内容
<?xml version="1.0" encoding="UTF-8" ?>

<mapper namespace="com.zi.repository.ClassesRepository">

<resultMap id="classMap" type="com.zi.entity.Classes">
<id column="id" property="id"></id>  <!-- <id> <>  设置主键    column 列名 跟结果集里的列名映射  property 属性 要把id映射给 实体类的哪个属性-->
<result column="classname" property="classname"></result>  <!--其他字段用  <result><>    -->
    <collection property="students" ofType="com.zi.entity.Student">
        <id column="sid" property="id" ></id>
        <result column="sname" property="studentname"></result>
    </collection>
</resultMap>

<select id="findById" parameterType="int" resultMap="classMap">
        select c.id , c.classname , s.id as sid , s.studentname as sname from t_student s,t_classes c
        where c.id = #{id} and c.id = s.grand
</select>

级联操作 多对多 客户和商品

一些说明

结果集和类映射
根据Mysql查找到的结果集,按照从左往右的顺序,依次查找对应实体类中的字段,若有则赋值,没有则不赋值。

as的使用,将结果集的列名返回为as 后的字段

select s.id , s.studentname  , c.id as cid,  c.classname as cname from t_student s,t_classes c
where s.id = 2;

Student(id=2, studentname=null, classes=Classes(id=4, classname=9班, students=null))

1. 在数据库创建对应数据表,并设置外键约束

##创建 Goods Customers 用户-商品对照 数据表

CREATE TABLE t_customers(
                          `id` INT  PRIMARY KEY,
                          `customername` VARCHAR(100) NOT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE t_goods(
                            `id` INT  PRIMARY KEY,
                            `goodname` VARCHAR(100) NOT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE t_cg(
                            `id` INT  PRIMARY KEY,
                            `cid` int  NOT NULL,
                            `gid` int  NOT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

##添加外键

ALTER TABLE t_cg
    ADD CONSTRAINT fk_tb_dept2
        FOREIGN KEY(cid)
            REFERENCES t_customers(id);

ALTER TABLE t_cg
    ADD CONSTRAINT fk_tb_dept3
        FOREIGN KEY(gid)
            REFERENCES t_goods(id);
2. 创建对应实体类

商品类

public class Good {
    private  int id ;
    private String goodname;
    private List<Customer> customers;
}

用户类

public class Customer {
    private  int id ;
    private String customername;
    private List<Good> goods;
}
3. 创建方法接口
public interface CustomerRepository {
    public Customer findById(int id);
}
4. 配置xml文件

在写配置文件前,需要理清楚SQL语句的关系
在数据库中,我要执行以下语句:

select  c.id ,c.customername,g.goodname  from t_customers c ,t_goods g,t_cg cg where c.id =2 and  c.id = cg.cid and g.id =cg.gid  ;

返回以下结果集:
在这里插入图片描述
开始写配置文件

	<?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.zi.repository.CustomerRepository">

    <resultMap id="customerMap" type="com.zi.entity.Customer">
    <id column="id" property="id"></id>  <!-- <id> <>  设置主键    column 列名 跟结果集里的列名映射  property 属性 要把id映射给 实体类的哪个属性-->
    <result column="customername" property="customername"></result>  <!--其他字段用  <result><>    -->
        <collection property="goods" ofType="com.zi.entity.Good">
            <id column="gid" property="id" ></id>
            <result column="goodname" property="goodname"></result>
        </collection>
    </resultMap>

    <select id="findById" parameterType="int" resultMap="customerMap">
        select  c.id ,c.customername,g.goodname ,g.id as gid from t_customers c ,t_goods g,t_cg cg
         where  c.id =2 and  c.id = cg.cid and g.id =cg.gid;
    </select>

</mapper>
5. 在全局配置文件中注入关联
    <mapper resource="com/zi/repository/CustomerRepository.xml"></mapper>
6. 在JAVA语句中使用
InputStream inputStream = test2.class.getClassLoader().getResourceAsStream("MyBatisConfig");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new  SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory =  sqlSessionFactoryBuilder.build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
CustomerRepository accountRepository3 = sqlSession.getMapper(CustomerRepository.class);
System.out.println(accountRepository3.findById(2));
出现读取不到对象数据的现象

原因是,我在创建实体类时,没有添加@Data,即没有构造函数,导致只声明了类,而没有构造它。

在这里插入图片描述

文件结构

下面是我的文件夹结构

Mybatis是一款开源的ORM框架,它提供了许多方便的功能来操作数据库。其中,级联属性赋值和延迟加载是Mybatis比较常用的两个特性。 1. 级联属性赋值 级联属性赋值是指在进行一次数据库操作时,同时将相关联的对象也进行操作。例如,当我们向数据库插入一条订单记录时,同时需要向订单明细表中插入多条记录,这些记录与订单记录存在关联关系。Mybatis提供了级联属性赋值的功能,可以方便地完成这种操作。 举个例子,假设我们有两个实体类Order和OrderDetail,它们之间是一对多的关系: ```java public class Order { private Integer id; private String orderNo; private List<OrderDetail> details; // getter and setter } public class OrderDetail { private Integer id; private String productName; private Integer quantity; private Integer orderId; // getter and setter } ``` 在Order实体类中,我们定义了一个List类型的属性details,用于保存该订单包含的所有订单明细记录。在OrderMapper.xml文件中,我们可以使用Mybatis提供的collection元素,来实现级联属性赋值: ```xml <insert id="addOrder" parameterType="Order"> insert into orders (order_no) values (#{orderNo}) <foreach collection="details" item="detail" index="index"> insert into order_detail (product_name,quantity,order_id) values (#{detail.productName},#{detail.quantity},LAST_INSERT_ID()) </foreach> </insert> ``` 在这个例子中,我们使用了foreach元素来遍历Order实体类中的details属性,将其中的每个OrderDetail对象对应插入到order_detail表中,同时将该订单的id作为order_id的值。这样,我们就完成了级联属性赋值的操作。 2. 延迟加载 延迟加载是指在进行查询操作时,不会立即将所有关联的数据都加载出来,而是等到真正需要使用这些数据时再去查询。这样可以提高系统的性能和减少内存的占用。 举个例子,假设我们有两个实体类User和Order,它们之间是一对多的关系: ```java public class User { private Integer id; private String name; private List<Order> orders; // getter and setter } public class Order { private Integer id; private String orderNo; private Integer userId; // getter and setter } ``` 在User实体类中,我们同样定义了一个List类型的属性orders,用于保存该用户的所有订单记录。在OrderMapper.xml文件中,我们可以使用Mybatis提供的association元素和select元素,来实现延迟加载: ```xml <select id="getUserById" resultType="User"> select * from users where id=#{id} </select> <resultMap id="userResultMap" type="User"> <id property="id" column="id"/> <result property="name" column="name"/> <collection property="orders" ofType="Order"> <id property="id" column="id"/> <result property="orderNo" column="order_no"/> <association property="user" javaType="User"> <id property="id" column="user_id"/> <select property="orders" resultMap="userResultMap"> select * from orders where user_id=#{id} </select> </association> </collection> </resultMap> ``` 在这个例子中,我们使用了association元素来定义Order实体类中的User属性,同时使用select元素来定义延迟加载的查询语句。在查询User对象时,只会查询出User对象本身的信息,而不会立即查询关联的订单记录。当我们需要使用订单记录时,Mybatis会自动执行查询语句,将相关的订单记录加载出来。这样,我们就完成了延迟加载的操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值