1. 延迟加载
1.1 基本概念1.2 延迟加载的优缺点1.3 延迟加载
1.3.1 局部懒加载1.3.2 全局懒加载 2. MyBatis缓存
2.1 基本概念
2.1.1 应用场景 2.2 一级缓存
2.2.1 基本概念2.2.2 缓存的使用2.2.3 清除缓存 2.3 二级缓存
2.3.1 基本概念2.3.2 缓存的使用2.3.3 二级缓存的问题2.3.4 脏读问题 3. MyBatis注解
3.1 常用注解3.2 增删改查
3.2.1 实体类3.2.2 mybatis配置3.2.3 Mapper接口3.3.4 测试代码 3.3 一对一查询
3.3.1 基本需求3.3.2 实体类3.3.3 Mapper接口3.3.4 mybatis配置3.3.5 测试代码 3.4 二级缓存
3.4.1 配置SqlMapConfig.xml 3.4.2 使用二级缓存 3.5 延迟加载
3.5.1 延迟加载配置
1. 延迟加载 1.1 基本概念
比如 当我们要查询用户的信息以及其关联的订单信息时, 。实际开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的订单信息。此时就是我们所说的延迟加载
举例说明 :
- 问题 : 在一对多中,当我们有一个用户,它有个100个订单 在查询用户的时候,要不要把关联的订单查出来? 在查询订单的时候,要不要把关联的用户查出来? - 回答 : 在查询用户时,用户下的订单应该是,什么时候用,什么时候查询。 在查询订单时,订单所属的用户信息应该是随着订单一起查询出来。
延迟加载 : 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。
1.2 延迟加载的优缺点优点:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表 速度要快。缺点:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时 间,所以可能造成用户等待时间变长,造成用户体验下降。在多表中: 一对多,多对多:通常情况下采用延迟加载 一对一(多对一):通常情况下采用立即加载注意:延迟加载是基于嵌套查询来实现的 1.3 延迟加载 1.3.1 局部懒加载
sqlMapConfig 配置 : 当调用 toStirng() 方法的时候就会加载
UserMapper.xml 配置 fetchType="lazy"
1.3.2 全局懒加载
在Mybatis的核心配置文件中可以使用setting标签修改全局的加载策略。
局部的加载策略优先级高于全局的加载策略
sqlConfigMap.xml 配置
OrderMapper.xml 配置
不需要任何配置, 但是如果设置了局部加载, 要删除掉, 否则局部加载/不加载优先级高于全局懒加载
2. MyBatis缓存 2.1 基本概念 2.1.1 应用场景
当用户频繁查询某些固定的数据时,第一次将这些数据从数据库中查询出来,保存在缓存中。
用户再次查询这些数据时,不用再通过数据库查询,而是去缓存里面查询。减少网络连接和数据库查询带来的损耗,从而提高我们的查询效率,减少高并发访问带来的系统性能问题。
经常查询一些不经常发生变化的数据,使用缓存来提高查询效率。
像大多数的持久化框架一样,Mybatis也提供了缓存策略,通过缓存策略来减少数据库的查询次数,
从而提高性能。 Mybatis中缓存分为一级缓存,二级缓存。
2.2 一级缓存 2.2.1 基本概念一级缓存是SqlSession级别的缓存,是默认开启的所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往
只执行一次SQL因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库
一级缓存是SqlSession范围的缓存,执行SqlSession的C(增加)U(更新)D(删除)操作,或者调
用clearCache()、commit()、close()方法,都会清空缓存
案例 :
- 第一次发起查询用户id为41的用户信息,先去找缓存中是否有id为41的用户信息,如果没有,从数据库 查询用户信息。得到用户信息,将用户信息存储到一级缓存中。如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这 样做的目的为了让缓存中存储的是最新的信息,避免脏读。第二次发起查询用户id为41的用户信息,先去找缓存中是否有id为41的用户信息,缓存中有,直接从缓 存中获取用户信息。
直接调用 sqlSession 的方法
//调用sqlSession清除缓存的方法 sqlSession.clearCache();
在sqlMapConfig 中配置
< select flushCache="true">2.3 二级缓存 2.3.1 基本概念
二级缓存是namspace级别(跨sqlSession)的缓存,是默认不开启的二级缓存的开启需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。
也就是要求实体类实现Serializable接口,配置方法很简单,只需要在映射XML文件配置
sqlMapConfig.xml 配置
UserMapper.xml 配置
实体类需要实现 Serializable 接口
2.3.3 二级缓存的问题二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个
SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
映射语句文件中的所有select语句将会被缓存。
映射语句文件中的所有insert、update 和 delete语句会刷新缓存
mybatis的二级缓存因为是namespace级别,所以在进行多表查询时会产生脏读问题
第一次查询后用户以及其订单信息会将查询结果存储到 usernamespace 缓存中如果中间对订单信息进行更新, 更新操作只会清除 ordernamespace 中的二级缓存再次查询时, 订单1金额还是 199 3. MyBatis注解 3.1 常用注解
@Insert:实现新增,代替了
User 实体类
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
}
3.2.2 mybatis配置
jdbc.properties 配置
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis_db jdbc.username=root jdbc.password=123456
sqlMapConfig.xml 配置
3.2.3 Mapper接口
UserMapper 接口
package cn.knightzz.mapper;
import cn.knightzz.entity.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface UserMapper {
@Select("select * from `user`")
public List findAll();
@Insert("insert into `user`(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address})")
public void saveUser(User user);
@Update("UPDATE `user` SET username = #{username},birthday = #{birthday},sex = #{sex},address = #{address} WHERe id = #{id}")
public void updateUser(User user);
@Delete("DELETE FROM `user` where id = #{id}")
public void deleteUser(Integer id);
}
3.3.4 测试代码
测试代码
package cn.knightzz.test;
import cn.knightzz.entity.User;
import cn.knightzz.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MyBatisMapperTest {
private User user = new User();
private SqlSession sqlSession;
private UserMapper mapper;
@Before
public void init() throws IOException {
InputStream stream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(stream);
sqlSession = build.openSession(true);
mapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void findAllTest(){
List users = mapper.findAll();
for (User user1 : users) {
System.out.println(user1);
}
}
@Test
public void updateUserTest(){
user.setId(1);
user.setUsername("卡莎");
user.setBirthday(new Date());
user.setAddress("湖北武汉");
mapper.updateUser(user);
}
@Test
public void deleteUserTest(){
mapper.deleteUser(2024);
}
@After
public void destroy(){
sqlSession.close();
}
}
3.3 一对一查询
3.3.1 基本需求
查询一个订单,与此同时查询出该订单所属的用户
SELECT * FROM orders;
SELECt * FROM `user` WHERe id = #{订单的uid};
3.3.2 实体类
Order
public class Order {
private Integer id;
private Integer uid;
private Double money;
private Date orderTime;
private User user;
}
User
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List orderList;
}
3.3.3 Mapper接口
OrderMapper
package cn.knightzz.mapper;
import cn.knightzz.entity.User;
import org.apache.ibatis.annotations.Select;
public interface OrderMapper {
@Select("select * from `orders` where uid = #{uid}")
public User findByUid(Integer uid);
}
UserMapper
package cn.knightzz.mapper;
import cn.knightzz.entity.User;
import org.apache.ibatis.annotations.*;
import javax.annotation.Resources;
import java.util.List;
public interface UserMapper {
@Select("select * from `user`")
@Results({
@Result(id = true, column = "id", property = "id"),
@Result(column = "brithday", property = "brithday"),
@Result(column = "sex", property = "sex"),
@Result(column = "address", property = "address"),
@Result(property = "orderList", javaType = List.class,
column = "id", many = @Many(select = "cn.knightzz.mapper.OrderMapper.findByUid"))
})
public ListfindAllWithOrder();
}
3.3.4 mybatis配置
需要在 sqlMapConfig.xml 增加 OrderMapper 配置
3.3.5 测试代码
package cn.knightzz.test;
import cn.knightzz.entity.Order;
import cn.knightzz.entity.User;
import cn.knightzz.mapper.OrderMapper;
import cn.knightzz.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MyBatisMapperTest {
private User user = new User();
private SqlSession sqlSession;
private UserMapper mapper;
private OrderMapper orderMapper;
@Before
public void init() throws IOException {
InputStream stream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(stream);
sqlSession = build.openSession(true);
mapper = sqlSession.getMapper(UserMapper.class);
orderMapper = sqlSession.getMapper(OrderMapper.class);
}
@Test
public void findAllWithOrder(){
List allWithOrders = mapper.findAllWithOrder();
for (User allWithOrder : allWithOrders) {
System.out.println(allWithOrder);
}
}
@After
public void destroy(){
sqlSession.close();
}
}
3.4 二级缓存
3.4.1 配置SqlMapConfig.xml
3.4.2 使用二级缓存
@CacheNamespace
public interface UserMapper {...}
3.5 延迟加载
3.5.1 延迟加载配置
fetchType = FetchType.LAZY 表示懒加载fetchType = FetchType.EAGER 表示立即加载fetchType = FetchType.DEFAULT 表示使用全局配置
@Select("select * from `user`")
@Results({
@Result(id = true, column = "id", property = "id"),
@Result(column = "brithday", property = "brithday"),
@Result(column = "sex", property = "sex"),
@Result(column = "address", property = "address"),
@Result(property = "orderList", javaType = List.class,
column = "id", many = @Many(select = "cn.knightzz.mapper.OrderMapper.findByUid", fetchType= FetchType.LAZY))
})
public ListfindAllWithOrder();



