1 1-1关联映射查询实现
需求:查询出某个用户的身份证信息。用户信息和身份证信息是 一 对 一的关系。
实现步骤:
1、必须在实体类中先建立1-1的关系。
定义一个身份证类
public class UserCard {
private int id;
private double height;
private double weight;
private int married;
//getter setter toString省略
}
再定义用户类关联身份证类
public class User {
private int id;
private String userName;
private Date birthday;
private char sex;
private String address;
// 一个用户对象 一个身份证对象: 1-1的关系。
private UserCard userCard;
//getter setter toString省略
}
2、实现1-1的关联映射查询实现。
获取会话对象,获取用户的数据访问层接口代理对象,创建方法查询用户信息。
public class MybatisDemo {
@Test
public void query1_1(){
// 1、获取与数据库的会话
SqlSession sqlSession = MybatisSqlSessionFactoryUtils.getSqlSession();
// 2、获取用户的数据访问层接口的代理对象,会自动找映射文件:UserMapper.xml文件
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 3、查询用户对象信息(目的是可以查询出1-1关联的身份证信息 )
List<User> users = userMapper.findAll();
System.out.println(users);
// 4、关闭会话
MybatisSqlSessionFactoryUtils.close(sqlSession);
}
}
因为创建了UserCard的对象类,所以,我们不管需不需要用到,都应该再dao包下创建它的映射文件。
public interface UserCardMapper {
}
public interface UserMapper {
List<User> findAll();
}
<!--UserCardMapper.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.dao.UserCardMapper">
<!--不需要用到,但是必须写上来-->
</mapper>
下面是配置UserMapper.xml,首先先配置好两个实体的结果集,然后在再将两段结果集进行关联,官方规定了1-1关联的字段映射必须使用一个标签:association。最后再配置SQL语句,结果集返回类型是两个实体类关联的结果集。
<mapper namespace="com.itheima.dao.UserMapper">
<resultMap id="userCardResultMap" type="UserCard">
<id property="id" column="id"/>
<result property="height" column="height"/>
<result property="weight" column="weight"/>
<result property="married" column="married"/>
</resultMap>
<resultMap id="userResultMap" type="User">
<id property="id" column="id"/>
<result property="userName" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</resultMap>
<!-- extends:先继承用户基础的结果集映射用户对象本身的信息,里面再关联映射关联字段的信息 -->
<resultMap id="user1_1ResultMap" type="User" extends="userResultMap">
<!-- 开始配置1-1关联映射的身份证字段对象信息:userCard
官方规定了1-1关联的字段映射必须使用一个标签:association
property:申明关联的1-1字段
resultMap:关联字段userCard自己的结果集映射
-->
<association property="userCard" resultMap="userCardResultMap"/>
</resultMap>
<!-- List<User> findAll(); -->
<select id="findAll" resultMap="user1_1ResultMap">
SELECT * FROM USER u LEFT JOIN user_card uc ON u.id = uc.id
</select>
</mapper>
2 1-N
需求: 查询出用户对象的时候,可以查询出它的全部订单信息。用户 与 订单是 1-N的关系!
实现步骤:
1、必须在实体类中先建立1-N的关系。
定义一个订单类:
public class OrderForm {
private int oid;
private int userId;
private String number;
private Date createTime;
private String note;
//getter setter toString省略
}
定义一个用户类:
public class User {
private int id;
private String userName;
private Date birthday;
private char sex;
private String address;
// 一个用户对象 一个身份证对象: 1-1的关系。
private UserCard userCard;
// 一个用户对象 一批订单对象: 1-N的关系
private List<OrderForm> orderForms;
//getter setter toString省略
}
public interface UserMapper {
List<User> findAll();
}
下面是同样是配置UserMapper.xml,首先先配置好两个实体的结果集,然后在再将两段结果集进行关联,官方规定了1-N关联的字段映射必须使用一个标签:collection。最后再配置SQL语句,结果集返回类型是两个实体类关联的结果集。
<?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.dao.UserMapper">
<resultMap id="userResultMap" type="User">
<id property="id" column="id"/>
<result property="userName" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</resultMap>
<resultMap id="orderFormResultMap" type="OrderForm">
<id property="oid" column="oid"/>
<result property="userId" column="user_id"/>
<result property="number" column="number"/>
<result property="createTime" column="create_time"/>
<result property="note" column="note"/>
</resultMap>
<!-- extends:先继承用户基础的结果集映射用户对象本身的信息,里面再关联映射关联字段的信息 -->
<resultMap id="user1_NResultMap" type="User" extends="userResultMap">
<!-- 一个用户包含一批订单,官方规定了1-N的字段必须使用如下标签映射: collection -->
<!--
property: 多方的属性名
javaType:多方的属性类型
ofType: 集合中每个元素的类型
resultMap:多方映射
-->
<collection property="orderForms" javaType="list" ofType="OrderForm"
resultMap="orderFormResultMap"/>
</resultMap>
<!-- List<User> findAll(); -->
<select id="findAll" resultMap="user1_NResultMap">
<!-- 连表查询 -->
SELECT * FROM USER u LEFT JOIN order_form of ON u.id = of.user_id
</select>
</mapper>
3 N-N
需求: 查询出全部用户信息的同时可以查询出用户的全部角色信息。用户与角色是:N-N关系!
实现步骤:
1、必须在实体类中先建立N-N的关系。
同样我们需要建立一个角色类:
public class Role {
private int roleId;
private String roleName;
private String roleDetail;
//getter setter toString省略
}
然后去用户类去关联:(其他代码参照1-N用户类)
// 一个用户对象 一批角色对象: N-N的关系
private List<Role> roles;
2、实现N-N的关联映射查询实现:实现上与1-N一模一样。单独来看都是1-N的关系。
这里的配置和1-N一样,直接上代码。
public class MybatisDemo {
@Test
public void queryN_N(){
// 1、获取与数据库的会话
SqlSession sqlSession = MybatisSqlSessionFactoryUtils.getSqlSession();
// 2、获取用户的数据访问层接口的代理对象,会自动找映射文件:UserMapper.xml文件
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 3、查询用户对象信息(目的是可以查询出1-N关联的订单信息 )
List<User> users = userMapper.findAll();
System.out.println(users);
// 4、关闭会话
MybatisSqlSessionFactoryUtils.close(sqlSession);
}
}
public interface UserMapper {
List<User> findAll();
}
<?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.dao.UserMapper">
<resultMap id="userResultMap" type="User">
<id property="id" column="id"/>
<result property="userName" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</resultMap>
<resultMap id="roleFormResultMap" type="Role">
<id property="roleId" column="role_id"/>
<result property="roleName" column="role_name"/>
<result property="roleDetail" column="role_Detail"/>
</resultMap>
<!-- extends:先继承用户基础的结果集映射用户对象本身的信息,里面再关联映射关联字段的信息 -->
<resultMap id="userN_NResultMap" type="User" extends="userResultMap">
<!-- 一个用户包含一批订单,官方规定了N_N与1-N的字段必须使用如下标签映射: collection -->
<!--
property: 多方的属性名
javaType:多方的属性类型
ofType: 集合中每个元素的类型
resultMap:多方映射
-->
<collection property="roles" javaType="list" ofType="Role"
resultMap="roleFormResultMap"/>
</resultMap>
<!-- List<User> findAll(); -->
<select id="findAll" resultMap="userN_NResultMap">
<!-- 连表查询 -->
SELECT * FROM USER u LEFT JOIN user_role ur ON u.id = ur.`user_id`
LEFT JOIN role r ON ur.`role_id` = r.`role_id`
</select>
</mapper>
4 延迟加载的配置优化
我们会发现,在之前代码中,在配置结果集的时候我们要根据每一个类去配置它的结果集,这种做法带来的坏处就是代码量过多,如果一个数据很多列,那么我们需要一个个的写,这是不可能的。那么我们就给了一种新的配置优化的做法。我们在前面会根据每个类去创建它的映射文件,比如User类就在dao包下创建UserMapper.java和UserMapper.xml,UserCard类就在dao包下创建UserCardMapper.java和UserCardMapper.xml。
那么我们就可以把之前的这段结果集代码给删除。
<resultMap id="userCardResultMap" type="UserCard">
<id property="id" column="id"/>
<result property="height" column="height"/>
<result property="weight" column="weight"/>
<result property="married" column="married"/>
</resultMap>
<resultMap id="userResultMap" type="User">
<id property="id" column="id"/>
<result property="userName" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</resultMap>
然后在UserCardMapper.java文件下创建一个方法
public interface UserCardMapper {
UserCard getUserCardById(int userId);
}
再去UserCardMapper.xml文件配置好映射文件。记住namespace: 必须申明成被服务接口的路径。
<?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.dao.UserCardMapper">
<!-- UserCard getUserCardById(int userId); -->
<select id="getUserCardById" resultType="UserCard">
select * from user_card where id = #{xxzxz}
</select>
</mapper>
然后再回到UserMapper.xml文件中进行配置,声明关联的字段、根据当前用户的哪个字段值去查询关联对象、 关联字段的类型、然后用select去提取UserCardMapper.java的相对路径,表示去这个关联对象中去查询信息。
<mapper namespace="com.itheima.dao.UserMapper">
<resultMap id="user1_1ResultMap" type="User" >
<id property="id" column="id"/>
<!-- 开始配置1-1关联映射的身份证字段对象信息:userCard
官方规定了1-1关联的字段映射必须使用一个标签:association
property:申明关联的1-1字段
javaType : 关联字段的类型
column:根据当前用户的哪个字段值去查询关联对象!
select:去那当前行的column列值去查询关联的这个字段的对象信息!
拓展:
fetchType="eager" 立即加载
fetchType="lazy" 延迟加载
-->
<association property="userCard" column="id" javaType="UserCard"
select="com.itheima.dao.UserCardMapper.getUserCardById"/>
</resultMap>
<!-- List<User> findAll(); -->
<select id="findAll" resultMap="user1_1ResultMap">
select * from user
</select>
</mapper>
通过这样配置,我们会发现代码量少了很多。
5 1-1延迟加载
延迟加载:需要的时候才去查询,不需要的时候不要查询!!提高数据操作的性能!
Mybatis默认是没有开启延迟加载的,本案例是可以支持延迟加载的,需要开启延迟加载才可以。
延迟加载的具体含义:不需要的时候不会加载关联的字段信息查询,需要的时候才会触发查询关联字段信息。
在mybatis-config.xml核心配置文件中配置。
<!--配置mybatis中全局设置-->
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
同样的做法:
需求:查询出某个用户的身份证信息。用户信息和身份证信息是 一 对 一的关系。
实现步骤:
1、必须在实体类中先建立1-1的关系。
忽略。可以翻看上面1-1的代码。
2、实现1-1的关联映射查询实现。
UserMapper.java
public interface UserMapper {
List<User> findAll();
}
UserMapper.xml
UserMapper.xml文件中进行配置,声明关联的字段、根据当前用户的哪个字段值去查询关联对象、 关联字段的类型、然后用select去提取UserCardMapper.java的相对路径,表示去这个关联对象中去查询信息。
SQL语句直接查询整个user,然后再去UserCardMapper.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.dao.UserMapper">
<resultMap id="user1_1ResultMap" type="User" >
<id property="id" column="id"/>
<!-- 开始配置1-1关联映射的身份证字段对象信息:userCard
官方规定了1-1关联的字段映射必须使用一个标签:association
property:申明关联的1-1字段
javaType : 关联字段的类型
column:根据当前用户的哪个字段值去查询关联对象!
select:去那当前行的column列值去查询关联的这个字段的对象信息!
拓展:
fetchType="eager" 立即加载
fetchType="lazy" 延迟加载
-->
<association property="userCard" column="id" javaType="UserCard"
select="com.itheima.dao.UserCardMapper.getUserCardById"/>
</resultMap>
<!-- List<User> findAll(); -->
<select id="findAll" resultMap="user1_1ResultMap">
select * from user
</select>
</mapper>
UserCardMapper.java
定义方法传入userId(其实就是主键)
public interface UserCardMapper {
UserCard getUserCardById(int userId);
}
UserCardMapper.xml
namespace: 必须申明成被服务接口的路径
把userId传进来做主键
<?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.dao.UserCardMapper">
<!-- UserCard getUserCardById(int userId); -->
<select id="getUserCardById" resultType="UserCard">
select * from user_card where id = #{xxzxz}
</select>
</mapper>
最后我们来看运行结果:
public class MybatisDemo {
@Test
public void query1_1(){
// 1、获取与数据库的会话
SqlSession sqlSession = MybatisSqlSessionFactoryUtils.getSqlSession();
// 2、获取用户的数据访问层接口的代理对象,会自动找映射文件:UserMapper.xml文件
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 3、查询用户对象信息(目的是可以查询出1-1关联的身份证信息 )
List<User> users = userMapper.findAll();
for(User u : users){
System.out.println(u.getUserName());
}
System.out.println("------------------------------------");
for (User u : users){
System.out.println("身份证:" + u.getUserCard());
}
// 4、关闭会话
MybatisSqlSessionFactoryUtils.close(sqlSession);
}
}
这是没有开启延迟加载的,会直接把数据加载出来。
这是开启延迟加载的,会等到需要取数据的时候再去加载。
6 1-N的延迟加载
其实1-N和N-N是一样的,然后代码的配置也是跟1-1差不多的,所以直接上代码。
需求: 查询出用户对象的时候,可以查询出它的全部订单信息。用户 与 订单是 1-N的关系!
实现步骤:
1、必须在实体类中先建立1-N的关系。
略。
2、实现1-N的关联映射查询实现。
public interface UserMapper {
List<User> findAll();
}
注意这个UserMapper.xml中的 fetchType=“lazy” : 延迟记载, fetchType=“eager” : 立即加载是就近原则,这里设置了,核心配置设置文件也设置了,优先选择这里,因为比较近。
collection是1-N和N-N的。
<?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.dao.UserMapper">
<resultMap id="user1_NResultMap" type="User">
<id column="id" property="id"></id>
<!-- 一个用户包含一批订单,官方规定了1-N的字段必须使用如下标签映射: collection -->
<!--
property: 多方的属性名
javaType:多方的属性类型
ofType: 集合中每个元素的类型
column: 根据当前用户的哪个字段的值去查询关联的订单信息对象
select : 根据用户id查询它的订单信息的方法,
fetchType="lazy" : 延迟记载
fetchType="eager" : 立即加载
-->
<collection property="orderForms" javaType="list" ofType="OrderForm" fetchType="lazy"
column="id" select="com.itheima.dao.OrderFormMapper.getOrdersByUserId" />
</resultMap>
<!-- List<User> findAll(); -->
<select id="findAll" resultMap="user1_NResultMap">
select * from user
</select>
</mapper>
public interface OrderFormMapper {
List<OrderForm> getOrdersByUserId(int userId);
}
<?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.dao.OrderFormMapper">
<!-- List<OrderForm> getOrdersByUserId(int userId);
-->
<select id="getOrdersByUserId" resultType="OrderForm">
select * , user_id userId , create_time createTime from order_form where user_id = #{xDsd}
</select>
</mapper>
public class MybatisDemo {
@Test
public void query1_N(){
// 1、获取与数据库的会话
SqlSession sqlSession = MybatisSqlSessionFactoryUtils.getSqlSession();
// 2、获取用户的数据访问层接口的代理对象,会自动找映射文件:UserMapper.xml文件
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 3、查询用户对象信息(目的是可以查询出1-N关联的订单信息 )
List<User> users = userMapper.findAll();
for (User user : users) {
System.out.println(user.getUserName());
}
System.out.println("------------------------------------------------");
for(User u : users){
System.out.println(u.getOrderForms());
}
// 4、关闭会话
MybatisSqlSessionFactoryUtils.close(sqlSession);
}
}
没有延迟加载
延迟加载