皮皮网

皮皮网

【android多线程源码】【代理记账源码 完整源码】【webps源码在线ps源码】mybatis session 源码

时间:2024-11-30 03:49:47 分类:休闲

1.三万字带你彻底吃透MyBatis源码!源码!源码
2.java通过反射拿到mybatis中的源码sql语句并操作怎么用什么时候用?
3.如何实现mybatis的sqlsessiontemplate
4.mybatis spring介绍、使用、实现原理

mybatis session 源码

三万字带你彻底吃透MyBatis源码!!源码

       随着互联网的源码迅猛发展,MyBatis逐渐成为了Java开发者不可或缺的源码android多线程源码框架技术。许多大厂在面试中偏好问及MyBatis的源码底层原理及源码实现,这表明了其在技术栈中的源码重要性。本文旨在全面解析MyBatis源码,源码帮助开发者深入理解这一强大的源码框架。为了方便学习,源码推荐大家先收藏后仔细研读。源码

       MyBatis源码在封装了JDBC之后,源码实现了对数据库操作的源码高级抽象。无论是源码获取连接、预编译语句、参数封装还是执行SQL,其核心步骤并未改变。

       解析过程始于通过`ClassLoader.getResourceAsStream`方法获取配置文件路径。代理记账源码 完整源码这个过程确保了MyBatis能正确加载配置信息,进而解析XML文件,构建配置中心。

       解析XML文件的关键在于`parseConfiguration`和`mapperParser.parse`方法。前者用于解析配置文件中的`Environment`、`Setting`等信息,后者则专注于解析Mapper映射器,将其与工厂类进行绑定。

       构建`SqlSessionFactory`的webps源码在线ps源码过程涉及解析Mapper映射器,生成`MappedStatement`对象,以及将接口类型与工厂类绑定。最终,`DefaultSqlSessionFactory`被创建,用于管理会话生命周期。

       会话的创建通过`openSession`方法完成,该方法实例化了`Executor`来执行SQL。`Executor`的配置则决定了事务管理和执行器类型。同时,开源源码和源码`Transaction`的管理分为两种方式,以确保数据的一致性和完整性。

       获取Mapper对象时,通过`mapperRegistry.getMapper`方法,该方法从`MapperRegistry`的`knownMappers`中获取接口类型和对应的工厂类。代理对象`MapperProxy`由JDK动态代理生成,用于执行实际的数据库操作。

       执行SQL时,调用代理对象的音乐解析源码 精品源码`invoke`方法,进而调用`execute`方法。无论是查询还是其他操作,均遵循此流程。在查询场景下,`selectOne`与`selectList`功能实现相同,仅在参数处理上有所差异。

       `MappedStatement`对象负责存储SQL信息,包括执行策略、参数类型等。`CacheKey`的生成则基于`BoundSql`内容,用于缓存结果,提高效率。

       通过以上解析,我们可以看到MyBatis源码的简洁与高效。深入理解其结构与机制,不仅有助于提高开发效率,还能增强对数据库操作的理解。总的来说,MyBatis的源码并不复杂,只需耐心研读,两三天内即可掌握其核心。

java通过反射拿到mybatis中的sql语句并操作怎么用什么时候用?

       操作。具体的步骤如下:

       获取 MyBatis 中的 MappedStatement 对象。可以通过 SqlSession 的 getConfiguration() 方法获取 Configuration 对象,然后再通过 Configuration 对象的 getMappedStatement() 方法获取 MappedStatement 对象。

       从 MappedStatement 对象中获取 BoundSql 对象,即 SQL 语句绑定的参数对象。

       从 BoundSql 对象中获取 SQL 语句字符串。可以通过调用 getSql() 方法获取 SQL 语句字符串。

       对 SQL 语句进行相应的操作。例如,可以对 SQL 语句进行修改、输出等操作。

       Java 通过反射获取 MyBatis 中的 SQL 语句的代码示例:

       SqlSession sqlSession = sqlSessionFactory.openSession();

       try {

       // 获取 MappedStatement 对象

       MappedStatement mappedStatement = sqlSession.getConfiguration().getMappedStatement("com.example.mapper.selectUser");

       // 获取 BoundSql 对象

       BoundSql boundSql = mappedStatement.getBoundSql(paramObject);

       // 获取 SQL 语句字符串

       String sql = boundSql.getSql();

       // 对 SQL 语句进行相应的操作

       // ...

       } finally {

       sqlSession.close();

       }

       需要注意的是,在使用反射获取 SQL 语句时,要注意保护用户隐私和安全,以免发生 SQL 注入等问题。

