Mybatis常用配置方式

Spring中Mybatis的配置方案一

2.1 多數(shù)據(jù)源配置案例

(1)數(shù)據(jù)源配置(2)創(chuàng)建sqlSessionFactory(3)配置掃描器,掃描指定路徑的mapper生成數(shù)據(jù)庫操作代理類(4)數(shù)據(jù)源配置(5)創(chuàng)建sqlSessionFactory(6)配置掃描器,掃描指定路徑的mapper生成數(shù)據(jù)庫操作代理類

(1)(2)(3)是一組配置布蔗, (4)(5)(6)是一組配置友驮,配置指定的數(shù)據(jù)源到對應的包下掃描配置文件生成數(shù)據(jù)庫操作代理類疼鸟。

(1)(4)分別創(chuàng)建了兩個數(shù)據(jù)源殴蓬,(2)(5)根據(jù)對應的數(shù)據(jù)源創(chuàng)建SqlSession工廠立润,(3)(6)配置mybaits掃描器狂窑,根據(jù)對應的SqlSession工廠和包路徑生成代理后的數(shù)據(jù)庫操作類。

2.1 原理簡單介紹

2.1.1 SqlSessionFactory原理

(2)(5)作用是根據(jù)配置創(chuàng)建一個SqlSessionFactory桑腮,看下SqlSessionFactoryBean的代碼知道它實現(xiàn)了FactoryBean和InitializingBean類泉哈,由于實現(xiàn)了InitializingBean,所以自然它的afterPropertiesSet方法破讨,由于實現(xiàn)了FactoryBean類丛晦,所以自然會有getObject方法。下面看下時序圖:

screenshot.png

從時序圖可知提陶,SqlSessionFactoryBean類主要是通過屬性配置創(chuàng)建SqlSessionFactory實例采呐,具體是解析配置中所有的mapper文件放到configuration,然后作為構造函數(shù)參數(shù)實例化一個DefaultSqlSessionFactory作為SqlSessionFactory。

2.1.2 MapperScannerConfigurer原理

掃描指定路徑的mapper生成數(shù)據(jù)庫操作代理類

MapperScannerConfigurer 實現(xiàn)了 BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware接口搁骑,所以會重寫一下方法:

//在bean注冊到ioc后創(chuàng)建實例前修改bean定義和新增bean注冊斧吐,這個是在context的refresh方法調(diào)用voidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)throwsBeansException;//在bean注冊到ioc后創(chuàng)建實例前修改bean定義或者屬性值voidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throwsBeansException;//set屬性設置后調(diào)用voidafterPropertiesSet()throwsException;//獲取IOC容器上下文,在context的prepareBeanFactory中調(diào)用voidsetApplicationContext(ApplicationContext applicationContext)throwsBeansException;//獲取bean在ioc容器中名字仲器,在context的prepareBeanFactory中調(diào)用voidsetBeanName(String name);

先上個掃描mapper生成代理類并注冊到ioc時序圖:

screenshot.png

首先MapperScannerConfigurer實現(xiàn)的afterPropertiesSet方法用來確保屬性basePackage不為空

publicvoidafterPropertiesSet()throwsException{? ? notNull(this.basePackage,"Property 'basePackage' is required");? }

postProcessBeanFactory里面啥都沒做煤率,setBeanName獲取了bean的名字,setApplicationContext里面獲取了ioc上下文乏冀。下面看重要的方法postProcessBeanDefinitionRegistry蝶糯,由于mybais是運行時候才通過解析mapper文件生成代理類注入到ioc,所以postProcessBeanDefinitionRegistry正好可以干這個事情辆沦。

publicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry){if(this.processPropertyPlaceHolders) {? ? ? processPropertyPlaceHolders();? ? }//構造一個ClassPathMapperScanner查找mapperClassPathMapperScanner scanner =newClassPathMapperScanner(registry);? ? scanner.setAddToConfig(this.addToConfig);//javax.annotation.Resourcescanner.setAnnotationClass(this.annotationClass);? ? scanner.setMarkerInterface(this.markerInterface);//引用sqlSessionFactoryscanner.setSqlSessionFactory(this.sqlSessionFactory);? ? scanner.setSqlSessionTemplate(this.sqlSessionTemplate);? ? scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);? ? scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);//ioc上下文scanner.setResourceLoader(this.applicationContext);? ? scanner.setBeanNameGenerator(this.nameGenerator);? ? scanner.registerFilters();//basePackage=com.alibaba.***.dal.***.mapper,com.alibaba.rock.auth.mapper,com.alibaba.rock.workflow.dal.workflow.mapperscanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));? }

下面重點看下scan方法:

publicSet doScan(String... basePackages) {//根據(jù)指定路徑去查找對應mapper的接口類昼捍,并轉化為beandefinationSet beanDefinitions =super.doScan(basePackages);if(beanDefinitions.isEmpty()) {? ? ? logger.warn("No MyBatis mapper was found in '"+ Arrays.toString(basePackages) +"' package. Please check your configuration.");? ? }else{//修改接口類bean的beandefinationprocessBeanDefinitions(beanDefinitions);? ? }returnbeanDefinitions;? }

其中super.doScan(basePackages);根據(jù)指定路徑查找mapper接口類,并生成bean的定義對象肢扯,對象中包含beanclassname,beanclass屬性妒茬,最后注冊該bean到ioc容器。下面看下最重要的processBeanDefinitions方法對bean定義的改造蔚晨。

privatevoidprocessBeanDefinitions(Set beanDefinitions){? ? GenericBeanDefinition definition;for(BeanDefinitionHolder holder : beanDefinitions) {? ? ? definition = (GenericBeanDefinition) holder.getBeanDefinition();// 上面講的掃描后beanclass設置的為mapper接口類乍钻,但是這里修改為MapperFactoryBean,MapperFactoryBean代理了mapper接口類,并且實際mapper接口類作為構造函數(shù)傳入了? ? ? definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); definition.setBeanClass(this.mapperFactoryBean.getClass());? ? ? definition.getPropertyValues().add("addToConfig",this.addToConfig);//設置屬性配置中的sqlSessionFactorybooleanexplicitFactoryUsed =false;if(StringUtils.hasText(this.sqlSessionFactoryBeanName)) {? ? ? ? definition.getPropertyValues().add("sqlSessionFactory",newRuntimeBeanReference(this.sqlSessionFactoryBeanName));? ? ? ? explicitFactoryUsed =true;? ? ? }elseif(this.sqlSessionFactory !=null) {? ? ? ? definition.getPropertyValues().add("sqlSessionFactory",this.sqlSessionFactory);? ? ? ? explicitFactoryUsed =true;? ? ? }if(StringUtils.hasText(this.sqlSessionTemplateBeanName)) {if(explicitFactoryUsed) {? ? ? ? ? logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");? ? ? ? }? ? ? ? definition.getPropertyValues().add("sqlSessionTemplate",newRuntimeBeanReference(this.sqlSessionTemplateBeanName));? ? ? ? explicitFactoryUsed =true;? ? ? }elseif(this.sqlSessionTemplate !=null) {if(explicitFactoryUsed) {? ? ? ? ? logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");? ? ? ? }? ? ? ? definition.getPropertyValues().add("sqlSessionTemplate",this.sqlSessionTemplate);? ? ? ? explicitFactoryUsed =true;? ? ? }if(!explicitFactoryUsed) {if(logger.isDebugEnabled()) {? ? ? ? ? logger.debug("Enabling autowire by type for MapperFactoryBean with name '"+ holder.getBeanName() +"'.");? ? ? ? }? ? ? ? definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);? ? ? }? ? }? }

注:這里修改了mapper接口類的beandefination中的beanclass為MapperFactoryBean,它則負責生產(chǎn)數(shù)據(jù)類操作代理類银择,實際mapper接口類作為構造函數(shù)傳入了 多糠。由于只修改了beanclass,沒有修改beanname,所以我們從容器中獲取時候無感知的浩考。

在上一個代理bean如何構造的時序圖:

screenshot.png

下面看下MapperFactoryBean是如何生成代理類的:

首先夹孔,上面代碼設置了MapperFactoryBean的setSqlSessionFactory方法:

publicvoidsetSqlSessionFactory(SqlSessionFactory sqlSessionFactory){if(!this.externalSqlSession) {this.sqlSession =newSqlSessionTemplate(sqlSessionFactory);? ? }? }

上面方法創(chuàng)建了sqlSession,由于MapperFactoryBean為工廠bean所以實例化時候會調(diào)用getObject方法:

publicTgetObject()throwsException{returngetSqlSession().getMapper(this.mapperInterface);? }

其實是調(diào)用了SqlSessionTemplate->getMapper,其中mapperInterface就是創(chuàng)建MapperFactoryBean時候的構造函數(shù)參數(shù)析孽。

publicTgetMapper(Class type){returngetConfiguration().getMapper(type,this);? }

這里調(diào)用getConfiguration().getMapper(type, this);實際是DefaultSqlSessionFactory里面的configration的getMapper方法:

public T getMapper(Classtype,SqlSessionsqlSession){//knownMappers是上面時序圖中步驟6設置進入的析蝴。finalMapperProxyFactory mapperProxyFactory = (MapperProxyFactory) knownMappers.get(type);if(mapperProxyFactory ==null) {thrownewBindingException("Type "+ type +" is not known to the MapperRegistry.");? ? }try{returnmapperProxyFactory.newInstance(sqlSession);? ? }catch(Exceptione) {thrownewBindingException("Error getting mapper instance. Cause: "+ e, e);? ? }? }protectedT newInstance(MapperProxy mapperProxy) {return(T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),newClass[]{ mapperInterface }, mapperProxy);? }publicT newInstance(SqlSession sqlSession) {//代理回調(diào)類為MapperProxyfinalMapperProxy mapperProxy =newMapperProxy(sqlSession, mapperInterface, methodCache);returnnewInstance(mapperProxy);? }

在上一個實際執(zhí)行sql時候調(diào)用代理類的序列圖:

screenshot.png

所以當調(diào)用實際的數(shù)據(jù)庫操作時候會調(diào)用MapperProxy的invoke方法:

publicObjectinvoke(Object proxy, Method method, Object[] args)throwsThrowable{if(Object.class.equals(method.getDeclaringClass())) {try{returnmethod.invoke(this, args);? ? ? }catch(Throwable t) {throwExceptionUtil.unwrapThrowable(t);? ? ? }? ? }finalMapperMethod mapperMethod = cachedMapperMethod(method);returnmapperMethod.execute(sqlSession, args);? }

mapperMethod.execute(sqlSession, args);里面實際是調(diào)用當前mapper對應的SqlSessionTemplate的數(shù)據(jù)庫操作,而它有委托給了代理類sqlSessionProxy绿淋,sqlSessionProxy是在SqlSessionTemplate的構造函數(shù)里面創(chuàng)建的:

publicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,

? ? ? PersistenceExceptionTranslator exceptionTranslator){? ? notNull(sqlSessionFactory,"Property 'sqlSessionFactory' is required");? ? notNull(executorType,"Property 'executorType' is required");this.sqlSessionFactory = sqlSessionFactory;this.executorType = executorType;this.exceptionTranslator = exceptionTranslator;this.sqlSessionProxy = (SqlSession) newProxyInstance(? ? ? ? SqlSessionFactory.class.getClassLoader(),newClass[] { SqlSession.class },newSqlSessionInterceptor());? }

所以最終數(shù)據(jù)庫操作有被代理SqlSessionInterceptor執(zhí)行:

publicObjectinvoke(Object proxy, Method method, Object[] args)throwsThrowable{//有TransactionSynchronizationManager管理SqlSession sqlSession = getSqlSession(? ? ? ? ? SqlSessionTemplate.this.sqlSessionFactory,? ? ? ? ? SqlSessionTemplate.this.executorType,? ? ? ? ? SqlSessionTemplate.this.exceptionTranslator);try{? ? ? ? Object result = method.invoke(sqlSession, args);if(!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {// force commit even on non-dirty sessions because some databases require// a commit/rollback before calling close()sqlSession.commit(true);? ? ? ? }returnresult;? ? ? }catch(Throwable t) {? ? ? ? ? .....? ? ? }? ? }publicstaticSqlSessiongetSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator){? ? notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);? ? notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);? ? SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);? ? SqlSession session = sessionHolder(executorType, holder);if(session !=null) {returnsession;? ? }if(LOGGER.isDebugEnabled()) {? ? ? LOGGER.debug("Creating a new SqlSession");? ? }//這里看到了使用sessionfactory熟悉的打開了一個sessionsession = sessionFactory.openSession(executorType);? ? registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);returnsession;? }

關于事務配置可移步:http://www.reibang.com/p/1d882343c036

三、Spring中Mybatis的配置方案二

2.1 多數(shù)據(jù)源配置案例

(1)數(shù)據(jù)源配置(2)創(chuàng)建sqlSessionFactory(3)配置掃描器尝盼,掃描指定路徑的mapper生成數(shù)據(jù)庫操作代理類(4)數(shù)據(jù)源配置(5)創(chuàng)建sqlSessionFactory(6)配置掃描器吞滞,掃描指定路徑的mapper生成數(shù)據(jù)庫操作代理類

與上節(jié)不同在在于(3)(6)

3.2 原理簡單介紹

這里只看??標簽解析,按照慣例看jar包的spring.handler找標簽解析

image.png

image.png

image.png

MapperScannerBeanDefinitionParser的代碼如下:

粘貼圖片.png

可知MapperScannerBeanDefinitionParser所做的事情和MapperScannerConfigurer類似都是內(nèi)部搞了個ClassPathMapperScanner盾沫。

四裁赠、SpringBoot中Mybatis的配置方案

4.1 SpringBoot中多數(shù)據(jù)源使用

數(shù)據(jù)源一配置:

//三、設置掃描器@MapperScan(basePackages ="com.alibaba.zlx.web.speech.mapper",sqlSessionFactoryRef="sqlSessionFactory1")publicclassTddlAutoConfiguration{@AutowiredprivateTddlProperties properties;//一赴精、創(chuàng)建數(shù)據(jù)源@Primary@Bean(name ="dataSource1")publicDataSourcedataSource1()throwsTddlException{? ? ? ? TDataSource dataSource =newTDataSource();? ? ? ? dataSource.setAppName(properties.getAppName());? ? ? ? dataSource.setSharding(properties.getSharding());? ? ? ? dataSource.setDynamicRule(properties.getDynamicRule());? ? ? ? dataSource.init();returndataSource;? ? }//二佩捞、創(chuàng)建SqlSessionFactory@Bean(name ="sqlSessionFactory1")@PrimarypublicSqlSessionFactorysqlSessionFactoryBean1()throwsException{? ? ? ? SqlSessionFactoryBean sqlSessionFactoryBean =newSqlSessionFactoryBean();? ? ? ? sqlSessionFactoryBean.setDataSource(dataSource1());? ? ? ? sqlSessionFactoryBean.setMapperLocations(resolveMapperLocations(newString[]{"classpath:mapper/*.xml"}));returnsqlSessionFactoryBean.getObject();? ? }//四、 創(chuàng)建事務管理器@Bean(name ="txManager1")@PrimarypublicPlatformTransactionManagertxManager1(@Qualifier("dataSource1")DataSource dataSource){? ? ? ? ? ? ? ? ? ? ? ? System.out.println("-----------dataource-----"+ dataSource.toString());returnnewDataSourceTransactionManager(dataSource);? ? }@Bean("sqlSessionTemplate1")@PrimarypublicSqlSessionTemplatesqlSessionTemplate(@Qualifier("sqlSessionFactory1")SqlSessionFactory sqlSessionFactory){? ? ? ? System.out.println("-----------sqlSessionFactory-----"+ sqlSessionFactory.toString());returnnewSqlSessionTemplate(sqlSessionFactory);? ? }}

數(shù)據(jù)源二配置:

//三蕾哟、設置掃描器@MapperScan(basePackages ="com.alibaba.gh.web.speech.mapper", sqlSessionFactoryRef ="sqlSessionFactory2")publicclassTddlAutoConfiguration2{@AutowiredprivateTddlProperties properties;//一一忱、創(chuàng)建數(shù)據(jù)源@Bean(name ="dataSource2")publicDataSourcedataSource2()throwsTddlException{? ? ? ? TDataSource dataSource =newTDataSource();? ? ? ? dataSource.setAppName(properties.getAppName());? ? ? ? dataSource.setSharding(properties.getSharding());? ? ? ? dataSource.setDynamicRule(properties.getDynamicRule());? ? ? ? dataSource.init();returndataSource;? ? }//二、創(chuàng)建SqlSessionFactory@Bean(name ="sqlSessionFactory2")publicSqlSessionFactorysqlSessionFactoryBean1()throwsException{? ? ? ? SqlSessionFactoryBean sqlSessionFactoryBean =newSqlSessionFactoryBean();? ? ? ? sqlSessionFactoryBean.setDataSource(dataSource2());? ? ? ? sqlSessionFactoryBean.setMapperLocations(resolveMapperLocations(newString[] {"classpath:mapper2/*.xml"}));returnsqlSessionFactoryBean.getObject();? ? }// 四谭确、創(chuàng)建事務管理器@Bean(name ="txManager2")publicPlatformTransactionManagertxManager1(@Qualifier("dataSource2")DataSource dataSource){? ? ? ? System.out.println("-----------dataource-----"+ dataSource.toString());returnnewDataSourceTransactionManager(dataSource);? ? }@Bean("sqlSessionTemplate2")publicSqlSessionTemplatesqlSessionTemplate(@Qualifier("sqlSessionFactory2")SqlSessionFactory sqlSessionFactory){? ? ? ? System.out.println("-----------sqlSessionFactory-----"+ sqlSessionFactory.toString());returnnewSqlSessionTemplate(sqlSessionFactory);? ? }}

另外SqlSessionTemplate是對SqlSessionFactory的一個包裝帘营,這里每個數(shù)據(jù)源也配置了一個,如果想使用它的話逐哈,只需要修改@mapperscan芬迄,設置sqlSessionTemplateRef替換sqlSessionFactoryRef

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市昂秃,隨后出現(xiàn)的幾起案子禀梳,更是在濱河造成了極大的恐慌,老刑警劉巖肠骆,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件算途,死亡現(xiàn)場離奇詭異,居然都是意外死亡蚀腿,警方通過查閱死者的電腦和手機郊艘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人纱注,你說我怎么就攤上這事畏浆。” “怎么了狞贱?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵刻获,是天一觀的道長。 經(jīng)常有香客問我瞎嬉,道長蝎毡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任氧枣,我火速辦了婚禮沐兵,結果婚禮上,老公的妹妹穿的比我還像新娘便监。我一直安慰自己扎谎,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布烧董。 她就那樣靜靜地躺著毁靶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逊移。 梳的紋絲不亂的頭發(fā)上预吆,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音胳泉,去河邊找鬼拐叉。 笑死,一個胖子當著我的面吹牛扇商,可吹牛的內(nèi)容都是我干的巷嚣。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼钳吟,長吁一口氣:“原來是場噩夢啊……” “哼廷粒!你這毒婦竟也來了?” 一聲冷哼從身側響起红且,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤坝茎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后暇番,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嗤放,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年壁酬,在試婚紗的時候發(fā)現(xiàn)自己被綠了次酌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恨课。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖岳服,靈堂內(nèi)的尸體忽然破棺而出剂公,到底是詐尸還是另有隱情,我是刑警寧澤吊宋,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布纲辽,位于F島的核電站,受9級特大地震影響璃搜,放射性物質(zhì)發(fā)生泄漏拖吼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一这吻、第九天 我趴在偏房一處隱蔽的房頂上張望吊档。 院中可真熱鬧,春花似錦唾糯、人聲如沸怠硼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吩愧,卻和暖如春芋酌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雁佳。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工脐帝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糖权。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓堵腹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親星澳。 傳聞我的和親對象是個殘疾皇子疚顷,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 單獨使用mybatis是有很多限制的(比如無法實現(xiàn)跨越多個session的事務),而且很多業(yè)務系統(tǒng)本來就是使用sp...
    七寸知架構閱讀 3,431評論 0 53
  • Spring 技術筆記Day 1 預熱知識一禁偎、 基本術語Blob類型腿堤,二進制對象Object Graph:對象圖...
    OchardBird閱讀 961評論 0 2
  • 1. 簡介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL如暖、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,429評論 0 4
  • # 前言 在前兩篇文章我們在 mybatis 源碼中探究了他的運行原理笆檀,但在實際使用中,我們需要將其和Spring...
    莫那一魯?shù)?/span>閱讀 3,456評論 0 4
  • 世人都在談愛情盒至,你我皆不能免俗酗洒。我們無聊的生活中總該有些什么士修,總該將這殘酷的生活模式詩意化浪漫化一些。不然只是延續(xù)...
    王小麥閱讀 1,455評論 14 19