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,即没有构造函数,导致只声明了类,而没有构造它。
文件结构
下面是我的文件夹结构