浅跟mybatis

写在开篇:建议自己建个简单的项目,使用idea跟跟,实践下,我的这篇文章纯属自己记录

------------------------------------------------------------------------------------------------------------------------

目前市面上主流的实现mvc的框架就是SSM,mybatis就是那个M,他是实现ORM的轻量级连接数据库的框架,与spring结合使用。他底层操作数据库的代码也是调用的java原生的jdbc。

在使用mybatis时,我们只需要配置mybaits的配置信息在spring配置文件中,应用启动时会自动加载配置,为我们自动装配使用mybatis所需要的bean。

使用mybatis我们需要实现配置的信息有sqlSessionFactory和工厂类中需要的参数,dataSource、ConfigLocation和mapperLocations

其中dataSource中配置了数据库连接信息和数据库连接池信息,可以使用原生的mybatis数据源配置,也支持使用外部数据源,我们公司使用的是阿里的druidDataSource。

应用启动加载mybatis配置的时候会为我们初始化mybatis运行时的参数,在创建dataSource bean的时候会测试连接数据库,,执行一个测试sql,以保证数据库可以正常访问。

因为sqlSession工厂bean实现了spring的initializingBean接口,所以在初始化的时候,会执行sqlSessionFactoryBean的afterPropertiesSet方法初始化参数,在这时就会扫描配置,当然也包括mappe.xml文件,为没有mapper.xml文件都生成一个mapperProxy代理类对象,然后作为mapper接口的初始化bean,为每一个mapper.xml中的方法都创建一个MapperMethod方法对象,同时将每个方法中的标签内容转换成对应sqlNode的对象。

 

InitializingBean,实现这个接口后,spring容器在创建了对象后会去执行这个对象实现了的afterPropertiesSet()方法,初试化被创建的bean。
--------------------------------------------题外话---------------------------------------------------
所以,如果我们有类似的需求,也可以参照实现
引用别人整理的:
1)设置属性值;
2)调用Bean中的BeanNameAware.setBeanName()方法,如果该Bean实现了BeanNameAware接口;
3)调用Bean中的BeanFactoryAware.setBeanFactory()方法,如果该Bean实现了BeanFactoryAware接口;
4)调用BeanPostProcessors.postProcessBeforeInitialization()方法;@PostConstruct注解后的方法就是在这里被执行的
5)调用Bean中的afterPropertiesSet方法,如果该Bean实现了InitializingBean接口;
6)调用Bean中的init-method,通常是在配置bean的时候指定了init-method,例如:<bean class="beanClass" init-method="init"></bean>
7)调用BeanPostProcessors.postProcessAfterInitialization()方法;
8)如果该Bean是单例的,则当容器销毁并且该Bean实现了DisposableBean接口的时候,调用destory方法;如果该Bean是prototype,则将准备好的Bean提交给调用者,后续不再管理该Bean的生命周期。

