ZB-038-04MyBatis与设计模式

MyBatis与设计模式

多种设计模式的集大成者

每当你看到 xxxFactory 的时候,基本可以断定它是一个工厂模式

  • 抽象工厂模式: SqlSessionFactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface SqlSessionFactory {

SqlSession openSession();

SqlSession openSession(boolean autoCommit);

SqlSession openSession(Connection connection);

SqlSession openSession(TransactionIsolationLevel level);

SqlSession openSession(ExecutorType execType);

SqlSession openSession(ExecutorType execType, boolean autoCommit);

SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);

SqlSession openSession(ExecutorType execType, Connection connection);

Configuration getConfiguration();

}

单例模式: ErrorContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ErrorContext {

private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<>();

// ...

// 私有方法,意味着外部无法使用这个构造器创建实例
private ErrorContext() {
}


public static ErrorContext instance() {
ErrorContext context = LOCAL.get();
// 保证了 context 只有一个
if (context == null) {
context = new ErrorContext();
LOCAL.set(context);
}
return context;
}

// ...

}

单例模式有很多变体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 你可以这样
public class MySingleton {

private static final MySingleton INSTANCE = new MySingleton();

private MySingleton(){}

public static MySingleton getInstance(){
return INSTANCE;
}
}

// 也可以这样,但是多线程下可能有问题
public class MySingleton {

private static MySingleton INSTANCE = null;

private MySingleton(){}

public static MySingleton getInstance(){
if(INSTANCE == null){
INSTANCE = new MySingleton();
}
return INSTANCE;
}
}

// 还可以这样 使用枚举
public enum MySingleton {

INSTANCE;

public void dosomething(){

}
}

代理模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// xml方式
public void deleteUserById(Integer id) {
try (SqlSession session = sqlSessionFactory.openSession(true)) {
session.delete("MyMapper.deleteUserById", id);
}
}

// 代理模式
interface UserMapper{
@Delete("delete from user where id =#{id}")
void deleteUserById(@Param("id") Integer id);
}
public void deleteUserById2(Integer id) {
try (SqlSession session = sqlSessionFactory.openSession(true)) {
// 此行断点,进去就可以看到 MapperProxyFactory 就是一种代理模式
UserMapper userMapper = session.getMapper(UserMapper.class);
userMapper.deleteUserById(id);
}
}

原理

  • 每当你写一个 interface UserMapper 的时候
  • 它就会把你这个接口传递给 Proxy代理,帮你动态创建代理实例
  • 通过 反射 invoke 调用接口相应的方法

装饰器模式

在已有如 Utils类 功能上增加附加功能,但是不改变 Utils类内部的逻辑

典型方式:缓存 如 CachingExecutor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class CachingExecutor implements Executor {

private final Executor delegate;
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
// 委托查询
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

// ...
}

模版模式

  • BaseExecutor
1
2
3
4
5
6
7
8
9
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();
return doUpdate(ms, parameter);
}

适配器模式 adapter

如电源插口

  • 中国的电源
  • 美国的电源
  • 日本的电源

MyBatis 有很多种日志 Log

为他们提供接口,自己按标准去实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface Log {

boolean isDebugEnabled();

boolean isTraceEnabled();

void error(String s, Throwable e);

void error(String s);

void debug(String s);

void trace(String s);

void warn(String s);

}