网站存在风险什么意思,手机网站建设哪个,温州网站建设公司公司哪家好,软件开发流程有哪些阶段spring-framework 版本#xff1a;v5.3.19 spring和mybatis的整合无非主要就是以下几个方面#xff1a; 1、SqlSessionFactory怎么注入#xff1f; 2、Mapper代理怎么注入#xff1f; 3、为什么要接管mybatis事务#xff1f; 文章目录 一、SqlSessionFactory怎么注入SqlSe… spring-framework 版本v5.3.19 spring和mybatis的整合无非主要就是以下几个方面 1、SqlSessionFactory怎么注入 2、Mapper代理怎么注入 3、为什么要接管mybatis事务 文章目录 一、SqlSessionFactory怎么注入SqlSessionFactoryBean 二、Mapper代理怎么注入MapperFactoryBeanSqlSessionTemplate 三、为什么要接管mybatis事务SpringManagedTransactionFactory 一、SqlSessionFactory怎么注入
SqlSessionFactoryBean
在mybatis-spring中定义了一个新的factoryBean——SqlSessionFactoryBean我们将其注入到spring容器即可。 其实也不难猜到这个factoryBean的getObject肯定返回了一个SqlSessionFactory这样spring容器中就有一个SqlSessionFactory bean了。后续就跟使用原生mybatis一样通过这个SqlSessionFactory去生成SqlSession进而生成Mapper的代理类去操作数据库。 所以getObject方法是如何生成SqlSessionFactory来到buildSqlSessionFactory
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {final Configuration targetConfiguration;XMLConfigBuilder xmlConfigBuilder null;if (this.configuration ! null) {targetConfiguration this.configuration;if (targetConfiguration.getVariables() null) {targetConfiguration.setVariables(this.configurationProperties);} else if (this.configurationProperties ! null) {targetConfiguration.getVariables().putAll(this.configurationProperties);}} else if (this.configLocation ! null) {xmlConfigBuilder new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);targetConfiguration xmlConfigBuilder.getConfiguration();} else {LOGGER.debug(() - Property configuration or configLocation not specified, using default MyBatis Configuration);targetConfiguration new Configuration();Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);}Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);if (hasLength(this.typeAliasesPackage)) {scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream().filter(clazz - !clazz.isAnonymousClass()).filter(clazz - !clazz.isInterface()).filter(clazz - !clazz.isMemberClass()).forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);}if (!isEmpty(this.typeAliases)) {Stream.of(this.typeAliases).forEach(typeAlias - {targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);LOGGER.debug(() - Registered type alias: typeAlias );});}if (!isEmpty(this.plugins)) {Stream.of(this.plugins).forEach(plugin - {targetConfiguration.addInterceptor(plugin);LOGGER.debug(() - Registered plugin: plugin );});}if (hasLength(this.typeHandlersPackage)) {scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz - !clazz.isAnonymousClass()).filter(clazz - !clazz.isInterface()).filter(clazz - !Modifier.isAbstract(clazz.getModifiers())).forEach(targetConfiguration.getTypeHandlerRegistry()::register);}if (!isEmpty(this.typeHandlers)) {Stream.of(this.typeHandlers).forEach(typeHandler - {targetConfiguration.getTypeHandlerRegistry().register(typeHandler);LOGGER.debug(() - Registered type handler: typeHandler );});}targetConfiguration.setDefaultEnumTypeHandler(defaultEnumTypeHandler);if (!isEmpty(this.scriptingLanguageDrivers)) {Stream.of(this.scriptingLanguageDrivers).forEach(languageDriver - {targetConfiguration.getLanguageRegistry().register(languageDriver);LOGGER.debug(() - Registered scripting language driver: languageDriver );});}Optional.ofNullable(this.defaultScriptingLanguageDriver).ifPresent(targetConfiguration::setDefaultScriptingLanguage);if (this.databaseIdProvider ! null) {// fix #64 set databaseId before parse mapper xmlstry {targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));} catch (SQLException e) {throw new IOException(Failed getting a databaseId, e);}}Optional.ofNullable(this.cache).ifPresent(targetConfiguration::addCache);if (xmlConfigBuilder ! null) {try {xmlConfigBuilder.parse();LOGGER.debug(() - Parsed configuration file: this.configLocation );} catch (Exception ex) {throw new IOException(Failed to parse config resource: this.configLocation, ex);} finally {ErrorContext.instance().reset();}}targetConfiguration.setEnvironment(new Environment(this.environment,this.transactionFactory null ? new SpringManagedTransactionFactory() : this.transactionFactory,this.dataSource));if (this.mapperLocations ! null) {if (this.mapperLocations.length 0) {LOGGER.warn(() - Property mapperLocations was specified but matching resources are not found.);} else {for (Resource mapperLocation : this.mapperLocations) {if (mapperLocation null) {continue;}try {XMLMapperBuilder xmlMapperBuilder new XMLMapperBuilder(mapperLocation.getInputStream(),targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());xmlMapperBuilder.parse();} catch (Exception e) {throw new IOException(Failed to parse mapping resource: mapperLocation , e);} finally {ErrorContext.instance().reset();}LOGGER.debug(() - Parsed mapper file: mapperLocation );}}} else {LOGGER.debug(() - Property mapperLocations was not specified.);}return this.sqlSessionFactoryBuilder.build(targetConfiguration);}跟原生mybatis一样构建一个Configuration对象然后使用SqlSessionFactoryBuilder去build一个SqlSessionFactory。需要注意的是这个过程中就算外界传入的Configuration对象有环境、数据源、事务管理器的配置无论是xml配置还是代码都会被忽略取而代之的是SqlSessionFactoryBean对应的environment、dataSource、transactionFactory属性。至此spring中就相当于有了SqlSessionFactory bean后续spring就可以用这个SqlSessionFactory bean去生成SqlSession。
二、Mapper代理怎么注入
MapperFactoryBean
跟使用原生mybatis一样对mapper接口生成一个个的代理对象。即在整合过程中会生成一个个代理对象bean对应流程如下。 1、MapperScan注解import了MapperScannerRegistrar bean。 2、MapperScannerRegistrar是一个ImportBeanDefinitionRegistrar会注册MapperScannerConfigurer bean。 3、MapperScannerConfigurer是一个BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor对应的增强方法会扫描出指定路径下的Mapper并把class type设为MapperFactoryBean。 4、MapperFactoryBean是一个FactoryBean其getObject方法跟原生mybatis一样通过SqlSession.getMapper生成一个mapper代理对象然后将其注入spring容器。
SqlSessionTemplate
所以是直接使用SqlSession来生成mapper的代理对象吗其实不然实际MapperFactoryBean的getObject中的getSqlSession()返回的是一个SqlSessionTemplate SqlSessionTemplate中维护了一个SqlSession的代理对象后续有关数据库的操作都会经过这个代理对象。 代理SqlSession的逻辑大概就是如果是同一个事务就获取同一个SqlSession如果不是同一个事务就新建一个SqlSession然后再用这个SqlSession去做事情。这么做是为了解决SqlSession线程不安全的问题正是因为如此导致不同事务用不同的SqlSession所以一级缓存也就失效了。
三、为什么要接管mybatis事务
SpringManagedTransactionFactory
在SqlSessionFactoryBean的buildSqlSessionFactory中我们默认会使用SpringManagedTransactionFactory作为我们的事务管理器来接管mybatis事务。 这么做是为了让 MyBatis 的事务管理与 Spring 的事务管理能够协同工作从而实现 MyBatis 与 Spring 的事务管理一致性。 具体来说SpringManagedTransactionFactory 在创建事务时会获取 Spring 的事务管理器并将其封装为 MyBatis 的 Transaction 对象。在事务提交或回滚时SpringManagedTransactionFactory 会将事务的状态同步到 Spring 的事务管理器中。