一、代码实例1
public class Main {
/**
* 通过java.lang.System#setProperty方法设置系统属性
* cglib.debugLocation=指定的字节码输出目录
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
System.setProperty("cglib.debugLocation", "./");
//1.加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//2.获取sqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//3.获取sqlSession会话对象
InvocationHandler dd;
SqlSession sqlSession = sqlSessionFactory.openSession();
Connection connection= sqlSession.getConnection();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
User user=new User();
user.setUserId(1);
user.setUserName("zhongguochongqing");
user.setDeptName("测试");
user.setRealName("太阳");
user.setPassword("123456");
int res=userMapper.insert(user);
sqlSession.commit();
sqlSession.close();
System.out.println(res);
}
}
1、看下怎么构建SqlSessionFactory
new SqlSessionFactoryBuilder() 是一个默认构造函数,没有什么好看的。
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
///解析mybatis的全部配置信息
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
///parser.parse() 解析成一个Configuration 里面所有的信息都在里面了
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
//最后构造一个默认的SqlSessionFactory 实现类对象
return new DefaultSqlSessionFactory(config);
}
//直接把配置信息赋值给了一个属性
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
2、然后看sqlSession = sqlSessionFactory.openSession();
///开始获取一个sqlSession
public SqlSession openSession(boolean autoCommit) {
///这里要获取一个 默认的ExecutorType,ExecutorType是一个枚举: SIMPLE REUSE BATCH
//当前默认返回 SIMPLE
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
//然后进入openSessionFromDataSource 方法
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
///根据配置信息获取一个 事务工厂,这个工厂就是
///为后面创建一个具体的事务,后面再看看具体它是怎么创建这个事务工厂的 todo
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
///然后创建了一个事务对象因为后面执行sql肯定是要用到事务的,
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
///然后构造一个simple类型的Executor,
//如果设置了拦截器的话就会返回这个执行器的代理对象
final Executor executor = configuration.newExecutor(tx, execType);
///构造一个 sqlSession,可以看到这个sqlSession里面是有 全局配置对象,执行器,和有关事务
//提交相关的信息 autoCommit
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
///当前this =configuration ,这里是构造 Executor的详细步骤,里面也比较简单,就是把
//配置对象 和事务对象传入,根据前面的executorType 构造指定的执行器
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
///mybatis默认缓存时有效的,这里就用缓存执行器 包装了下原始的执行器,
///因为在mybatis中一级缓存时在executor里面的
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
///这里是给执行器 安装拦截器
return (Executor) interceptorChain.pluginAll(executor);
}
///SimpleExecutor 是BaseExecutor的子类,最终SimpleExecutor的构造函数也会调用这个
//具体内容如下:
protected BaseExecutor(Configuration configuration, Transaction transaction) {
//设置下事务对象
this.transaction = transaction;
///初始化延迟加载的 缓队列
this.deferredLoads = new ConcurrentLinkedQueue<>();
//设置下缓存
this.localCache = new PerpetualCache("LocalCache");
this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
this.closed = false;
this.configuration = configuration;
//this.warpper 就是simpleExecutor
this.wrapper = this;///这是一个simpleExecutor的自引用
}
结论:
从上面的代码得出的一些重要信息是: 在构造sqlSession时就只是一些简单的创建一些对象,然后赋值下而已,构建sqlSession对象时会构造: 临时的事务工厂然后构造一个事务对象,也会创建一个Executor对象,同时这个对象会用CacheExecutor包装下。就是说在创建SqlSession对象时或创建几个重要对象,且这些对象是和SqlSession关联的,然后就是给执行器添加拦截器
a: 事务对象 b: 执行器executor ,事务对象是在执行器中
3、然后看看拦截器的添加过程
///首先这个方法是 interceptorChain对象的,而interceptorChain是在 全局配置对象中的属性,
//在解析配置的时候创建的interceptorChain
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
///调用拦截器的 plugin方法,这里就是生成target(此时是Executor)
target = interceptor.plugin(target);
}
return target;
}
///这个是自定义的一个拦截器MyExecutorInterceptor 的plugin方法,这里什么都没有做
//就是返回原始的Executor
@Override
public Object plugin(Object target) {
System.out.println("MyExecutorInterceptor-plugin");
return target;
}
4、然后看看UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
///DefaultSqlSession 的方法,Type是具体Mapper的接口类
//Mapper还是有全局配置对象来构建
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
///进入configuration.getMapper,里面有一个mapper注册器MapperRegistry
//这个mapper注册器中有
//Map<Class<?>, MapperProxyFactory<?>> knownMappers = new ConcurrentHashMap<>();
//Class 就是我们自定义的Mapper接口类,对应的时这个mapper的动态代理 创建工厂
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
///具体进入MapperRegistry.getMapper 方法中。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//从缓存中获取一个 代理工厂,应是在 解析配置文件的时候就创建好了
//每一个Mapper接口都对应一个代理工厂,代理工厂中有UserMapper这个接口Class对象,同时
//还有 Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
//这个接口定义的所有方法的执行器缓存Map
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
///用工厂创建一个UserMapper接口的 MapperProxy型的代理对象。就是用jdk代理的方式
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
///return mapperProxyFactory.newInstance(sqlSession);的方法如下
public T newInstance(SqlSession sqlSession) {
///这个MapperProxy 是一个InvocationHandler 用来生成代理的,它有几个重要属性
//1. 当前UserMappr接口Class,还有sqlSession
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
///然后创建一个mapperProxy 代理,代理对象实现了UserMapper接口,里面的InvocationHandler 就是mapperProxy 本身,最后调用UserMapper的方法都是会调用这个代理
return newInstance(mapperProxy);
}
上面的代码主要是 获取UserMapper接口的jdk实现的动态代理类,具体代码内容可以查看:【JDK动态代理】以下是mybatis生产一个Mapper接口动态代理类-CSDN博客
5、下面就是执行数据库操作
///首先进入UserMapper 的代理类的 insert方法
public final int insert(User var1) {
try {
///super.h 就是上面的mapperProxy对象 ,然后调用者mapperProxy的invoker
//this就是当前代理对象本身,m4就是UserMapper接口的insert方法Method对象
return (Integer)super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
///然后进入mapperProxy 的invoke的方法中
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
///如果是Object类的方法 就不拦截
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
///然后用cachedInvoker封装method,返回一个MapperMethodInvoker(默认PlainMethodInvoker) 在调用MapperMethodInvoker 的invoker
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
///调用invoker后面会进入MapperMethod的execute方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
///解析参数 里面由ParamNameResolver类解析参数
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
后面会进入 DefaultSqlSession 中的update方法
///这里才开始用执行器
public int update(String statement, Object parameter) {
try {
dirty = true;
//通过org.bqs.mapper.UserMapper.insert 获取到对应的MappedStatement
///MappedStatement里面封装了要执行的sql语句相关的信息,它对应的
//就是mapper.xml文件中的 一个sql配置
MappedStatement ms = configuration.getMappedStatement(statement);
///在创建sqlSession时创建的executor 开始执行
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
后面来到SimpleExecutor 的doUpdate方法中
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
//这是一个jdbc的Statement
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
///利用全局配置 创建一个StatementHandler 默认是 RoutingStatementHandler 然后内部要包含了具体的 PreparedStatementHandler ,要是一个静态代理模式,由于我加了拦截器 ,当前返回的时一个代理对象StatementHandler
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());
///利用StatementHandler 类执行jdbc的Statement 具体内容是啥
//
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
configuration.newStatementHandler 方法
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,
Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
///返回一个StatementHandler 它里面封装了 Executor,ParameterHandler ResultSetHandler 还有BoundSql MapperedStatement
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,
rowBounds, resultHandler, boundSql);
///处理StatementHandler类型的拦截器
return (StatementHandler) interceptorChain.pluginAll(statementHandler);
}
6、看看StatementHandler 具体做了啥
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
}
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.prepareStatement(sql);
} else {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(),
ResultSet.CONCUR_READ_ONLY);
}
}