SqlSessionFactory为一个接口,它的任务是创建SqlSession。SqlSession类似于一个JDBC的Connection对象。
每次应用程序需要访问数据库,我们就要通过SqlSessionFactory创建SqlSession,所以SqlSessionFactory应该在mybatis整个声明周期中。而我们如果多次创建同一个数据库的SqlSessionFactory,则每次创建SqlSessionFactory会打开更多的数据库连接资源,那么连接资源很快就会被耗尽。因此SqlSessionFactory的责任是唯一的,它的责任就是创建SqlSession,所以我们果断采用单例模式。
MyBatis中有两种方式创建SqlSessionFactory:一种是XML配置方式(建议),另一种是代码方式。
提供了两个SqlSessionFactory的实现类,DefaultSqlSessionFactory和 SqlSessionmanager,目前SqlSessionmanager没有使用,mybatis目前使用的是DefaultSqlSessionFactory
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();
}
Configuration类的全限定名为:org.apache.ibatis.session.Configuration,它在Mybatis中将以一个Configuration类对象的形式存在,而这个对象将存在于整个Mybatis应用的周期中,以便重复读取和运用。在内存中的数据是计算机系统中读取速度最快的,我们可以解析一次配置的XML文件保存到Configuration类对象中。方便我们从这个对象中读取配置信息,性能高。单例占用空间小,基本不占用存储空间而且可以反复使用。Conf类对象保存着我们配置在Mybatis的信息。
SqlSessionFactoryBuilder为一个类,SqlSessionFactoryBuilder利用XML或者java编码来获得资源来构建SqlSessionFactory的,通过它可以构建多个SqlSessionFactory。它的作用就是一个构建器,一旦我们构建SqlSessionFactory,它的作用就已经完结,失去了存在的意义,这师我们就应该毫不犹豫的废弃它,将它回收。所以它的生命周期只存在于方法的局部,它的作用就是生成SqlSessionFactory对象。
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
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.
}
}
}
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
SqlSession是一个接口类(类似于一个JDBC中的Connection接口对象),它类似于你们公司的前台美女客服,它扮演着门面的作用,而真正干活的是
Executor接口,你可以认为它是公司的工程师。假设我是客户找你们公司干活,我只需要告诉前台的美女客服(
SqlSession)我们什么信息(参数),要做什么东西,她会将结果给我。在这个过程中,作为用户的我,所关心的是:
(1)要给美女客服(SqlSession)什么信息(功能和参数)
(2)美女客服会给我什么结果(Result)
而我不关系工程师(Executor)是怎么为我工作的,只要前台告诉工程师(Executor),工程师就知道如何为我工作,这个步骤对我而言是个黑箱操作。
SqlSession的用途有两个:(1)获取映射器(2)直接通过命名去执行SQL返回信息(ibatis版本留下的方式)。
SqlSession它的生命周期应该在请求数据库处理事务的过程中。它是一个线程不安全的对象,在涉及多线程的时候我们需要特别的当心,操作数据库需要注意其隔离级别,数据库锁等高级特性。此外,每次创建的SqlSession都必须及时关闭它,它长期存在就会使数据库连接池的活动资源减少,对系统性能的影响很大。
public interface SqlSession extends Closeable {
<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
<K, V> Map<K, V> selectMap(String statement, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
void select(String statement, Object parameter, ResultHandler handler);
void select(String statement, ResultHandler handler);
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
int insert(String statement);
int insert(String statement, Object parameter);
int update(String statement);
int update(String statement, Object parameter);
int delete(String statement);
int delete(String statement, Object parameter);
void commit();
void commit(boolean force);
void rollback();
void rollback(boolean force);
List<BatchResult> flushStatements();
void close();
void clearCache();
<T> T getMapper(Class<T> type);
Connection getConnection();
}
Mapper,
Mapper是一个接口,而没有任何实现类,它的作用是发送SQL,然后返回我们需要的结果,或者执行SQL从而修改数据库的数据,因此它应该在一个SqlSession事务方法之内,是一个方法级别的东西。它就如同JDBC中一条SQL语句的执行,它的最大范围和SqlSession是相同的。尽管我们一直保存着Mapper,但是你会发现它很难控制,所以尽量在一个SqlSession事务的方法中使用它们,然后废弃掉。