应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

深入Mybatis

  1前言
  大家都知道MyBatis是我们常用的一个持久层框架,那么今天我们就来深入Mybatis底层,来探究MyBatis到底是怎么实现数据库操作的呢?2持久层的开发模式
  1传统的开发模式
  接口定义业务方法publicinterfaceUserService{publicUsergetUserById(intid);}
  实现类实现接口方法(sql语句写在java代码里面)publicclassUserServiceImplimplementsUserService{OverridepublicUsergetUserById(intid){ConnectionconnJDBCTools。getConnection();Stringsqlselectfromuserwhereid?;PreparedStatementpstmtnull;ResultSetrsnull;try{pstmtconn。prepareStatement(sql);pstmt。setInt(1,id);rspstmt。executeQuery();if(rs。next()){intsidrs。getInt(1);Stringnamers。getString(2);UserusernewUser(sid,name);returnuser;}}catch(Exceptione){TODOAutogeneratedcatchblocke。printStackTrace();}finally{JDBCTools。release(conn,pstmt,rs);}returnnull;}}
  测试Testpublicvoidf1()throwsException{UserServiceuserServicenewUserServiceImpl();UseruseruserService。getUserById(1);System。out。println(user);}
  2Mybatis的开发模式
  定义接口方法publicinterfaceUserMapper{publicUsergetUserById(intid);}
  接口对应的映射xml文件(sql语句写在xml文件)lt;?xmlversion1。0encodingUTF8?!DOCTYPEmapperPUBLICmybatis。orgDTDMapper3。0ENhttp:mybatis。orgdtdmybatis3mapper。dtdmappernamespacecn。itsource。mapper。UserMapperselectidgetUserByIdparameterTypejava。lang。IntegerresultTypecn。itsource。domain。UserselectfromUserwhereid{id}selectmapper
  测试Testpublicvoidf1()throwsException{UserMappermapper(UserMapper)newMyInvocationHandler()。getInstance(UserMapper。class);Userusermapper。getUserById(1);System。out。println(user);}
  通过以上代码可以看到,MyBatis的方式省去了实现类的创建,改为用xml来定义业务方法的具体实现
  为什么MyBatis可以不用通过实例化对象来操作我们的代码呢?这里就不得不说说jdk的动态代理
  jdk动态代理运行时结合接口和mapper。xml来动态创建一个代理对象,程序调用该代理对象的方法来完成业务3jdk动态代理
  创建一个类,实现InvocationHandler接口
  1自定义getInstance方法:入参为目标对象,通过Proxy。newProxyInstance方法创建代理对象,并返回
  2实现接口的invoke方法,通过反射机制完成业务逻辑代码
  invoke方法是核心代码,在该方法中实现具体的业务需求
  3使用invoke方法解析数据库信息配置xml,创建数据库连接对象读取数据源配置信息publicstaticMapString,StringgetProperties(){MapString,StringmapnewHashMapString,String();SAXReaderreadernewSAXReader();try{Documentdocumentreader。read(srcconfig。xml);获取根节点Elementrootdocument。getRootElement();Iteratoriterroot。elementIterator();while(iter。hasNext()){Elemente(Element)iter。next();解析environments节点if(environments。equals(e。getName())){Iteratoriter2e。elementIterator();while(iter2。hasNext()){解析environment节点Elemente2(Element)iter2。next();Iteratoriter3e2。elementIterator();while(iter3。hasNext()){Elemente3(Element)iter3。next();解析dataSource节点if(dataSource。equals(e3。getName())){if(POOLED。equals(e3。attributeValue(type))){Iteratoriter4e3。elementIterator();获取数据库连接信息while(iter4。hasNext()){Elemente4(Element)iter4。next();map。put(e4。attributeValue(name),e4。attributeValue(value));}}}}}}}}catch(Exceptione){TODOAutogeneratedcatchblocke。printStackTrace();}returnmap;}获取信息,创建数据源对象MapString,StringmapParseXML。getProperties();ComboPooledDataSourcedatasourcenewComboPooledDataSource();datasource。setDriverClass(map。get(driver));datasource。setJdbcUrl(map。get(url));datasource。setUser(map。get(username));datasource。setPassword(map。get(password));datasource。setInitialPoolSize(20);datasource。setMaxPoolSize(40);datasource。setMinPoolSize(2);datasource。setAcquireIncrement(5);Connectionconndatasource。getConnection();4反射
  数据库连接,接下来就需要获取待执行的SQL语句,sql的定义全部写在UserMapper。xml中;解析xml执行sql语句,执行完毕,查询结果会保存在ResultSet中,还需要将ResultSet对象中的数据进行解析,封装到JavaBean中返回
  上述步骤通过两步实现
  第一步:反射机制创建User对象
  第二步:通过反射动态执行类中所有属性的setter方法,完成赋值获取sql语句Stringsqlelement。getText();获取参数类型StringparameterTypeelement。attributeValue(parameterType);创建pstmtPreparedStatementpstmtcreatePstmt(sql,parameterType,conn,args);ResultSetrspstmt。executeQuery();if(rs。next()){读取返回数据类型StringresultTypeelement。attributeValue(resultType);反射创建对象ClassclazzClass。forName(resultType);objclazz。newInstance();获取ResultSet数据ResultSetMetaDatarsmdrs。getMetaData();遍历实体类属性集合,依次将结果集中的值赋给属性Field〔〕fieldsclazz。getDeclaredFields();for(inti0;ifields。length;i){ObjectvaluesetFieldValueByResultSet(fields〔i〕,rsmd,rs);通过属性名找到对应的setter方法Stringnamefields〔i〕。getName();namename。substring(0,1)。toUpperCase()name。substring(1);StringMethodNamesetname;MethodmethodObjclazz。getMethod(MethodName,fields〔i〕。getType());调用setter方法完成赋值methodObj。invoke(obj,value);}}
  代码的实现大致思路如上所述,具体实现起来有很多细节需要处理5工具类
  上述操作使用的两个工具类完整代码如下
  ParseXMLpublicclassParseXML{读取数据源配置信息publicstaticMapString,StringgetProperties(){MapString,StringmapnewHashMapString,String();SAXReaderreadernewSAXReader();try{Documentdocumentreader。read(srcconfig。xml);获取根节点Elementrootdocument。getRootElement();Iteratoriterroot。elementIterator();while(iter。hasNext()){Elemente(Element)iter。next();解析environments节点if(environments。equals(e。getName())){Iteratoriter2e。elementIterator();while(iter2。hasNext()){解析environment节点Elemente2(Element)iter2。next();Iteratoriter3e2。elementIterator();while(iter3。hasNext()){Elemente3(Element)iter3。next();解析dataSource节点if(dataSource。equals(e3。getName())){if(POOLED。equals(e3。attributeValue(type))){Iteratoriter4e3。elementIterator();获取数据库连接信息while(iter4。hasNext()){Elemente4(Element)iter4。next();map。put(e4。attributeValue(name),e4。attributeValue(value));}}}}}}}}catch(Exceptione){TODOAutogeneratedcatchblocke。printStackTrace();}returnmap;}根据接口查找对应的mapper。xmlpublicstaticStringgetMapperXML(StringclassName){保存xml路径Stringxml;SAXReaderreadernewSAXReader();Documentdocument;try{documentreader。read(srcconfig。xml);Elementrootdocument。getRootElement();Iteratoriterroot。elementIterator();while(iter。hasNext()){ElementmappersElement(Element)iter。next();if(mappers。equals(mappersElement。getName())){Iteratoriter2mappersElement。elementIterator();while(iter2。hasNext()){ElementmapperElement(Element)iter2。next();com。cehnjie。dao。StudentDAO。替换classNameclassName。replace(。,);获取接口结尾名StringclassNameEndclassName。split()〔className。split()。length1〕;StringresourceNamemapperElement。attributeValue(resource);获取resource结尾名StringresourceName2resourceName。split()〔resourceName。split()。length1〕;StudentDAO。xml。替换resourceName2resourceName2。replace(。,);StringresourceNameEndresourceName2。split()〔0〕;if(classNameEnd。equals(resourceNameEnd)){xmlsrcresourceName;}}}}}catch(DocumentExceptione){TODOAutogeneratedcatchblocke。printStackTrace();}returnxml;}}
  MyInvocationHandlerpublicclassMyInvocationHandlerimplementsInvocationHandler{privateStringclassName;publicObjectgetInstance(Classcls){保存接口类型classNamecls。getName();ObjectnewProxyInstanceProxy。newProxyInstance(cls。getClassLoader(),newClass〔〕{cls},this);return(Object)newProxyInstance;}publicObjectinvoke(Objectproxy,Methodmethod,Object〔〕args)throwsThrowable{SAXReaderreadernewSAXReader();返回结果Objectobjnull;try{获取对应的mapper。xmlStringxmlParseXML。getMapperXML(className);Documentdocumentreader。read(xml);Elementrootdocument。getRootElement();Iteratoriterroot。elementIterator();while(iter。hasNext()){Elementelement(Element)iter。next();Stringidelement。attributeValue(id);if(method。getName()。equals(id)){获取信息,创建数据源对象MapString,StringmapParseXML。getProperties();ComboPooledDataSourcedatasourcenewComboPooledDataSource();datasource。setDriverClass(map。get(driver));datasource。setJdbcUrl(map。get(url));datasource。setUser(map。get(username));datasource。setPassword(map。get(password));datasource。setInitialPoolSize(20);datasource。setMaxPoolSize(40);datasource。setMinPoolSize(2);datasource。setAcquireIncrement(5);Connectionconndatasource。getConnection();获取sql语句Stringsqlelement。getText();获取参数类型StringparameterTypeelement。attributeValue(parameterType);创建pstmtPreparedStatementpstmtcreatePstmt(sql,parameterType,conn,args);ResultSetrspstmt。executeQuery();if(rs。next()){读取返回数据类型StringresultTypeelement。attributeValue(resultType);反射创建对象ClassclazzClass。forName(resultType);objclazz。newInstance();获取ResultSet数据ResultSetMetaDatarsmdrs。getMetaData();遍历实体类属性集合,依次将结果集中的值赋给属性Field〔〕fieldsclazz。getDeclaredFields();for(inti0;ifields。length;i){ObjectvaluesetFieldValueByResultSet(fields〔i〕,rsmd,rs);通过属性名找到对应的setter方法Stringnamefields〔i〕。getName();namename。substring(0,1)。toUpperCase()name。substring(1);StringMethodNamesetname;MethodmethodObjclazz。getMethod(MethodName,fields〔i〕。getType());调用setter方法完成赋值methodObj。invoke(obj,value);}}conn。close();}}}catch(Exceptione){TODOAutogeneratedcatchblocke。printStackTrace();}returnobj;}根据条件创建pstmtparamsqlparamparameterTypeparamconnparamargsreturnthrowsExceptionpublicPreparedStatementcreatePstmt(Stringsql,StringparameterType,Connectionconn,Object〔〕args)throwsException{PreparedStatementpstmtnull;try{switch(parameterType){caseint:intstartsql。indexOf({);intendsql。indexOf(});获取参数占位符{name}Stringtargetsql。substring(start,end1);将参数占位符替换为?sqlsql。replace(target,?);pstmtconn。prepareStatement(sql);intnumInteger。parseInt(args〔0〕。toString());pstmt。setInt(1,num);break;casejava。lang。String:intstart2sql。indexOf({);intend2sql。indexOf(});Stringtarget2sql。substring(start2,end21);sqlsql。replace(target2,?);pstmtconn。prepareStatement(sql);Stringstrargs〔0〕。toString();pstmt。setString(1,str);break;default:ClassclazzClass。forName(parameterType);Objectobjargs〔0〕;booleanflagtrue;存储参数ListObjectvaluesnewArrayListObject();保存带的sqlStringsql2;while(flag){intstart3sql。indexOf({);判断{}是否替换完成if(start30){flagfalse;break;}intend3sql。indexOf(});Stringtarget3sql。substring(start3,end31);获取{}的值如{name}拿到nameStringnamesql。substring(start32,end3);通过反射获取对应的getter方法namename。substring(0,1)。toUpperCase()name。substring(1);StringMethodNamegetname;MethodmethodObjclazz。getMethod(MethodName);调用getter方法完成赋值ObjectvaluemethodObj。invoke(obj);values。add(value);sqlsql。replace(target3,?);sql2sql。replace(?,);}截取sql2,替换参数String〔〕sqlssql2。split();pstmtconn。prepareStatement(sql);for(inti0;isqls。length1;i){Objectvaluevalues。get(i);if(java。lang。String。equals(value。getClass()。getName())){pstmt。setString(i1,(String)value);}if(java。lang。Integer。equals(value。getClass()。getName())){pstmt。setInt(i1,(Integer)value);}}break;}}catch(SQLExceptione){TODOAutogeneratedcatchblocke。printStackTrace();}returnpstmt;}根据将结果集中的值赋给对应的属性paramfieldparamrsmdparamrsreturnpublicObjectsetFieldValueByResultSet(Fieldfield,ResultSetMetaDatarsmd,ResultSetrs){Objectresultnull;try{intcountrsmd。getColumnCount();for(inti1;icount;i){if(field。getName()。equals(rsmd。getColumnName(i))){Stringtypefield。getType()。getName();switch(type){caseint:resultrs。getInt(field。getName());break;casejava。lang。String:resultrs。getString(field。getName());break;default:break;}}}}catch(SQLExceptione){TODOAutogeneratedcatchblocke。printStackTrace();}returnresult;}}6总结
  MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理。多学习研究优秀框架的实现思路,对提升自己的编码能力大有裨益。

