mybatiss学习之路1

来源:互联网 发布:阿里云更换系统 编辑:程序博客网 时间:2024/06/08 08:44

SqlSessionFactoryBean 是一个Factory类,主要是用来生成SqlSessionFactory的。以下是SqlSessionFactoryBean的主要属性

private Resource configLocation;///////mapper文件Resource 对象数组
private Resource[] mapperLocations;
////数据源private DataSource dataSource;/////事务工厂private TransactionFactory transactionFactory;private Properties configurationProperties;private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();//////根据给的入参实例化的 sqlSessionFactory 实例对象 ,getObjec() 方法返回的就是这个对象private SqlSessionFactory sqlSessionFactory;//EnvironmentAware requires spring 3.1private String environment = SqlSessionFactoryBean.class.getSimpleName();private boolean failFast;/////拦截器  可以在生成执行sql语句之前  修改sql语句或者是修改数据源private Interceptor[] plugins;private TypeHandler<?>[] typeHandlers;private String typeHandlersPackage;private Class<?>[] typeAliases;private String typeAliasesPackage;private Class<?> typeAliasesSuperType;//issue #19. No default provider.private DatabaseIdProvider databaseIdProvider;private ObjectFactory objectFactory;private ObjectWrapperFactory objectWrapperFactory;

spring中定义的 sqlsessionFactoryBean 对象通过 Application.getBean 方法获得的对象实际上是  sqlsessionFactoryBean.getObject()方法返回的对象(如果想获得sqlsessionFactoryBean本身的话在对象id前面加一个 &   因为spring  在生成 FactoryBean 对象的时候会在bean id的前面加一个 &) 。

public SqlSessionFactory getObject() throws Exception {  if (this.sqlSessionFactory == null) {    afterPropertiesSet();  }  return this.sqlSessionFactory;}

返回的实际上就是sqlsessionFactoryBean 本身的  sqlsessionFactory   这个对象的实例化是 afterPropertiesSet() 方法中 (实现了InitalizingBean 接口) 


public void afterPropertiesSet() throws Exception {  notNull(dataSource, "Property 'dataSource' is required");  notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");  this.sqlSessionFactory = buildSqlSessionFactory();}
进入  buildsqlsessinofactory()  方法

protected SqlSessionFactory buildSqlSessionFactory() throws IOException {  Configuration configuration;  XMLConfigBuilder xmlConfigBuilder = null;  if (this.configLocation != null) {    xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);    configuration = xmlConfigBuilder.getConfiguration();  } else {    if (LOGGER.isDebugEnabled()) {      LOGGER.debug("Property 'configLocation' not specified, using default MyBatis Configuration");    }    configuration = new Configuration();    configuration.setVariables(this.configurationProperties);  }  if (this.objectFactory != null) {    configuration.setObjectFactory(this.objectFactory);  }  if (this.objectWrapperFactory != null) {    configuration.setObjectWrapperFactory(this.objectWrapperFactory);  }  if (hasLength(this.typeAliasesPackage)) {    String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,        ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);    for (String packageToScan : typeAliasPackageArray) {      configuration.getTypeAliasRegistry().registerAliases(packageToScan,              typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);      if (LOGGER.isDebugEnabled()) {        LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");      }    }  }  if (!isEmpty(this.typeAliases)) {    for (Class<?> typeAlias : this.typeAliases) {      configuration.getTypeAliasRegistry().registerAlias(typeAlias);      if (LOGGER.isDebugEnabled()) {        LOGGER.debug("Registered type alias: '" + typeAlias + "'");      }    }  }////////添加拦截器  if (!isEmpty(this.plugins)) {    for (Interceptor plugin : this.plugins) {      configuration.addInterceptor(plugin);      if (LOGGER.isDebugEnabled()) {        LOGGER.debug("Registered plugin: '" + plugin + "'");      }    }  }  if (hasLength(this.typeHandlersPackage)) {    String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,        ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);    for (String packageToScan : typeHandlersPackageArray) {      configuration.getTypeHandlerRegistry().register(packageToScan);      if (LOGGER.isDebugEnabled()) {        LOGGER.debug("Scanned package: '" + packageToScan + "' for type handlers");      }    }  }  if (!isEmpty(this.typeHandlers)) {    for (TypeHandler<?> typeHandler : this.typeHandlers) {      configuration.getTypeHandlerRegistry().register(typeHandler);      if (LOGGER.isDebugEnabled()) {        LOGGER.debug("Registered type handler: '" + typeHandler + "'");      }    }  }  if (xmlConfigBuilder != null) {    try {      xmlConfigBuilder.parse();      if (LOGGER.isDebugEnabled()) {        LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");      }    } catch (Exception ex) {      throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);    } finally {      ErrorContext.instance().reset();    }  }  if (this.transactionFactory == null) {    this.transactionFactory = new SpringManagedTransactionFactory();  }  configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));  if (this.databaseIdProvider != null) {    try {      configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));    } catch (SQLException e) {      throw new NestedIOException("Failed getting a databaseId", e);    }  }////////根据我们配置的mapper.xml文件    if (!isEmpty(this.mapperLocations)) {    for (Resource mapperLocation : this.mapperLocations) {      if (mapperLocation == null) {        continue;      }      try {        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),            configuration, mapperLocation.toString(), configuration.getSqlFragments());
/////////1.  在这个方法中会去把 mapper 文件中的namespace 转化成Class对象并把 该类存到  configuration对象的mapperRegistry属性中 
用来记录 通过接口的函数名字和xml的id关连的 mapper接口/////////2.  转化结果集  resultmap 并把他记录在 configuration  的resultMaps中
/////////3.
/////////4. 将每个sql 语句转化成 MappedStatement 并把他存在 configuration的  mappedStatements中         xmlMapperBuilder.parse();      } catch (Exception e) {        throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);      } finally {        ErrorContext.instance().reset();      }      if (LOGGER.isDebugEnabled()) {        LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");      }    }  } else {    if (LOGGER.isDebugEnabled()) {      LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");    }  }  return this.sqlSessionFactoryBuilder.build(configuration);}

