【mybatis】简介
【mybatis】mybatis & mybatis-plus & hibernate的区别
【mybatis】核心成员分析
【mybatis】Mybatis的工作流程
【mybatis】Mybatis中的一级、二级缓存
目录
概览
Mybatis是一款优秀的框架,里面也使用了以下几种设计模式供我们参考
- Builder 模式:例如
SqlSessionFactoryBuilder
、XMLConfigBuilder
、XMLMapperBuilder
、XMLStatementBuilder
、CacheBuilder
; - 工厂模式:例如
SqlSessionFactory
、ObjectFactory
、MapperProxyFactory
; - 单例模式:例如
ErrorContext
和LogFactory
; - 代理模式:Mybatis实现的核心,比如
MapperProxy
、ConnectionLogger
,用的jdk的动态代理;还有executor.loader
包使用了cglib或者javassist达到延迟加载的效果; - 组合模式:例如
SqlNode
和各个子类ChooseSqlNode
等; - 模板方法模式:例如
BaseExecutor
和SimpleExecutor
,还有BaseTypeHandler
和所有的子类例如IntegerTypeHandler
; - 适配器模式:例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;
- 装饰者模式:例如
cache
包中的cache.decorators
子包中等各个装饰者的实现; - 迭代器模式:例如迭代器模式
PropertyTokenizer
;
Builder 模式
Builder 模式也叫建造者模式,它是使用多个简单的对象一步一步构建成一个复杂的对象,它提供了一种创建对象的最佳方式。一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。
意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
何时使用:一些基本部件不会变,而其组合经常变化的时候。
如何解决:将变与不变分离开。
关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。
应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。
优点: 1、建造者独立,易扩展。 2、便于控制细节风险。
缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。
使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。
注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
实现
官方Demo
我们拿麦当劳为例:
一个典型的套餐可以是一个汉堡(Burger)和一杯冷饮(Cold drink)。
汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中。
冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中。
我们将创建一个表示食物条目(比如汉堡和冷饮)的 Item 接口和实现 Item 接口的实体类,以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类,汉堡是包在纸盒中,冷饮是装在瓶子中。
然后我们创建一个 Meal 类,带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilder。BuilderPatternDemo,我们的演示类使用 MealBuilder 来创建一个 Meal。
Item:用户点的食物清单List里的,定义每一种食物的属性接口,比如:
食物名称(鸡肉汉堡)、食物包装(纸盒装的)、食物价格(50块钱)
食物名称(可口可乐)、食物包装(瓶装的)、食物价格(30块钱)
。。。。。。。。
package com.maple.mybatis.design.patterns.builder;
/**
* 食物条目(汉堡和冷饮)
*/
public interface Item {
/**
* 名称:鸡肉汉堡
*
* @return
*/
String name();
/**
* 食物包装:汉堡是包在纸盒中,冷饮是装在瓶子中。
*
* @return
*/
Packing packing();
/**
* 价格
*
* @return
*/
float price();
}
Packing:食物的包装接口
package com.maple.mybatis.design.patterns.builder;
/**
* 包装:纸盒 和 瓶子 都会实现改接口
*/
public interface Packing {
String pack();
}
食物的包装接口实现类,有两种包装,纸盒 + 瓶装
Wrapper:纸盒包装
package com.maple.mybatis.design.patterns.builder;
/**
* 纸盒包装
*/
public class Wrapper implements Packing {
public String pack() {
return "Wrapper";
}
}
Bottle:瓶装
package com.maple.mybatis.design.patterns.builder;
/**
* 瓶子包装
*/
public class Bottle implements Packing {
public String pack() {
return "Bottle";
}
}
食物类目接口的实现类,因为我们有 汉堡和饮品 两种食物
Burger:汉堡
因为目前只知道汉堡是用纸盒包装的,不知道是鸡肉还是蔬菜汉堡,以及他们的价格,所以我们把Burger定义为基类,具体的食物名称和价格我们留给子类去重写
package com.maple.mybatis.design.patterns.builder;
/**
* 汉堡实现Item接口
*/
public abstract class Burger implements Item {
public Packing packing() {
return new Wrapper();
}
public abstract float price();
}
ChickenBurger:鸡肉汉堡
package com.maple.mybatis.design.patterns.builder;
/**
* 鸡肉汉堡,继承Burger,是纸盒的
*/
public class ChickenBurger extends Burger {
public String name() {
return "Chicken Burger";
}
public float price() {
return 50.5f;
}
}
VegBurger:蔬菜汉堡
package com.maple.mybatis.design.patterns.builder;
/**
* 蔬菜汉堡,继承Burger,是纸盒的
*/
public class VegBurger extends Burger {
public String name() {
return "Veg Burger";
}
public float price() {
return 25.0f;
}
}
ColdDrink:冷饮
因为目前只知道冷饮是瓶装的,不知道是可口可乐还是东鹏特饮,以及他们的价格,所以我们把ColdDrink定义为基类,具体的食物名称和价格我们留给子类去重写
package com.maple.mybatis.design.patterns.builder;
/**
* 冷饮实现Item接口
*/
public abstract class ColdDrink implements Item {
public Packing packing() {
return new Bottle();
}
public abstract float price();
}
Coke:可口可乐
package com.maple.mybatis.design.patterns.builder;
/**
* 都是冷饮,继承ColdDrink,瓶装的
*/
public class Coke extends ColdDrink{
public String name() {
return "Coke";
}
public float price() {
return 30.0f;
}
}
Pepsi:东鹏特饮
package com.maple.mybatis.design.patterns.builder;
/**
* 都是冷饮,继承ColdDrink,瓶装的
*/
public class Pepsi extends ColdDrink{
public String name() {
return "Pepsi";
}
public float price() {
return 35.0f;
}
}
Meal:吃晚餐了,我们可以给我们的晚餐里增加食物;看看我们这顿饭都点了啥;一共花了多少钱
package com.maple.mybatis.design.patterns.builder;
import java.util.ArrayList;
import java.util.List;
/**
* 吃晚餐了:我们可以给我们的晚餐里增加食物;看看我们这顿饭都点了啥;一共花了多少钱
*/
public class Meal {
private List<Item> items = new ArrayList<Item>();
public void addItem(Item item) {
items.add(item);
}
public float getCost() {
float cost = 0.0f;
for (Item item : items) {
cost += item.price();
}
return cost;
}
public void showItems() {
for (Item item : items) {
System.out.print("Item : " + item.name());
System.out.print(", Packing : " + item.packing().pack());
System.out.println(", Price : " + item.price());
}
}
}
MealBuilder:我们开始对外推出我们的套餐组合
有蔬菜汉堡+可乐组合,还有鸡肉汉堡+东鹏特饮组合。。。商家可以随意进行搭配
package com.maple.mybatis.design.patterns.builder;
/**
* 麦当劳套餐组合
*/
public class MealBuilder {
/**
* 蔬菜汉堡和Coke饮品
*
* @return
*/
public Meal prepareVegMeal() {
Meal meal = new Meal();
meal.addItem(new VegBurger());
meal.addItem(new Coke());
return meal;
}
/**
* 鸡肉汉堡和Pepsi饮品
*
* @return
*/
public Meal prepareNonVegMeal() {
Meal meal = new Meal();
meal.addItem(new ChickenBurger());
meal.addItem(new Pepsi());
return meal;
}
}
BuilderPatternDemo:那么当用户购买参套组合的时候,就可以看到每个组合里都有什么食物,如果套餐里没有的话,还可以继续增加食物,也可以实时看到价格
package com.maple.mybatis.design.patterns.builder;
/**
* 用户开始点餐了
* 展示用户点餐的类目和价格
*/
public class BuilderPatternDemo {
public static void main(String[] args) {
MealBuilder mealBuilder = new MealBuilder();
// A用户来份蔬菜汉堡+可口可乐套餐
Meal vegMeal = mealBuilder.prepareVegMeal();
System.out.println("Veg Meal");
vegMeal.showItems();
System.out.println("Total Cost: " +vegMeal.getCost());
// B用户来份鸡肉汉堡+东鹏特饮套餐
Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
System.out.println("\n\nNon-Veg Meal");
nonVegMeal.showItems();
System.out.println("Total Cost: " +nonVegMeal.getCost());
// B用户在上面的套餐基础上又增加了 一个蔬菜汉堡
nonVegMeal.addItem(new VegBurger());
System.out.println("\n\nNon-Veg Meal 增加蔬菜汉堡之后....");
nonVegMeal.showItems();
System.out.println("Total Cost: " +nonVegMeal.getCost());
}
}
Mybatis里的Builder模式
例如:SqlSessionFactoryBuilder
、XMLConfigBuilder
、XMLMapperBuilder
、XMLStatementBuilder
、CacheBuilder
SqlSessionFactoryBuilder
、XMLConfigBuilder
、XMLMapperBuilder
、XMLStatementBuilder 这几个都是有多个参数,不同的参数去设置不同的属性,所以使用了Builder模式,但是这里也说不上好与坏,因为这里不用Builder模式,只使用构造器方式来创建对象也完全OK的。
CacheBuilder这里就是规范的Builder模式啦,我们一起来看一下。
首先就是每个
字段给一个构建方法
每个字段构建完成之后,利用这些字段开始创建所需要的对象
调用方随意组合自己所需要的字段,最后调用build()方法开始创建对象