如何实现mybatis的sqlsessiontemplate

       SqlSession sqlSession = null;

       try {

        sqlSession = sqlSessionFactory.openSession();

        //namespace+id

        sqlSession.insert("cn.jarjar.dao.BlogMapper.insertBlog", blog);

        sqlSession.commit(true)

       } catch (Exception e) {

        e.printStackTrace();

        sqlSession.rollback(true);

       } finally {

        sqlSession.close();

       }

       ä¹Ÿå°±æ˜¯è¦åƒåŽŸå§‹çš„java.sql.Connection对象一样,必须按照:新建连接->执行SQL->提交(查询不需要)->如果操作数据存在异常需要回滚->释放数据库连接。注意第一点和最后一点,每个SqlSession新建之后必须释放,不然会造成数据库连接泄露的危险。也就是意味着SqlSession是个有状态的对象,是无法进行复用的,所以只能局限于request或者方法的范围,也就是所谓的线程不安全。

       çŽ°è±¡2:如果使用spring集成mybatis,官方提供了整和包mybatis-spring.jar,如果完成配置之后,使用方式及其简单,简单示例如下:

       //注入spring中配置的SqlSessionTemplate对象,单例

       @Resource(name="sqlSessionTemplate")

       public SqlSessionTemplate sqlSessionTemplate;

       public void saveTestTrans(){

        this.sqlSessionTemplate.selectList("testdomain.selectAnySql", "select * from my_blog where id='1'");

       }

       è¿™é‡Œçš„SqlSessionTemplate不仅是单例的,而且不需要手工新建和关闭SqlSession

       é—®é¢˜1:

       é‚£ä¹ˆé—®é¢˜æ¥äº†ï¼Œä¸ºä»€ä¹ˆmybatis-spring.jar中的SqlSessionTemplate可以被多个dao复用,而且不会造成数据连接泄露呢,并且还可以自动新建和释放数据库连接?官方解答是因为SqlSessionTemplate是线程安全的,也就是确保每个线程使用的sqlSession的唯一并不互相冲突。

       é¦–先看了一下mybatis-spring的源码,发现SqlSessionTemplate是通过代理拦截和SqlSessionHolder实现的sqlsession线程安全和自动新建和释放连接的。看构造函数函数中构建代理类,该代理类实现SqlSession接口,定义了方法拦截器,如果调用代理类实例中实现SqlSession接口定义的方法,该调用则被导向SqlSessionInterceptor的invoke方法,这个方法中自动进行了SqlSession的自动请求和释放(如果不被spring托管则自己新建和释放sqlsession,如果被spring管理则使用SqlSessionHolder进行request和relase操作)

       ä»¥ä¸‹ç½‘址针对SqlSessionTemplate的线程安全特性进行了详细的探究:blogs.com/daxin/p/.html

       é—®é¢˜2:

       ç„¶åŽåˆæƒ³åˆ°è¿™æ ·ä¸€ä¸ªé—®é¢˜ï¼Œè™½ç„¶çŽ°åœ¨å‡ ä¹Žæ‰€æœ‰é¡¹ç›®éƒ½ä½¿ç”¨spring作为java程序的基本框架,如果我不使用spring管理mybatis,仅仅使用原始的mybatis,怎么样才能构建一个和SqlSessionTemplate相似的对象呢?

       é¦–先想到必须使用java的treadLocal构建一个sqlsession的对象,如ThreadLocal sqlSession = new ThreadLocal

       ()。

       ç»è¿‡æŸ¥æ‰¾ï¼Œå‘现mybatis自身就有这样一个类实现了类似的功能,类路径:org.apache.ibatis.session.SqlSessionManager,但是没有注释,可能存在mybatis-spring这种神器之后,mybatis放弃了对这个类的维护。

       è¯¥ç±»å®žçŽ°äº†SqlSessionFactory, SqlSession并且在其中定义了一个treadLocal的sqlssion对象,同时使用了代理拦截进行了sqlsession的自动管理,具体代码可以自己查阅,对于理解mybatis原理和java的代理机制很有帮助。

       é‚£ä¹ˆå†™ä¸ªç®€å•çš„程序验证一下SqlSessionManager是否真的可以保证线程安全和自动新建和释放sqlssion:TestSqlManager.java

       private static SqlSession sqlSession;

       public static SqlSession getSqlSessionTest(){

        if(sqlSession == null){

        //构建使用的SqlSessionFactory

        SqlSessionFactory sqlSessionFactory = MyBatisUtil.getSqlSessionFactory();

        sqlSession = SqlSessionManager.newInstance(sqlSessionFactory);

        }

        return sqlSession;

       }

       public static void main(String[] args) throws InterruptedException {

        Run run = new Run();

        List

        threads = new ArrayList

        ();

        for (int i = 0; i < ; i++) {

        Thread t = new Thread(run);

        threads.add(t);

        System.out.println("thread:{ "+t.getName()+"}, start");

        t.start();

        }

        for (Thread t : threads) {

        System.out.println("thread:{ "+t.getName()+"},join");

        t.join();

        }

       }

       æˆ‘本机装的mysql,通过监控语句:select SUBSTRING_INDEX(host,’:’,1) as ip , count(*) from information_schema.processlist group by ip;发现执行过程中存在连接并发的情况,但是执行之后全部释放掉了。