了解下 Configuration 这个类 的主要属性   这个类包含了mybatis 的所有配置

//////对应<environment> 标签 可以配置数据源 及数据源和环境的关系,可以根据环境切换数据源
protected Environment environment;protected boolean safeRowBoundsEnabled = false;protected boolean safeResultHandlerEnabled = true;protected boolean mapUnderscoreToCamelCase = false;protected boolean aggressiveLazyLoading = true;protected boolean multipleResultSetsEnabled = true;protected boolean useGeneratedKeys = false;protected boolean useColumnLabel = true;protected boolean cacheEnabled = true;protected boolean callSettersOnNulls = false;protected String logPrefix;protected Class <? extends Log> logImpl;protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;protected JdbcType jdbcTypeForNull = JdbcType.OTHER;protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));protected Integer defaultStatementTimeout;protected Integer defaultFetchSize;protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;protected Properties variables = new Properties();protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();protected ObjectFactory objectFactory = new DefaultObjectFactory();protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();protected MapperRegistry mapperRegistry = new MapperRegistry(this);protected boolean lazyLoadingEnabled = false;protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNLprotected String databaseId;/** * Configuration factory class. * Used to create Configuration for loading deserialized unread properties. * * @see <a href='https://code.google.com/p/mybatis/issues/detail?id=300'>Issue 300</a> (google code) */protected Class<?> configurationFactory;//插件链
protected final InterceptorChain interceptorChain = new InterceptorChain();protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();//mappedStatements Map 每个sql语句对应yige MappedStatement对象  包括 入参 对象 出参对象 (都是String 即id)protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
///////sql语句和结果集 之间的映射关系protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");
//////sql语句和 入参集 之间的映射关系protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<KeyGenerator>("Key Generators collection");protected final Set<String> loadedResources = new HashSet<String>();
//一些sql 碎片 自定义的一些sql片段protected final Map<String, XNode> sqlFragments = new StrictMap<XNode>("XML fragments parsed from previous mappers");//未解析处理的statementsprotected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<XMLStatementBuilder>();protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<CacheRefResolver>();
//未解析处理的ResultMapsprotected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>();
//未解析处理的Methodsprotected final Collection<MethodResolver> incompleteMethods = new LinkedList<MethodResolver>();/* * A map holds cache-ref relationship. The key is the namespace that * references a cache bound to another namespace and the value is the * namespace which the actual cache is bound to. */protected final Map<String, String> cacheRefMap = new HashMap<String, String>();

(插一句工厂类的好处,有些类的属性比较多,一个一个配置会比较麻烦,还有些属性是不想暴露给外面的 使用Factory来生成bean会更好,如果想 生成代理类的话也比较方便,直接在工厂类生成bean的时候修改就好了)


一般我们拿到的sqlSessionFactory 是 DefaultSqlSessionFactory类型的

public DefaultSqlSessionFactory(Configuration configuration) {  this.configuration = configuration;}
把所有的配置都放在了configuration对象中  这里只是生成了sqlsessionfactory对象
再看看如何直接用配置文件中的id直接访问数据库  主要是利用session来操作数据库的 默认实现是DefaultSqlSession
主要有这几个属性
///mybatis的配置都在这对象中
pivate Configuration configuration;
////执行器,实际对数据库操作的对象
private Executor executor;
//是否自动提交private boolean autoCommit;
private boolean dirty;
以查询为例  最后调用的方法是  selectList()
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {  try {    MappedStatement ms = configuration.getMappedStatement(statement);    return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);  } catch (Exception e) {    throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);  } finally {    ErrorContext.instance().reset();  }}

在xml配置文件中 一条sql 对应一个 MappedStatement 这个映射是存在configuration中的mappedStatements中的 key是 (如果启用了namespace
是namespace+id)id  value是对应的MappedStatement对象  看下MappedStatement属性
private String resource;private Configuration configuration;private String id;private Integer fetchSize;private Integer timeout;private StatementType statementType;private ResultSetType resultSetType;private SqlSource sqlSource;private Cache cache;private ParameterMap parameterMap;private List<ResultMap> resultMaps;private boolean flushCacheRequired;private boolean useCache;private boolean resultOrdered;private SqlCommandType sqlCommandType;private KeyGenerator keyGenerator;private String[] keyProperties;private String[] keyColumns;private boolean hasNestedResultMaps;private String databaseId;private Log statementLog;private LanguageDriver lang;private String[] resultSets;

真正的执行方法是 executor的query
执行器 executor有三种  默认的是simpleExecutor  其中query方法
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {   BoundSql boundSql = ms.getBoundSql(parameter);   CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);   return query(ms, parameter, rowBounds, resultHandler, key, boundSql);}
MappedStatement中的getBoundSql 的作用是给入参并解析出 BoundSql BoundSql中的属性
//解析好的sql 语句
private String sql;private List<ParameterMapping> parameterMappings;private Object parameterObject;private Map<String, Object> additionalParameters;private MetaObject metaParameters;

mybatis访问数据最终还是通过jdbc的方式去访问的    StatementHandler
回顾下jdbc连接数据库
http://www.cnblogs.com/centor/p/6142775.html  转载
看mybatis 是如何获取数据库连接的  
通过  Exector中的Transaction获取连接
Transaction中存有Datasource 数据源
如果是根据接口去访问   则还需要配置 MapperScannerConfigurer  这类实现了  BeanDefinitionRegistryPostProcessor
会将配置的那个包下的所有接口都转成代理类