-
掌握mybatis延迟加载
-
掌握mybatis缓存
-
掌握mybatis注解开发
mybatis延迟加载
延迟加载介绍
延迟加载也叫懒加载。指的是按需加载,在实际用到数据的时候才加载,不需要用到数据的时候不加载。延迟加载的特点先从单表查询,需要时再从关联表查询数据。因为都是单表的操作,对于提升数据库性能有一定的帮助。
案例演示
使用延迟加载,都是在多表关联查询的场景。mybatis框架提供的一对一关联查询配置(association)标签,一对多关联查询配置(collection)标签,支持延迟加载。
association延迟加载
需求
查询全部订单数据,并且关联查询出订单所属的用户数据。使用延迟加载方式实现。
需求实现
创建项目
改造UserMapper.xml,增加根据用户Id查询的sql配置
<!--根据用户Id查询用户-->
<select id="findUserById" parameterType="int" resultType="user">
SELECT
u.id,
u.username,
u.birthday,
u.sex,
u.address
FROM
`user` u
WHERE
id = #{id}
</select>
改造OrdersMapper.xml,一对一关联查询
<!-- 配置订单到用户的一对一关联关系,说明:
type:要映射的类型
id:唯一标识名称,通过id引用该resultMap
-->
<resultMap type="orders" id="ordersUsersResultMap">
<!-- 配置订单主键字段对应关系 -->
<id column="id" property="id"/>
<!-- 配置订单的普通字段对应关系 -->
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- association:配置一对一关联关系,说明:
1.使用延迟加载方式实现:
select:配置要调用的查询sql语句id(名称空间+"."+sql语句id)。
column:配置要传递的参数字段
-->
<association property="user" javaType="User"
select="cn.itheima.mapper.UserMapper.findUserById"
column="user_id">
</association>
</resultMap>
<!-- 查询全部订单数据,并且关联查询订单所属的用户数据(resultMap)-->
<select id="findAllOrdersAndUserResultMap" resultMap="ordersUsersResultMap">
SELECT
o.id,
o.user_id,
o.number,
o.createtime,
o.note
FROM
orders o
</select>
配置sqlMapConfig.xml,开启mybatis延迟加载
打开mybatis官方文档,找到settings配置:
-
lazyLoadingEnabled:开启延迟加载开关,默认是false未开启,需要配置为true
-
aggressiveLazyLoading:将积极加载改为消极加载,默认是false消极加载,不需要配置
<!--全局参数配置-->
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--加载策略:消极加载-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
测试只查询订单数据(不查询用户数据)
/**
* 测试查询全部订单数据,并且关联查询订单所属的用户数据(resultMap)
*/
@Test
public void findAllOrdersAndUserResultMapTest(){
//1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取接口代理对象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
// 4.执行数据库操作
List<Orders> list = mapper.findAllOrdersAndUserResultMap();
for(Orders o:list){
// 只获取订单数据,此时不会去查询用户数据
System.out.println("订单id:"+o.getId()+",订单编号:"+o.getNumber()+
",订单创建时间:"+o.getCreatetime()+",所属用户id:"+o.getUserId());
}
// 5.释放资源
sqlSession.close();
}
测试延迟加载用户数据
/**
* 测试查询全部订单数据,并且关联查询订单所属的用户数据(resultMap)
*/
@Test
public void findAllOrdersAndUserResultMapTest(){
//1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取接口代理对象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
// 4.执行数据库操作
List<Orders> list = mapper.findAllOrdersAndUserResultMap();
for(Orders o:list){
// 只获取订单数据
System.out.println("订单id:"+o.getId()+",订单编号:"+o.getNumber()+
",订单创建时间:"+o.getCreatetime()+",所属用户id:"+o.getUserId());
// 获取用户数据,延迟加载方式去查询用户数据
System.out.println("订单所属用户数据:"+o.getUser());
}
// 5.释放资源
sqlSession.close();
}
collection延迟加载
需求
查询全部用户数据,并且关联查询出用户所有的订单数据。使用延迟加载方式实现。
需求实现
改造OrdersMapper.xml,增加根据用户id查询订单数据配置
<!--根据用户id查询订单数据-->
<select id="findOrdersByUserId" parameterType="int" resultType="orders">
SELECT
o.id,
o.user_id,
o.number,
o.createtime,
o.note
FROM
orders o
WHERE
o.user_id=#{id}
</select>
改造UserMapper.xml,一对多关联查询
<!-- 配置用户到订单的一对多关联关系,说明:
type:要映射的类型
id:唯一标识名称,通过id引用该resultMap
-->
<resultMap type="user" id="usersOrdersResultMap">
<!-- 配置用户的主键字段对应关系 -->
<id column="id" property="id"/>
<!-- 配置用户的普通字段对应关系 -->
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- collection:配置一对多关联关系,说明:
1.使用延迟加载方式实现
select:配置要调用的查询sql语句id(名称空间+"."+sql语句id)。
column:配置要传递的参数字段
-->
<collection property="ordersList" javaType="List" ofType="Orders"
select="cn.itheima.mapper.OrdersMapper.findOrdersByUserId"
column="id"
>
</collection>
</resultMap>
<!-- 查询全部用户数据,并且关联查询出用户的所有订单数据 -->
<select id="findAllUsersAndOrders" resultMap="usersOrdersResultMap">
SELECT
u.id,
u.username,
u.birthday,
u.sex,
u.address
FROM
`user` u
</select>
配置sqlMapConfig.xml,开启mybatis延迟加载
打开mybatis官方文档,找到settings配置:
-
lazyLoadingEnabled:开启延迟加载开关,默认是false未开启,需要配置为true
-
aggressiveLazyLoading:将积极加载改为消极加载,默认是false消极加载,不需要配置
<!--全局参数配置-->
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--加载策略:消极加载-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
测试值查询用户数据(不查询订单数据)
/**
* 测试查询全部用户数据,并且关联查询出用户的所有订单数据
*/
@Test
public void findAllUsersAndOrdersTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4.执行数据库操作
List<User> list = mapper.findAllUsersAndOrders();
for(User u:list){
// 只获取用户数据。此时不会查询订单数据
System.out.println("用户id:"+u.getId()+"用户名称:"+u.getUsername());
// 获取订单数据。延迟加载方式去查询订单数据
//System.out.println("用户:"+u.getUsername()+",拥有订单数量:"+u.getOrdersList().size());
}
// 5.释放资源
sqlSession.close();
}
测试延迟加载订单数据
/**
* 测试查询全部用户数据,并且关联查询出用户的所有订单数据
*/
@Test
public void findAllUsersAndOrdersTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4.执行数据库操作
List<User> list = mapper.findAllUsersAndOrders();
for(User u:list){
// 只获取用户数据。此时不会查询订单数据
//System.out.println("用户id:"+u.getId()+"用户名称:"+u.getUsername());
// 获取订单数据。延迟加载方式去查询订单数据
System.out.println("用户:"+u.getUsername()+",拥有订单数量:"+u.getOrdersList().size());
}
// 5.释放资源
sqlSession.close();
}
mybatis缓存
mybatis框架提供了缓存策略,通过缓存策略可以减少查询数据库的次数,提升系统性能。在mybatis框架中缓存分为一级缓存,和二级缓存。
一级缓存
一级缓存介绍
一级缓存是sqlSession范围的缓存,只能在同一个sqlSession内部有效。它本身已经存在,一级缓存可以直接使用。
案例演示
创建项目
测试一级缓存
说明:通过同一个sqlSession对象,执行两次相同的查询,观察发出sql语句的次数。
/**
* 测试一级缓存
*/
@Test
public void OneCacheTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 创建用户对象
User user = new User();
user.setUsername("%小%");
user.setSex("1");
// 第一次查询
List<User> list = mapper.findUserByNameAndSex(user);
System.out.println(list);
System.out.println("-----------------华丽丽分割线--------------------");
// 第二次查询
List<User> list1 = mapper.findUserByNameAndSex(user);
System.out.println(list1);
// 4.释放资源
sqlSession.close();
}
执行结果说明:
虽然执行了两次查询,但是只执行了一次数据库操作(整个过程只有一条sql语句)。这就是mybatis提供的一级缓存在起作用。因为一级缓存的存在,第二次发起同样的查询,并没有再去查询数据库,而是直接从一级缓存中取数据。
一级缓存分析
一级缓存是sqlSession范围缓存。当调用sqlSession的修改、添加、删除、提交、关闭等方法时,一级缓存会被清空。
-
第一次查询id为1的用户,先去缓存中查找是否有id为1的用户数据。如果没有,从数据库中查询用户数据,并将数据存储到一级缓存中
-
第二次查询id为1的用户,先去缓存中查找是否有id为1的用户数据。此时缓存中有,直接从缓存中取出用户数据
-
如果sqlSession执行添加、修改、删除、提交、关闭等操作,清空sqlSession中的一级缓存数据。清空的目的是为了让缓存中存放最新数据,避免脏读
测试一级缓存清空
/**
* 测试一级缓存
*/
@Test
public void OneCacheTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 创建用户对象
User user = new User();
user.setUsername("%小%");
user.setSex("1");
// 第一次查询
List<User> list = mapper.findUserByNameAndSex(user);
System.out.println(list);
System.out.println("-----------------华丽丽分割线--------------------");
// sqlSession提交,测试清空一级缓存
sqlSession.commit();
// 第二次查询
List<User> list1 = mapper.findUserByNameAndSex(user);
System.out.println(list1);
// 4.释放资源
sqlSession.close();
二级缓存
二级缓存介绍
二级缓存是mapper映射级别缓存,作用范围跨越sqlSession,即可以在多个sqlSession之间共享二级缓存数据。
案例演示
在sqlMapConfig.xml配置开启二级缓存
打开mybatis官方文档,找到settings配置:
<!--全局参数配置-->
<settings>
<!--配置开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
修改用户实体类对象,实现java.io.Serializable接口
在UserMapper.xml,开启使用缓存
二级缓存还需要在具体的mapper映射文件中明确开启,这样做的原因是缓存数据要消耗资源,只有在需要使用的时候开启,可以避免资源的过度消耗。
测试二级缓存
说明:通过两个sqlSession对象,执行两次相同的查询,观察发出sql语句的次数。
/**
* 测试二级缓存
*/
@Test
public void TwoCacheTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession1
SqlSession sqlSession1 = sqlSessionFactory.openSession();
// 3.获取mapper代理对象
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
// 创建用户对象
User user = new User();
user.setUsername("%小%");
user.setSex("1");
List<User> list1 = mapper1.findUserByNameAndSex(user);
System.out.println(list1);
// 4.释放资源
sqlSession1.close();
System.out.println("-----------------华丽丽分割线--------------------");
// 5.打开SqlSession2
SqlSession sqlSession2 = sqlSessionFactory.openSession();
// 6.获取mapper代理对象
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
// 创建用户对象
User user2 = new User();
user2.setUsername("%小%");
user2.setSex("1");
List<User> list2 = mapper2.findUserByNameAndSex(user2);
System.out.println(list2);
// 7.释放资源
sqlSession2.close();
}
-
sqlSession1查询,从二级缓存中取数据,缓存命中率为0,即缓存中没有数据
-
发起sql语句执行数据库操作,取出数据,并把数据存放到二级缓存
-
sqlSession2查询,从二级缓存中取数据,缓存命中率为0.5,缓存中有数据,直接取出
二级缓存分析
-
sqlSession1执行UserMapper中的查询方法,将数据写入UserMapper的二级缓存中
-
sqlSession2执行UserMapper中的查询方法,从二级缓存中取出数据
-
sqlSession3执行UserMapper中的增删改、提交方法,清空UserMapper二级缓存
mybatis注解开发
在第一天mybatis框架的介绍中,mybatis框架是通过xml或者注解方式,配置实现java对象与sql语句的对应关系。也就是说mybatis框架中除了使用xml方式配置,还能使用注解的方式配置。
注解实现基本CRUD操作
需求
通过注解方式实现用户表(user)的增删改查操作。
-
新增一个用户
-
根据用户id查询用户
-
根据用户id修改用户
-
根据用户id删除用户
需求实现
创建项目
新增用户(@Insert)
在UserMapper接口中,增加新增用户方法
package cn.itheima.mapper;
import cn.itheima.po.User;
import org.apache.ibatis.annotations.Insert;
/**
* 持久层接口:UserMapper
*/
public interface UserMapper {
/**
* 1.新增用户
*
* 注解说明:
* @Insert:相当于xml配置中,insert标签,用于放置新增sql语句
*/
@Insert("insert into `user`(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})")
void addUserAnnotation(User user);
}
测试
package cn.itheima.test;
import cn.itheima.mapper.UserMapper;
import cn.itheima.po.User;
import cn.itheima.util.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import java.util.Date;
/**
* 测试注解开发
*/
public class UserMapperTest {
/**
* 测试新增用户
*/
@Test
public void addUserAnnotationTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 3.获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4.执行数据库操作
// 创建用户对象
User user = new User();
user.setUsername("注解开发-新增用户");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("注解开发-用户地址");
mapper.addUserAnnotation(user);
// 5.释放资源
sqlSession.close();
}
}
根据用户id查询用户(@Select)
在UserMapper接口中,增加查询方法
/**
* 2.根据用户id查询用户
*
* 注解说明:
* @Select:相当于xml配置中,select标签,用于放置查询sql语句
*/
@Select("select * from `user` where id=#{id}")
User findUserByIdAnnotation(Integer id);
测试
/**
* 测试根据用户id查询用户
*/
@Test
public void findUserByIdAnnotationTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4.执行数据库操作
User user = mapper.findUserByIdAnnotation(45);
System.out.println(user);
// 5.释放资源
sqlSession.close();
}
根据用户Id修改用户(@Update)
在UserMapper接口中,增加修改方法
/**
* 3.根据用户id修改用户
*
* 注解说明:
* @Update:相当于xml配置中,update标签,用于放置修改sql语句
*/
@Update("update `user` set username=#{username},sex=#{sex} where id=#{id}")
void updateUserAnnotation(User user);
测试
/**
* 测试根据用户id修改用户
*/
@Test
public void updateUserAnnotationTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 3.获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4.执行数据库操作
// 创建用户对象
User user = new User();
user.setId(45);
user.setUsername("注解开发-新增用户-进行修改操作");
user.setSex("2");
mapper.updateUserAnnotation(user);
// 5.释放资源
sqlSession.close();
}
根据用户id删除用户(@Delete)
在UserMapper接口中,增加删除方法
/**
* 4.根据用户id删除用户
*
* 注解说明:
* @Delete:相当于xml配置中,delete标签,用于放置删除sql语句
*/
@Delete("delete from `user` where id=#{id}")
void deleteUserAnnotation(Integer id);
测试
/**
* 测试根据用户id删除用户
*/
@Test
public void deleteUserAnnotationTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 3.获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4.执行数据库操作
mapper.deleteUserAnnotation(46);
// 5.释放资源
sqlSession.close();
}
获取数据库维护主键值(@SelectKey)
在addUser方法上,添加@SelectKey注解
/**
* 1.新增用户
*
* 注解说明:
* @Insert:相当于xml配置中,insert标签,用于放置新增sql语句
*
* @SelectKey:相当于xml配置中的selectKey标签,用于获取数据库维护的主键值
* 属性:
* statement:指定查询主键值sql语句
* keyColumn:主键字段
* keyProperty:主键属性
* resultType:主键字段属性类型
* before:布尔类型值,true相当于xml配置中的order="BEFORE";false相当于xml配置中的order="AFTER"
*/
@Insert("insert into `user`(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})")
@SelectKey(statement ={"select LAST_INSERT_ID()"},
keyColumn = "id",
keyProperty = "id",
resultType = Integer.class,
before = false)
void addUserAnnotation(User user);
测试
/**
* 测试新增用户
*/
@Test
public void addUserAnnotationTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 3.获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4.执行数据库操作
// 创建用户对象
User user = new User();
user.setUsername("注解开发-新增用户");
user.setSex("1");
user.setBirthday(new Date());
user.setAddress("注解开发-用户地址");
System.out.println("执行前:"+user);
mapper.addUserAnnotation(user);
System.out.println("执行后:"+user);
// 5.释放资源
sqlSession.close();
}
注解小结
在注解方式实现基本CRUD操作中,使用的注解有:
注解 | 描述 | 对应xml配置标签 |
---|---|---|
@Insert | 配置新增sql语句 | <insert/> |
@Select | 配置查询sql语句 | <select/> |
@Update | 配置修改sql语句 | <update/> |
@Delete | 配置删除sql语句 | <delete/> |
@SelectKey | 查询数据库维护主键值 | <selectKey/> |
注解高级应用
mybatis框架中注解除了实现基本的CRUD操作以外,还可以实现复杂的关系映射(一对一关联查询,一对多关联查询)。
复杂关系映射注解介绍
注解 | 描述 | 对应xml配置标签 |
---|---|---|
@Results | 配置java对象属性与sql语句中字段的对应关系,相当于xml配置中的<resultMap>标签 | <resultMap/> |
@Result | 相当于<resultMap>标签中的<id/> 和<result/>子标签 | <id/> <result/> |
@One | 一对一关系映射(延迟加载) | <association/> |
@Many | 一对多关系映射(延迟加载) | <collection/> |
案例演示
创建项目
注解实现一对一关联查询
需求:查询全部订单数据,并且关联查询出订单所属的用户数据。
编写OrderMapper接口
package cn.itheima.mapper;
import cn.itheima.po.Orders;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* 订单mapper接口
*/
public interface OrdersMapper {
/**
* 查询全部订单数据,并且关联查询出订单所属的用户数据
* 注解说明:
* @Select:
* 作用:放置查询的sql语句
*
* @Results:
* 作用:配置java对象属性与sql语句中字段的对应关系,相当于xml配置中的<resultMap>标签
*
* @Result:
* 作用:相当于<resultMap>标签中的<id/> 和<result/>子标签
* 属性:
* id:布尔类型值,设置是否是主键字段。true是主键字段。默认值是false
* column:字段名称
* property:属性名称
*/
@Select("SELECT o.id,o.user_id,o.number,o.createtime,o.note,u.username,u.address "+
"FROM orders o "+
"LEFT JOIN `user` u ON o.user_id = u.id"
)
@Results({
@Result(id=true,column = "id",property = "id"),
@Result(column = "user_id",property = "userId"),
@Result(column = "number",property = "number"),
@Result(column = "createtime",property = "createtime"),
@Result(column = "note",property = "note"),
@Result(column = "user_id",property = "user.id"),
@Result(column = "username",property = "user.username"),
@Result(column = "address",property = "user.address")
})
List<Orders> findAllOrdersAndUserAnnotation();
}
测试
package cn.itheima.test;
import cn.itheima.mapper.OrdersMapper;
import cn.itheima.po.Orders;
import cn.itheima.util.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import java.util.List;
/**
* 测试注解开发
*/
public class OrdersMapperTest {
/**
* 测试查询全部订单数据,并且关联查询出订单所属的用户数据
*/
@Test
public void findAllOrdersAndUserAnnotationTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取mapper代理对象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
// 4.执行数据库操作
List<Orders> list = mapper.findAllOrdersAndUserAnnotation();
for(Orders o:list){
System.out.println("订单编号:"+o.getNumber()+",所属用户信息:"+o.getUser());
}
// 5.释放资源
sqlSession.close();
}
}
注解实现一对一关联查询,延迟加载实现
需求:查询全部订单数据,并且关联查询出订单所属的用户数据。采用延迟加载实现。
在OrderMapper接口中增加查询方法
/**
* 查询全部订单数据,并且关联查询出订单所属的用户数据(延迟加载方式实现)
*
* 注解说明:
* @Select:
* 作用:放置查询sql语句
* @Results:
* 作用:配置java对象属性与sql语句中的字段名称对应关系,相当于xml中的<resultMap/>标签
* @Result:
* 作用:相当于<resultMap/>标签的<id/>和<result/>子标签
* 属性:
* id:设置是否是主键字段。true主键字段;默认是false
* column:字段名称
* property:属性名称
* one:配置一对一关联查询(延迟加载)
* @One:
* 作用:配置延迟加载一对一关联查询
* 属性:
* select:关联查询sql语句(接口全限定名称+"."+接口方法名称)
* fetchType:配置延迟加载方式
*/
@Select("SELECT o.id,o.user_id,o.number,o.createtime,o.note FROM orders o")
@Results(value = {
@Result(id = true, column = "id", property = "id"),
@Result(column = "user_id", property = "userId"),
@Result(column = "number", property = "number"),
@Result(column = "createtime", property = "createtime"),
@Result(column = "note", property = "note"),
@Result(column = "user_id", property = "user",
one = @One(select = "cn.itheima.mapper.UserMapper.findUserByIdAnnotation", fetchType = FetchType.LAZY)
)
})
List<Orders> findAllOrdersAndUserAnnotationLazy();
测试
/**
* 测试查询全部订单数据,并且关联查询出订单所属的用户数据(延迟加载方式实现)
*/
@Test
public void findAllOrdersAndUserAnnotationLazyTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取mapper代理对象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
// 4.执行数据库操作
List<Orders> list = mapper.findAllOrdersAndUserAnnotationLazy();
for(Orders o:list){
System.out.println("订单编号:"+o.getNumber()+",订单所属用户:"+o.getUser());
}
// 5.释放资源
sqlSession.close();
}
注解实现一对多关联查询
需求:查询全部用户数据,并且关联查询出用户的全部订单数据。采用延迟加载方式实现。
在UserMapper接口中,增加查询方法
/**
* 5.查询全部用户数据,并且关联查询出用户的全部订单数据
*
* 注解说明:
* @Select:
* 作用:配置查询sql语句
* @Results:
* 作用:配置java对象属性名称与sql语句字段名称对应关系,相当于xml配置中<resultMap/>标签
* @Result:
* 作用:相当于<resultMap/>标签的<id/>和<result/>子标签
* 属性:
* id:设置是否主键字段。true是主键字段。默认false
* column:字段名称
* property:属性名称
* many:配置一对多关联关系,相当于xml配置中<collection/>标签
* @Many:
* 作用:配置一对多关联查询
* 属性:
* select:指定关联查询sql语句(接口的全限定名称+"."+接口方法名称)
* fetchType:配置延迟加载方式
*/
@Select("SELECT u.id,u.username,u.birthday,u.sex,u.address FROM `user` u ")
@Results({
@Result(id=true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "birthday",property = "birthday"),
@Result(column = "sex",property = "sex"),
@Result(column = "address",property = "address"),
@Result(column = "id",property = "ordersList",
many = @Many(select = "cn.itheima.mapper.OrdersMapper.findAllOrdersByUserIdAnnotation",
fetchType = FetchType.LAZY))
})
List<User> findAllUsersAndOrdersAnnotation();
在OrderMapper接口中增加根据用户Id查询方法
/**
* 根据用户id查询订单数据
*
* 注解说明:
* @Select:配置查询sql语句
*/
@Select("select * from orders where user_id=#{id}")
List<Orders> findAllOrdersByUserIdAnnotation(Integer id);
测试
/**
* 查询全部用户数据,并且关联查询出用户的全部订单数据
*/
@Test
public void findAllUsersAndOrdersAnnotationTest(){
// 1.获取SqlSessionFactory
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
// 2.打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4.执行数据库操作
List<User> list = mapper.findAllUsersAndOrdersAnnotation();
for(User u:list){
System.out.println("用户名称:"+u.getUsername()+",用户订单:"+u.getOrdersList());
}
// 5.释放资源
sqlSession.close();
}