mybatis spring介绍、使用、实现原理

       maven依赖<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.6</version></dependency>使用

       SqlSessionFactoryBean 可以创建sqlSessionFactory,dataSource是自己的数据源的bean @MapperScan注解可以帮助我们把MyBatis的Mapper类注册为bean,这样我们就可以在使用的地方通过@Autowired/@Resource引用来使用。

@MapperScan("com.github.liuzhengyang")@ConfigurationpublicclassMyBatisConfig{ @Autowired@BeanpublicSqlSessionFactoryBeansqlSessionFactoryBean(DataSourcedataSource){ SqlSessionFactoryBeansqlSessionFactoryBean=newSqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);returnsqlSessionFactoryBean;}}实现原理

       mybatis-spring帮助我们简化的工作、带来的价值是

       SqlSessionFactory创建的工作,使用原生的mybatis需要用配置文件配置mybatis,mybais-spring可以用@Bean代码创建。(虽然mybatis也能用代码构建,不过SqlSessionFactory被spring管理了,在使用的时候只需要@Autowire会更方便)

       ä¸å†éœ€è¦æ¯æ¬¡openSession、close,这些工作在mybatis-spring内部实现了,mybatis-spring帮助我们判断是否要openSession

       Mapper类变成了bean,需要使用的时候直接@Autowired就可以

       æä¾›çº¿ç¨‹å®‰å…¨çš„SqlSessionTemplate

SqlSessionFactory如何创建

       SqlSessionFactory通过SqlSessionFactoryBean#buildSqlSessionFactory构建,调用时机是SqlSessionFactoryBean.afterPropertiesSet。 SqlSessionFactory有大量可配置项,这些配置项最终转变为SqlSessionFactory的构建参数(Configuration)

