一、SqlSessionFactoryBuilder的作用及工作模式
作用:主要是加载XMLConfig配置文件,生成SqlSessionFactroy对象;通过建造者模式,构建非常复杂的SqlsessionFactory对象
主要代码说明:
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
//通过IO流读取xml配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
//通过XMLConfigBuilder对象的方法 parse();生产 Configuration配置对象
//并调用重载build方法,构建DefaultSqlSessionFavtory对象
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
//获取SqlSessionFactory对象
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
二、Configuration配置说明
Configuration配置主要是对各种配置属性进行保存,比如数据源、事务、缓存工厂、xml解析类型、日志类型;Mybatis都给出了默认的配置选项;他默认提供了一系列的注册机;
//事务类型
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
//数据源类型
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class); typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class); typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
//缓存类型
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class); typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
//数据库供应商类型。识别连接那种数据库
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
//xml解析类型
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);\
//日志类型
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
//动态代理类型
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
xml配置文件解析
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//指定根节点。调用解析方法
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
//解析方法
private void parseConfiguration(XNode root) {
try {
//参数配置节点解析,
propertiesElement(root.evalNode("properties")); //issue #117 read properties first
//别名配置节点解析
typeAliasesElement(root.evalNode("typeAliases"));
//插件节点解析
pluginElement(root.evalNode("plugins"));
//对象工厂节点解析
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
//系统配置节点解析
settingsElement(root.evalNode("settings"));
//environment节点解析
environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
//databaseId解析
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//类型处理器解析
typeHandlerElement(root.evalNode("typeHandlers"));
//mapper节点解析
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
所有节点解析后,都会设置道Configuration中去;
三、SqlSessionFactory的作用
SqlSessionFactory的作用是为了创建SqlSession;存在于整个mybatis应用生命周期;默认构建的是DefaultSqlSession;但Mybatis并没有对其进行单例的控制,
主要代码说明:
/*
* 参数说明:execType:执行器类型
* level:注册的事务类型
* autoCommit:是否自动提交,默认为false
*/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//获取Mybatis的配置环境,对于xml配置文件中的environment标签,
final Environment environment = configuration.getEnvironment();
//获取事务工厂,如果单独使用则使用的是jdbc的默认事务工厂,如果与spring进行整合的话,使用的是sring的事务
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//获取sql执行器
final Executor executor = configuration.newExecutor(tx, execType);
//构建Sqlsession
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();
}
}
四、SqlSession的作用
作为与数据库交互的对象,生命周期存在于每次与数据库交互期间;最常使用的是DefaulteSqlSession;默认提供了crud一系列基础接口方法,并且提供了获取Mapper与Conncation的接口方法;
主要方法: <T> T getMapper(Class<T> type);
该方法用于获取Mapper接口的代理类,执行最终的sql;
该SqlSession只要用于获取mapper的代理类。以及构建事务。为sql的执行做准备
五、Mapper接口代理类的产生+Mapper运行流程
Mybatis的Mapper接口,通过注册的形式,注册到Mybatis的配置对象中Conuration,使用 Configuration 中的MapperRegistry进行保存。
protected MapperRegistry mapperRegistry = new MapperRegistry(this);
MapperRegistry:
MapperRegistry是所有Mapper接口注册;内部使用Map保持,以接口的绝对地址作为key,以MapperProxyFactory作为value
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new
HashMap<Class<?>, MapperProxyFactory<?>>();
Mapper代理类的产生:
1、调用用Sqlsession.getMapper()
public <T> T getMapper(Class<T> type) {
//Mybatis配置类Configuration获取Mapper
return configuration.<T>getMapper(type, this);
}
2、Configuration中的MapperRegistry;通过Mapper的class作为key获取MapperProxyFactory工厂的产生
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//1、通过Mapper接口的class获取到MapperProxyFactory,接口代理工厂
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null)
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
try {
//2、接口代理工程生成Mapper代理对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
MapperProxyFactory
//接口代理工厂生成代理对象
protected T newInstance(MapperProxy<T> mapperProxy) {
//4、通过接口代理生成代理对象
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
//3、new出MaperProxy代理类
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
MapperProxy
该类实现的InvocationHandler接口,可以产生代理对象
//mapper接口方法都会进入这里
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//判断是否是抽象方法,如果不是则直接代理运行返回,如果是则不进入if
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//缓存该方法,一级缓存结果,获取该方法查询的缓存
final MapperMethod mapperMethod = cachedMapperMethod(method);
//执行sql
return mapperMethod.execute(sqlSession, args);MapperMethod
}
MapperMetod
该类为最终执行sql语句以及一些结果集的封装
主要sql执行代码块
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
//判断该方法sql的执行类型
if (SqlCommandType.INSERT == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
} else if (SqlCommandType.UPDATE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
} else if (SqlCommandType.DELETE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
} else if (SqlCommandType.SELECT == command.getType()) {
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 {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
} else {
throw new BindingException("Unknown execution method for: " + command.getName()); }
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result;}
六、Mybatis的事务控制
Mybatis的Transaction接口定义了事务方法,提交、回滚、关闭、获取连接的方法
public interface Transaction {
/**
* Retrieve inner database connection
* @return DataBase connection
* @throws SQLException
*/
Connection getConnection() throws SQLException;
/**
* Commit inner database connection.
* @throws SQLException
*/
void commit() throws SQLException;
/**
* Rollback inner database connection.
* @throws SQLException
*/
void rollback() throws SQLException;
/**
* Close inner database connection.
* @throws SQLException
*/
void close() throws SQLException;
}
1、SqlSession调用commit
2、Executor调用commit
3、Transaction调用commit
4、Contection调用commit