模拟Mybatis的实现方法
所需要用到的其他工具或技术:
项目管理工具:Maven
测试运行工具:Junit
数据库 :Derby
XML操作工具:Dom4j
继续不废话
MavenDependencies:
junit junit 4.9 test org.apache.derby derby 10.10.2.0 org.apache.derby derbyclient 10.10.2.0 dom4j dom4j 1.6.1
SQL建表及数据插入(如果在第一节中作过,可以跳过此步):
CREATETABLEUSER_TEST_TB( IDINTPRIMARYKEY, USERNAMEVARCHAR(20)NOTNULL, PASSWORDVARCHAR(20)NOTNULL, NICKNAMEVARCHAR(20)NOTNULL ); INSERTINTOUSER_TEST_TBVALUES(1,'1st','111','Jack'); INSERTINTOUSER_TEST_TBVALUES(2,'2nd','222','Rose'); INSERTINTOUSER_TEST_TBVALUES(3,'3rd','333','Will');
Mybatis配置文件src/main/resource源目录下
test-mybatis-configuration.xml
User.java对象类(src/main/java/com/bjpowernode/practice目录下)
packagecom.bjpowernode.practice; /** * *UserModel * */ publicclassUser { privateStringid; privateStringusername; privateStringpassword; privateStringnickname; publicStringgetId() { returnid; } publicvoidsetId(Stringid) { this.id=id; } publicStringgetUsername() { returnusername; } publicvoidsetUsername(Stringusername) { this.username=username; } publicStringgetPassword() { returnpassword; } publicvoidsetPassword(Stringpassword) { this.password=password; } publicStringgetNickname() { returnnickname; } publicvoidsetNickname(Stringnickname) { this.nickname=nickname; } }
Select.java注解类(src/main/java/com/bjpowernode/practice/annotation目录下)
packagecom.bjpowernode.practice.annotation; importjava.lang.annotation.ElementType; importjava.lang.annotation.Retention; importjava.lang.annotation.RetentionPolicy; importjava.lang.annotation.Target; /**标注此注解只能用在方法上*/ @Target(ElementType.METHOD) /**标注此注解生命周期是在Runtime运行时*/ @Retention(RetentionPolicy.RUNTIME) public@interfaceSelect { Stringvalue(); }
UserMapper.java基于Annotation的配置类(src/main/java/com/bjpowernode/practice/annotation目录下)
packagecom.bjpowernode.practice.annotation; importcom.bjpowernode.practice.User; importjava.util.List; publicinterfaceUserMapper { @Select("select*fromUSER_TEST_TB") publicListgetUser(); }
Mapper.java对象类(src/main/java/com/bjpowernode/practice/simulation目录下)
packagecom.bjpowernode.practice.simulation; /** * *存储查询结果对象 * */ publicclassMapper { /** *返回类型 */ privateStringresultType; /** *查询SQL */ privateStringquerySql; publicStringgetResultType() { returnresultType; } publicvoidsetResultType(StringresultType) { this.resultType=resultType; } publicStringgetQuerySql() { returnquerySql; } publicvoidsetQuerySql(StringquerySql) { this.querySql=querySql; } }
SQLSelectProxy.javaAOP动态代理类(src/main/java/com/bjpowernode/practice/simulation目录下)
packagecom.bjpowernode.practice.simulation; importcom.bjpowernode.practice.annotation.Select; importjava.lang.reflect.InvocationHandler; importjava.lang.reflect.Method; importjava.sql.PreparedStatement; importjava.sql.ResultSet; importjava.util.List; publicclassSQLSelectProxyimplementsInvocationHandler { @Override publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable { /** *获得Mapper方法上的Select注解,以此来取得注解中的SQL语句 */ Selectselect=method.getAnnotation(Select.class); if(!method.isAnnotationPresent(Select.class)) { thrownewRuntimeException("缺少@Select注解!"); } PreparedStatementpstmt=null; ResultSetrs=null; Objectobj=null; try { pstmt=SqlSessionImpl.connection.prepareStatement(select.value()); rs=pstmt.executeQuery(); /** *获得Method的返回对象类型,此处应当作判断处理,当List的时候,当只返回一个对象的时候. *为了简单实现功能并与第一节中测试文件不发生冲突起见,此处当作List处理 */ StringreturnType=method.getGenericReturnType().toString();//java.util.Listif(returnType.startsWith(List.class.getName())) { //去掉我们不需要的字符串,得到List中的类型 returnType=returnType.replace(List.class.getName(),"").replace("<","").replace(">",""); } else { //返回其他对象应当作其他处理,此处为了简单起见,暂不处理 } obj=SqlSessionImpl.executeQuery(rs,returnType); } finally { if(rs!=null&&!rs.isClosed()) { rs.close(); } if(pstmt!=null&&!pstmt.isClosed()) { pstmt.close(); } } returnobj; } }
SqlSession.javaMybatis模拟接口(src/main/java/com/bjpowernode/practice/simulation目录下)
packagecom.bjpowernode.practice.simulation; importjava.util.List; /** * *模拟SqlSession * */ publicinterfaceSqlSession { publicTgetMapper(Class clazz); public List selectList(Stringquery)throwsException; }
SqlSessionFactory.javaMybatis模拟类(src/main/java/com/bjpowernode/practice/simulation目录下)
packagecom.bjpowernode.practice.simulation; importjava.io.IOException; importjava.io.InputStream; importjava.util.HashMap; importjava.util.List; importjava.util.Map; importorg.dom4j.Document; importorg.dom4j.DocumentException; importorg.dom4j.Element; importorg.dom4j.io.SAXReader; /** * *模拟SqlSessionFactory * */ publicclassSqlSessionFactory { privateInputStreamconfiguration; publicSqlSessionopenSession()throwsIOException { SqlSessionImplsession=newSqlSessionImpl(); loadConfigurations(session); returnsession; } /** * *通过Dom4j读取配置文件信息 * *@paramsession *@throwsIOException */ privatevoidloadConfigurations(finalSqlSessionImplsession)throwsIOException { try { Documentdocument=newSAXReader().read(configuration); Elementroot=document.getRootElement(); Listmappers=root.element("mappers").elements("mapper"); for(Elementmapper:mappers) { if(mapper.attribute("resource")!=null) { session.setXmlSQLs(loadXMLConfiguration(mapper.attribute("resource").getText())); } if(mapper.attribute("class")!=null) { } } } catch(Exceptione) { System.out.println("读取配置文件错误!"); } finally { configuration.close(); } } /** * *通过dom4j读取Mapper.xml中的信息 * *@paramresource *@return *@throwsDocumentException *@throwsIOException */ privateMap loadXMLConfiguration(Stringresource)throwsDocumentException,IOException { Map map=newHashMap (); InputStreamis=null; try { is=this.getClass().getClassLoader().getResourceAsStream(resource); Documentdocument=newSAXReader().read(is); Elementroot=document.getRootElement(); if(root.getName().equalsIgnoreCase("mapper")) { Stringnamespace=root.attribute("namespace").getText(); for(Elementselect:(List )root.elements("select")) { MappermapperModel=newMapper(); mapperModel.setResultType(select.attribute("resultType").getText()); mapperModel.setQuerySql(select.getText().trim()); map.put(namespace+"."+select.attribute("id").getText(),mapperModel); } } } finally { is.close(); } returnmap; } publicInputStreamgetConfiguration() { returnconfiguration; } publicvoidsetConfiguration(InputStreamconfiguration) { this.configuration=configuration; } }
SqlSessionFactoryBuilder.javaMybatis模拟类(src/main/java/com/bjpowernode/practice/simulation目录下)
packagecom.bjpowernode.practice.simulation; importjava.io.InputStream; /** * *模拟SqlSessionFactoryBuilder * */ publicclassSqlSessionFactoryBuilder { publicSqlSessionFactorybuild(InputStreamis) { SqlSessionFactorysessionFactory=newSqlSessionFactory(); sessionFactory.setConfiguration(is); returnsessionFactory; } }
SqlSessionImpl.javaMybatis模拟类(src/main/java/com/bjpowernode/practice/simulation目录下)
packagecom.bjpowernode.practice.simulation; importjava.lang.reflect.Method; importjava.lang.reflect.Proxy; importjava.sql.Connection; importjava.sql.DriverManager; importjava.sql.PreparedStatement; importjava.sql.ResultSet; importjava.util.ArrayList; importjava.util.List; importjava.util.Map; /** * *模拟SqlSessionImpl * */ publicclassSqlSessionImplimplementsSqlSession { /**DBconnection*/ publicstaticConnectionconnection; privateMapxmlSQLs; privateList annotationClasses; publicSqlSessionImpl() { /** *driverString和connString应该是从配置文件读取,这里简化了 */ finalStringdriverString="org.apache.derby.jdbc.ClientDriver"; finalStringconnString="jdbc:derby://localhost:1527/bjpowernode;create=true"; try { Class.forName(driverString); /**获得DB连接*/ connection=DriverManager.getConnection(connString); } catch(Exceptione) { System.out.println("获取DBConnection出错!"); } } /** *基于Annotation的数据库操作 * */ @Override public TgetMapper(Class clazz) { TclazzImpl= (T)Proxy.newProxyInstance(this.getClass().getClassLoader(),newClass[]{clazz},newSQLSelectProxy()); returnclazzImpl; } /** * *基于XML的查询操作 */ @Override public List selectList(Stringquery)throwsException { PreparedStatementpstmt=null; ResultSetrs=null; try { /**简单的PreparedStatemeJDBC实现*/ pstmt=connection.prepareStatement(xmlSQLs.get(query).getQuerySql()); rs=pstmt.executeQuery(); /**执行查询操作*/ returnexecuteQuery(rs,xmlSQLs.get(query).getResultType()); } finally { if(!rs.isClosed()) { rs.close(); } if(!pstmt.isClosed()) { pstmt.close(); } } } /** * *执行查询操作,并将查询到的结果与配置中的ResultType根据变量名一一对应,通过反射调用Set方法注入各个变量的值 * *@paramrs *@paramtype *@return *@throwsException */ publicstatic List executeQuery(ResultSetrs,Stringtype)throwsException { intcount=rs.getMetaData().getColumnCount(); List columnNames=newArrayList (); for(inti=1;i<=count;i++) { columnNames.add(rs.getMetaData().getColumnName(i)); } finalListlist=newArrayList
UserMapper.xml基于XML的Mapper配置文件(src/main/java/com/bjpowernode/practice/xml目录下)
select* fromUSER_TEST_TB
TestMyBatis.java测试类(src/test/java/com/bjpowernode/practice目录下)
packagecom.bjpowernode.practice; importcom.bjpowernode.practice.annotation.UserMapper; importcom.bjpowernode.practice.simulation.SqlSession; importcom.bjpowernode.practice.simulation.SqlSessionFactory; importcom.bjpowernode.practice.simulation.SqlSessionFactoryBuilder; importcom.bjpowernode.practice.simulation.SqlSessionImpl; importjava.io.InputStream; importjava.sql.SQLException; importjava.text.MessageFormat; importjava.util.List; importorg.junit.After; importorg.junit.Before; importorg.junit.Test; publicclassTestMyBatis { /**配置置文件*/ privateStringsource; privateInputStreaminputStream; privateSqlSessionFactorysqlSessionFactory; @Before publicvoidsetUp() { source="test-mybatis-configuration.xml"; } /** * *基于XML格式配置的测试方法 * */ @Test publicvoidtestXMLConfingure() { try { /** *获得Session */ inputStream=TestMyBatis.class.getClassLoader().getResourceAsStream(source); sqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream); SqlSessionsession=sqlSessionFactory.openSession(); /** *执行Query操作 */ Listusers=(List)session.selectList("com.bjpowernode.practice.UserMapper.getUser"); System.out.println("QuerybyXMLconfiguration..."); /** *打印结果 */ this.printUsers(users); } catch(Exceptione) { e.printStackTrace(); } } /** * *基于Annotation配置的测试方法 * */ @Test publicvoidtestAnnotationConfingure() { try { inputStream=TestMyBatis.class.getClassLoader().getResourceAsStream(source); sqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream); SqlSessionsession=sqlSessionFactory.openSession(); UserMapperuserMapper=session.getMapper(UserMapper.class); System.out.println("\r\nQuerybyannotationconfiguration..."); this.printUsers(userMapper.getUser()); } catch(Exceptione) { e.printStackTrace(); } } @After publicvoidclearUp()throwsSQLException { if(SqlSessionImpl.connection!=null&&!SqlSessionImpl.connection.isClosed()) { SqlSessionImpl.connection.close(); } } privatevoidprintUsers(finalList users) { intcount=0; for(Useruser:users) { System.out.println(MessageFormat.format("==User[{0}]=================",++count)); System.out.println("UserId:"+user.getId()); System.out.println("UserUserName:"+user.getUsername()); System.out.println("UserPassword:"+user.getPassword()); System.out.println("Usernickname:"+user.getNickname()); } } }
以上就是基于XML以及Annotation的方式对Mybatis实现了一个简单的模拟。旨在理解Mybatis的工作原理。
笔者一直觉得当学习一个工具类技术的时候,路线应该是
1.实现一个小例子
2.找材料理解其中原理
3.学习技术细节,并动手全部实现
4.在全部学完之后动手做一个小项目,尽可能的使用这个在技术中的各个环节。
总结
以上所述是小编给大家介绍的模拟Mybatis的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。