@OverridepublicvoidafterPropertiesSet()throwsException{ notNull(dataSource,"Property'dataSource'isrequired");notNull(sqlSessionFactoryBuilder,"Property'sqlSessionFactoryBuilder'isrequired");state((configuration==null&&configLocation==null)||!(configuration!=null&&configLocation!=null),"Property'configuration'and'configLocation'cannotspecifiedwithtogether");this.sqlSessionFactory=buildSqlSessionFactory();}protectedSqlSessionFactorybuildSqlSessionFactory()throwsException{ finalConfigurationtargetConfiguration;...XMLConfigBuilderxmlConfigBuilder=null;if(this.configuration!=null){ targetConfiguration=this.configuration;if(targetConfiguration.getVariables()==null){ targetConfiguration.setVariables(this.configurationProperties);}elseif(this.configurationProperties!=null){ targetConfiguration.getVariables().putAll(this.configurationProperties);}}elseif(this.configLocation!=null){ xmlConfigBuilder=newXMLConfigBuilder(this.configLocation.getInputStream(),null,this.configurationProperties);targetConfiguration=xmlConfigBuilder.getConfiguration();}else{ LOGGER.debug(()->"Property'configuration'or'configLocation'notspecified,usingdefaultMyBatisConfiguration");targetConfiguration=newConfiguration();Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);}...returnthis.sqlSessionFactoryBuilder.build(targetConfiguration);}Mapper类如何注册成bean到BeanFactory中的

       ä½¿ç”¨äº†mybatis-spring,会扫描特定的Mapper类(@MapperScan注解控制,控制标注了任意注解的接口可以被注册上,还可以配置接口的parent判断),然后作为Bean注册到beanFactory中,从而能被其他的bean依赖使用。

@MapperpublicinterfaceUserMapper{ UsergetUserById(longid);}

       è¦å®žçŽ°è¿™æ ·çš„scan机制,就需要一个scan mapper的BeanPostProcessor,这个processor中,scan当前classpath下满足MapperScan配置的package要求的类(接口),并且判断是否有@Mapper注解,如果符合,创建BeanDefinition注册到BeanFactory中。在getBean的时候,调用MapperFactoryBean.getObject拿到的Mapper代理,实现是Configuration.getMapper(Class type, SqlSession sqlSession), SqlSession是SqlSessionTemplate自身。最后在afterPropertiesSet,会拿到SqlSessionFactory.getConfiguration(),调用addMapper(Class type)添加到mybatis中

       ä¸ºä»€ä¹ˆå¢žåŠ äº†@MapperScan注解,就能扫描注册Mapper了呢。从MapperScan类可以看到,上面有一个@Import注解,import了MapperScannerRegistrar

@Import(MapperScannerRegistrar.class)@Repeatable(MapperScans.class)public@interfaceMapperScan{ ...}

       spring的@Import注解一般用来引用其他的Configuration,还可以引用 ImportSelector和ImportBeanDefinitionRegistrar 实现或其他的Component类。

       Provides functionality equivalent to the element in Spring XML. Allows for importing @Configuration classes, ImportSelector and ImportBeanDefinitionRegistrar implementations, as well as regular component classes (as of 4.2; analogous to AnnotationConfigApplicationContext.register).

       æ€»ä¹‹ï¼Œç­‰ä»·äºŽå£°æ˜Žäº†ä¸€ä¸ªMapperScannerRegistrar Bean。我们看一下MapperScannerRegistrar的实现,MapperScannerRegistrat实现了ImportBeanDefinitionRegistrar和ResourceLoaderAware接口。

       ImportBeanDefinitionRegistrar接口,用来在处理@Configuration类的时候,创建bean definition级别的bean。

       Interface to be implemented by types that register additional bean definitions when processing @Configuration classes. Useful when operating at the bean definition level (as opposed to @Bean method/instance level) is desired or necessary.

       åœ¨spring的refresh阶段,有一步是invokeBeanFactoryPostProcessors,会调用到ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry,最终会调用到loadBeanDefinitionsFromRegistrars,调用到MapperScannerRegistrar.registerBeanDefinitions

@OverridepublicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry){ intregistryId=System.identityHashCode(registry);if(this.registriesPostProcessed.contains(registryId)){ thrownewIllegalStateException("postProcessBeanDefinitionRegistryalreadycalledonthispost-processoragainst"+registry);}if(this.factoriesPostProcessed.contains(registryId)){ thrownewIllegalStateException("postProcessBeanFactoryalreadycalledonthispost-processoragainst"+registry);}this.registriesPostProcessed.add(registryId);processConfigBeanDefinitions(registry);}privatevoidloadBeanDefinitionsForConfigurationClass(ConfigurationClassconfigClass,TrackedConditionEvaluatortrackedConditionEvaluator){ if(trackedConditionEvaluator.shouldSkip(configClass)){ StringbeanName=configClass.getBeanName();if(StringUtils.hasLength(beanName)&&this.registry.containsBeanDefinition(beanName)){ this.registry.removeBeanDefinition(beanName);}this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());return;}if(configClass.isImported()){ registerBeanDefinitionForImportedConfigurationClass(configClass);}for(BeanMethodbeanMethod:configClass.getBeanMethods()){ loadBeanDefinitionsForBeanMethod(beanMethod);}loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}privatevoidloadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar,AnnotationMetadata>registrars){ registrars.forEach((registrar,metadata)->registrar.registerBeanDefinitions(metadata,this.registry));}

       å†çœ‹ä¸€ä¸‹MapperScannerRegistrar的实现。registerBeanDefinitions创建了一个BeanDefinition,bean是MapperScannerConfigurer,配置了MapperScannerConfigurer需要的属性配置(配置来源于@MapperScan注解),例如annotationClass, factoryBean等。

publicclassMapperScannerRegistrarimplementsImportBeanDefinitionRegistrar,ResourceLoaderAware{ @OverridepublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry){ AnnotationAttributesmapperScanAttrs=AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));if(mapperScanAttrs!=null){ registerBeanDefinitions(importingClassMetadata,mapperScanAttrs,registry,generateBaseBeanName(importingClassMetadata,0));}}voidregisterBeanDefinitions(AnnotationMetadataannoMeta,AnnotationAttributesannoAttrs,BeanDefinitionRegistryregistry,StringbeanName){ BeanDefinitionBuilderbuilder=BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);builder.addPropertyValue("processPropertyPlaceHolders",true);Class<?extendsAnnotation>annotationClass=annoAttrs.getClass("annotationClass");if(!Annotation.class.equals(annotationClass)){ builder.addPropertyValue("annotationClass",annotationClass);}Class<?>markerInterface=annoAttrs.getClass("markerInterface");if(!Class.class.equals(markerInterface)){ builder.addPropertyValue("markerInterface",markerInterface);}Class<?extendsBeanNameGenerator>generatorClass=annoAttrs.getClass("nameGenerator");if(!BeanNameGenerator.class.equals(generatorClass)){ builder.addPropertyValue("nameGenerator",BeanUtils.instantiateClass(generatorClass));}Class<?extendsMapperFactoryBean>mapperFactoryBeanClass=annoAttrs.getClass("factoryBean");if(!MapperFactoryBean.class.equals(mapperFactoryBeanClass)){ builder.addPropertyValue("mapperFactoryBeanClass",mapperFactoryBeanClass);}StringsqlSessionTemplateRef=annoAttrs.getString("sqlSessionTemplateRef");if(StringUtils.hasText(sqlSessionTemplateRef)){ builder.addPropertyValue("sqlSessionTemplateBeanName",annoAttrs.getString("sqlSessionTemplateRef"));}StringsqlSessionFactoryRef=annoAttrs.getString("sqlSessionFactoryRef");if(StringUtils.hasText(sqlSessionFactoryRef)){ builder.addPropertyValue("sqlSessionFactoryBeanName",annoAttrs.getString("sqlSessionFactoryRef"));}List<String>basePackages=newArrayList<>();basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));if(basePackages.isEmpty()){ basePackages.add(getDefaultBasePackage(annoMeta));}StringlazyInitialization=annoAttrs.getString("lazyInitialization");if(StringUtils.hasText(lazyInitialization)){ builder.addPropertyValue("lazyInitialization",lazyInitialization);}StringdefaultScope=annoAttrs.getString("defaultScope");if(!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)){ builder.addPropertyValue("defaultScope",defaultScope);}builder.addPropertyValue("basePackage",StringUtils.collectionToCommaDelimitedString(basePackages));registry.registerBeanDefinition(beanName,builder.getBeanDefinition());}privatestaticStringgenerateBaseBeanName(AnnotationMetadataimportingClassMetadata,intindex){ returnimportingClassMetadata.getClassName()+"#"+MapperScannerRegistrar.class.g