原文链接:https://blog.csdn.net/t194978/article/details/81515986
spring初始化bean

  ------------------------------------------------------------------------------------------------------------------------

 

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

    protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
        XMLConfigBuilder xmlConfigBuilder = null;
        Configuration configuration;
        if (this.configLocation != null) {
            xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), (String)null, this.configurationProperties);
            configuration = xmlConfigBuilder.getConfiguration();
        } else {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration");
            }

            configuration = new Configuration();
            configuration.setVariables(this.configurationProperties);
        }

        String[] typeHandlersPackageArray;
        String[] arr$;
        int len$;
        int i$;
        String packageToScan;
        if (StringUtils.hasLength(this.typeAliasesPackage)) {
            typeHandlersPackageArray = StringUtils.tokenizeToStringArray(this.typeAliasesPackage, ",; \t\n");
            arr$ = typeHandlersPackageArray;
            len$ = typeHandlersPackageArray.length;

            for(i$ = 0; i$ < len$; ++i$) {
                packageToScan = arr$[i$];
                configuration.getTypeAliasRegistry().registerAliases(packageToScan);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Scanned package: '" + packageToScan + "' for aliases");
                }
            }
        }

        int len$;
        if (!ObjectUtils.isEmpty(this.typeAliases)) {
            Class[] arr$ = this.typeAliases;
            len$ = arr$.length;

            for(len$ = 0; len$ < len$; ++len$) {
                Class<?> typeAlias = arr$[len$];
                configuration.getTypeAliasRegistry().registerAlias(typeAlias);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Registered type alias: '" + typeAlias + "'");
                }
            }
        }

        if (!ObjectUtils.isEmpty(this.plugins)) {
            Interceptor[] arr$ = this.plugins;
            len$ = arr$.length;

            for(len$ = 0; len$ < len$; ++len$) {
                Interceptor plugin = arr$[len$];
                configuration.addInterceptor(plugin);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Registered plugin: '" + plugin + "'");
                }
            }
        }

        if (StringUtils.hasLength(this.typeHandlersPackage)) {
            typeHandlersPackageArray = StringUtils.tokenizeToStringArray(this.typeHandlersPackage, ",; \t\n");
            arr$ = typeHandlersPackageArray;
            len$ = typeHandlersPackageArray.length;

            for(i$ = 0; i$ < len$; ++i$) {
                packageToScan = arr$[i$];
                configuration.getTypeHandlerRegistry().register(packageToScan);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Scanned package: '" + packageToScan + "' for type handlers");
                }
            }
        }

        if (!ObjectUtils.isEmpty(this.typeHandlers)) {
            TypeHandler[] arr$ = this.typeHandlers;
            len$ = arr$.length;

            for(len$ = 0; len$ < len$; ++len$) {
                TypeHandler<?> typeHandler = arr$[len$];
                configuration.getTypeHandlerRegistry().register(typeHandler);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Registered type handler: '" + typeHandler + "'");
                }
            }
        }

        if (xmlConfigBuilder != null) {
            try {
                xmlConfigBuilder.parse();
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Parsed configuration file: '" + this.configLocation + "'");
                }
            } catch (Exception var23) {
                throw new NestedIOException("Failed to parse config resource: " + this.configLocation, var23);
            } finally {
                ErrorContext.instance().reset();
            }
        }

        if (this.transactionFactory == null) {
            this.transactionFactory = new SpringManagedTransactionFactory();
        }

        Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);
        configuration.setEnvironment(environment);
        if (this.databaseIdProvider != null) {
            try {
                configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
            } catch (SQLException var22) {
                throw new NestedIOException("Failed getting a databaseId", var22);
            }
        }

        if (!ObjectUtils.isEmpty(this.mapperLocations)) {
            Resource[] arr$ = this.mapperLocations;
            len$ = arr$.length;

            for(i$ = 0; i$ < len$; ++i$) {
                Resource mapperLocation = arr$[i$];
                if (mapperLocation != null) {
                    try {
                        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), configuration, mapperLocation.toString(), configuration.getSqlFragments());
                        xmlMapperBuilder.parse();
                    } catch (Exception var20) {
                        throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", var20);
                    } finally {
                        ErrorContext.instance().reset();
                    }

                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Parsed mapper file: '" + mapperLocation + "'");
                    }
                }
            }
        } else if (this.logger.isDebugEnabled()) {
            this.logger.debug("Property 'mapperLocations' was not specified or no matching resources found");
        }

        return this.sqlSessionFactoryBuilder.build(configuration);
    }
主要实现代码

  在这里还做了一件事,就是给我们的每个mapper接口都初始化了一个动态代理类MapperProxy<T> implements InvocationHandler, Serializable。同时将mapper接口中的每个方法信息都初始化到了org.apache.ibatis.session.Configuration中

 

当我们在程序中调用一个数据库执行方法去操作数据库时,就会在代理类中查询到实现加载好的方法对应的mapperMethod类,拿到方法信息,通过动态sqlSource(DynamicSqlSource)类循环sqlNode对象执行 getBoundSql方法进行sql拼接。通过debug我们会发现sql拼接的时候会将example中的参数转换成#{},而#{}会被转化成?占位符,使用jdbc的statement进行参数赋值,最终在sql是用引号引起来作为参数拼接到sql中的,而${}是直接将内容作为一个可执行的sql放进去的,所以前两种方式传递sql是比较安全的。处理完sql之后openSession 打开事务,操作数据库








posted @ 2020-01-09 15:07  田海超  阅读(128)  评论(0编辑  收藏  举报