我们前面看过了一大堆的理论了,我们现在来看看实战操作。
mybatis是数据库操作的框架,也就是我们常说的持久化层。那么持久化层面对的就是和数据库读取写入做操作,也就是说这种场合下我们就要面对一个不得不提的问题就是和数据库这种磁盘操作是慢的,我们一般就引入缓存层来解决,其实mybatis也是提供了关于缓存的解决方案。也就是常说的一级二级缓存。
我们在进入一二级缓存的实现之前先想想我们自己操作的时候基于mybatis的实现原理如何实现这个缓存操作。
我们之前就知道了Mybatis在实现查询的时候对mapper是使用的jdk的动态代理实现的。我们就来模拟一下这个实现。
我们是在源码上面操作的,所以只需要在源码那个pom文件添加一下依赖就可以了。
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Builder
public class Order {
private int id;
private int price;
}
我们这里就不真实连接数据库了,就写个伪代码
package com.yx.cache;
import com.yx.domain.Order;
/**
* @author: levi
* @description: TODO
* @date: 2022-10-15 17:29
* @version: 1.0
*/
public interface OrderDao {
@MyCache(type = "redis")
Order queryById(int id);
}
package com.yx.cache;
import com.yx.domain.Order;
/**
* @author: levi
* @description: TODO
* @date: 2022-10-15 17:29
* @version: 1.0
*/
public class OrderDaoImpl implements OrderDao{
@Override
public Order queryById(int id) {
Order order = Order.builder().id(1).price(100).build();
return order;
}
}
// 定义一个缓存map
public static Map<String,Object> cache = new HashMap<>();
@Test
public void testCache() throws IOException{
OrderDao orderDao = new OrderDaoImpl();
OrderDao instance = (OrderDao)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{OrderDao.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
// 如果方法有query我们就去做缓存的操作,其余的删除修改插入就不了
if (method.getName().contains("query")) {
result = MybatisTest.cache.get(String.valueOf(args[0]));
if (Objects.nonNull(result)) {
return result;
} else {
// 缓存没查出来就走真实执行,然后返回结果,并且塞到缓存里面
result = method.invoke(orderDao, args);
MybatisTest.cache.put(String.valueOf(args[0]), result);
}
}
return result;
}
});
// 调用方法,并且输出
System.out.println(instance.queryById(1));
}
运行结果输出,Order(id=1, price=100)
上面我们写死的判断名字里面有没有query,现在用注解改一下。
// 创建注解
import java.lang.annotation.*;
/**
* @author: levi
* @description: TODO
* @date: 2022-10-15 17:52
* @version: 1.0
*/
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyCache {
String type();
}
@Test
public void testCacheInno() throws IOException{
OrderDao orderDao = new OrderDaoImpl();
OrderDao instance = (OrderDao)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{OrderDao.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
MyCache myCache = method.getDeclaredAnnotation(MyCache.class);
if (myCache != null) {
// 判断缓存的执行类型
if("local".equals(myCache.type())){
result = MybatisTest.cache.get(String.valueOf(args[0]));
if (Objects.nonNull(result)) {
return result;
} else {
result = method.invoke(orderDao, args);
MybatisTest.cache.put(String.valueOf(args[0]), result);
}
}else if("redis".equals(myCache.type())){
System.out.println("redis缓存");
}else {
System.out.println("默认走本地缓存");
}
}
return result;
}
});
System.out.println(instance.queryById(1));
}
我们这里就是打个预防针,我们想想可以在代理这里执行操作的时候加上缓存的判断执行,其实实际上他也是这么做的,我们这里就是大致理解一下,为下面mybatis的操作打个预告。