腰痛的中医治疗腰痛腰痛多为一侧或两侧疼痛,但又有兼正中脊部疼痛者,称为腰脊痛,西医的腰肌劳损,腰椎间盘突出症,坐骨神经痛均可参照治之1。肾着汤加减:治寒湿偏重腰痛,证见:腰部冷痛……李建群和名导同居27年不结婚,一生无儿无女,为何临终前坦言后你们两个不结婚,也不生孩子,等到老了肯定会后悔的。这是演员李建群父母对她说的话。李建群是在剧组拍戏时,和大她14岁的导演陈家林相恋。可恋爱多年,不论父母催婚如……博主月入百万,冥想成为市场新商机!节后超长工作日让打工人精神状态堪忧。各位inker们,你听说过冥想吗?最近几年,它的热度可以说是逐年攀升,成了都市社畜缓解焦虑的新方式。虽然乍一听像是玄学,但热爱它……黑龙江省1141户出口企业去年获退税24。38亿元2022年,为有效助力外贸高质量发展,帮助出口企业应对风险挑战,国家税务总局黑龙江省税务局持续加快出口退税进度,提升出口退税便利化水平,多措并举支持外贸企业稳资金、稳订单、稳市……理想L9陷辅助驾驶失灵争议,纠纷为何不可避免?新年伊始,造车新势力之一的理想汽车,连续因为交通事故争议引发关注。1月23日,网名为歪歪歪歪大叔的网友在微博上发了一段视频,并配文理想L9高速NOA(自动辅助导航驾驶)失……狠狠搞钱,养成10个富有的习惯1制定目标有目标才有动力,目标不要太大,不切合实际,先从小目标着手,一点点去激发自己内在的动力,脚踏实地去实现。2培养人脉多结交那些能帮助自己实现目标的人,换句话说……假性宫缩见红见羊水等如何分辨是否真临产及如何处理?2022育儿季导读:对于第一次怀孕生宝宝的孕妈来说,由于没有生育的经验,到了孕晚、临产前的时候,就会开始神经紧张起来,身体一旦有什么动静,就开始慌张无措,总以为是自己要开……5换1!三方交易!西蒙斯尽力了,76人和总冠军说再见吧上有计策下有对策,休赛期最大的悬念西蒙斯去哪儿还在上演。此前76人方面已经将本应该付给西蒙斯的825万美元薪资冻结,如果西蒙斯坚持不出战常规赛的话,76人将从这部分钱里扣除罚金……202122赛季需要更换球队,重振职业生涯或争夺总冠军的五名这些年来NBA球员因为种种原因不得不离开一支球队,前往另外一支球队效力。他们需要改变当前环境的两个最大原因是为了重振职业生涯和挑战总冠军。勒布朗詹姆斯离开克里夫兰骑士加入迈阿密……5部现象级雷剧,部部天雷滚滚,却都爆红一时,你看过哪一部?在这个烂片横行,只有更烂,没有最烂的年代,雷剧实在是浩如烟海,千奇百怪。但能够天雷滚滚,雷出风格,雷出话题度的却不多,这5部爆红一时的雷剧,你看过哪一部?雷得拖累了品牌,……欣然轻资讯G怪猎联动索尼克自杀小队杀死正义联盟卡普空宣布,《怪物猎人崛起》将于2021年11月26日发布《索尼克》联动合作任务!本次将同时发布2个特别活动任务,例如在原野中收集金环的任务,可充分体验作品《索尼克》的独……这条网红街的景色太美,湖光山色满树繁花,来过一次就爱上啦朋友们,我是美食营养师环环,私信我回复数字2,送你6个营养小锦囊。爱做营养美食,也喜欢探寻特色美食,欢迎您关注我,享受营养特色美食不迷路!疫情放缓,最美人间四月天整……
4战4球4助攻,阿根廷国脚中场阿尔马达当选美职联23月最佳直播吧3月31日讯美职联官方消息,亚特兰大联中场阿尔马达当选2月、3月最佳球员。新赛季美职联2月底开幕,阿根廷国脚中场阿尔马达代表亚特兰大联出战4场联赛,贡献4球4助攻,……人工智能AI绘画的美女,很逼真!以下内容全部来自于科技!未来人工智能替代一些人工的工作,指日可待呀!中国风美女中国风美女是指具有中国传统文化元素的美女形象,如汉服、唐装、蝴蝶装、旗袍、丝绸服饰等,配以传……楼盘烂尾关银行什么事?点评中南林樾断贷事件3月1号,中南林樾的业主发布公告,公告内容如下:1自2023年3月1日本告知书起,将停止向临沂中南项目按揭贷款合作银行(具体哪几个银行我就不提了)偿还个人贷款的每月还款直……杜兰特确定复出日期太阳没人搞破坏比篮网专注带保罗夺冠问题不大《亚利桑那体育》杜安兰金最新报道,凯文杜兰特初步确定太阳队主场迎战雷霆队的比赛复出,利用最后22场常规赛磨合阵容,杜兰特表示,克里斯保罗的篮球智商、经验会让他们快速产生良好化学……是德KeysightN5247BM高达67GHz的有源器件表套装解决方案可执行高达67GHz的毫米波有源器件表征包括N5247B67GHzPNAX(配有选件423020021022029)、S9300725298384868789B应用……极为相似!网友为证明英国就是陕西,列出了九大证据陕西和英国,每年都会吸引数百万游客前来旅游和消费,而且它们还以独特且类似的美食和景点,闻名于世。它们的魅力和壮丽是毋庸置疑的。陕西兵马俑被称为世界第七大奇迹,英国素……全市各行业场景各区移动通信用户感知度报告出炉,与你的感受一致市经信委介绍,2022年,上海持续推进双千兆宽带城市建设,全市累计建设5G室外基站6。8万个、室内小站27。4万个,基站总数增长76。为检验网络建设成效、持续提升城市信息基础设……CBA三热点赵睿脾气火爆,崔永熙发挥出色,四人已基本无缘国家1、赵睿是目前国内综合实力唯一能够比肩郭艾伦的后卫,但是本赛季的赵睿不论在广东队还是国家队,感觉都打的不舒服,经常在场上吃T,而且无视主教练,曾经在国家队和广东队顶撞过杜峰,这……肢解一个跨国巨头公司,只需要一场美国陷阱观书斋丨作者图片来源丨网络观书斋(公众号ID:guanshuzhaiyougan)一本好书,一部人生。2015年,美国通用电气以170亿美元收购了阿尔斯通的能……13600KB760M装机小雕够给力,果然还是13香前言目前这台AMDRyzen3600X已经服役四年多了,虽然性能还够用,但是平台已经老去,目前处境很尴尬:升级鸡肋弃之可惜。于是想着还是直接换一台新主机吧!在AMD和英特……女人不管多大,都要试试赫本风裙子,优雅时尚又洋气春天是一个很适合穿赫本风的季节,赫本风的裙子穿在身上,会显得整个人优雅又复古。最重要的是,赫本风根本不挑年纪,不管多大都可以尝试,每个年纪都可以穿出属于自己独一无二的味道。……你的孩子需要做窝沟封闭吗窝沟封闭是全世界公认的最有效、最经济、最具可操作性的一种窝沟干预策略。什么是窝沟封闭?窝沟封闭:是指在不损伤牙齿的情况下,将窝沟封闭剂涂抹到牙齿表面比较深的窝、沟、……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网