模拟Mybatis的实现方法

所需要用到的其他工具或技术:

项目管理工具 : Maven

测试运行工具 : Junit

数据库 : Derby

XML操作工具:Dom4j

继续不废话

Maven Dependencies:

<dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>4.9</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.apache.derby</groupId>
 <artifactId>derby</artifactId>
 <version>10.10.2.0</version>
 </dependency>
 <dependency>
 <groupId>org.apache.derby</groupId>
 <artifactId>derbyclient</artifactId>
 <version>10.10.2.0</version>
 </dependency>
 <dependency>
 <groupId>dom4j</groupId>
 <artifactId>dom4j</artifactId>
 <version>1.6.1</version>
 </dependency> 

SQL 建表及数据插入(如果在第一节中作过,可以跳过此步):

CREATE TABLE USER_TEST_TB(
ID INT PRIMARY KEY,
USERNAME VARCHAR(20) NOT NULL,
PASSWORD VARCHAR(20) NOT NULL,
NICKNAME VARCHAR(20) NOT NULL
);
INSERT INTO USER_TEST_TB VALUES(1,'1st','111','Jack');
INSERT INTO USER_TEST_TB VALUES(2,'2nd','222','Rose');
INSERT INTO USER_TEST_TB VALUES(3,'3rd','333','Will'); 

Mybatis配置文件 src/main/resource源目录下

test-mybatis-configuration.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
 <properties>
 <property name="driver" value="org.apache.derby.jdbc.ClientDriver" />
 <property name="url"
 value="jdbc:derby://localhost:1527/bjpowernode;create=true" />
 </properties>
 <environments default="development">
 <environment id="development">
 <transactionManager type="JDBC" />
 <dataSource type="POOLED">
 <property name="driver" value="${driver}" />
 <property name="url" value="${url}" />
 </dataSource>
 </environment>
 </environments>
 <mappers>
 <mapper class="com.bjpowernode.practice.annotation.UserMapper" />
 <mapper resource="com/bjpowernode/practice/xml/UserMapper.xml" />
 </mappers>
</configuration> 

User.java对象类(src/main/java/com/bjpowernode/practice目录下)

package com.bjpowernode.practice;
/**
 *
 * User Model
 *
 */
public class User
{
 private String id;
 private String username;
 private String password;
 private String nickname;
 public String getId()
 {
 return id;
 }
 public void setId(String id)
 {
 this.id = id;
 }
 public String getUsername()
 {
 return username;
 }
 public void setUsername(String username)
 {
 this.username = username;
 }
 public String getPassword()
 {
 return password;
 }
 public void setPassword(String password)
 {
 this.password = password;
 }
 public String getNickname()
 {
 return nickname;
 }
 public void setNickname(String nickname)
 {
 this.nickname = nickname;
 }
} 

Select.java 注解类(src/main/java/com/bjpowernode/practice/annotation目录下)

package com.bjpowernode.practice.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** 标注此注解只能用在方法上 */
@Target(ElementType.METHOD)
/** 标注此注解生命周期是在Runtime运行时 */
@Retention(RetentionPolicy.RUNTIME)
public @interface Select
{
 String value();
} 

UserMapper.java 基于Annotation的配置类(src/main/java/com/bjpowernode/practice/annotation目录下)

package com.bjpowernode.practice.annotation;
import com.bjpowernode.practice.User;
import java.util.List;
public interface UserMapper
{
 @Select("select * from USER_TEST_TB")
 public List<User> getUser();
} 

Mapper.java 对象类(src/main/java/com/bjpowernode/practice/simulation目录下)

package com.bjpowernode.practice.simulation;
/**
 *
 * 存储查询结果对象
 *
 */
public class Mapper
{
 /**
 * 返回类型
 */
 private String resultType;
 /**
 * 查询SQL
 */
 private String querySql;
 public String getResultType()
 {
 return resultType;
 }
 public void setResultType(String resultType)
 {
 this.resultType = resultType;
 }
 public String getQuerySql()
 {
 return querySql;
 }
 public void setQuerySql(String querySql)
 {
 this.querySql = querySql;
 }
} 

SQLSelectProxy.java AOP动态代理类(src/main/java/com/bjpowernode/practice/simulation目录下)

package com.bjpowernode.practice.simulation;
import com.bjpowernode.practice.annotation.Select;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
public class SQLSelectProxy implements InvocationHandler
{
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
 /**
 * 获得Mapper方法上的Select注解,以此来取得注解中的SQL语句
 */
 Select select = method.getAnnotation(Select.class);
 if (!method.isAnnotationPresent(Select.class))
 {
 throw new RuntimeException("缺少@Select注解!");
 }
 PreparedStatement pstmt = null;
 ResultSet rs = null;
 Object obj = null;
 try
 {
 pstmt = SqlSessionImpl.connection.prepareStatement(select.value());
 rs = pstmt.executeQuery();
 /**
 * 获得Method的返回对象类型,此处应当作判断处理,当List的时候,当只返回一个对象的时候.
 * 为了简单实现功能并与第一节中测试文件不发生冲突起见,此处当作List处理
 */
 String returnType = method.getGenericReturnType().toString();//java.util.List<com.bjpowernode.practice.User>
 if (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();
 }
 }
 return obj;
 }
} 

SqlSession.java Mybatis模拟接口(src/main/java/com/bjpowernode/practice/simulation目录下)

package com.bjpowernode.practice.simulation;
import java.util.List;
/**
 *
 * 模拟SqlSession
 *
 */
public interface SqlSession
{
 public <T> T getMapper(Class<T> clazz);
 public <E> List<E> selectList(String query) throws Exception;
} 

SqlSessionFactory.java Mybatis模拟类(src/main/java/com/bjpowernode/practice/simulation目录下)

package com.bjpowernode.practice.simulation;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
 *
 * 模拟SqlSessionFactory
 *
 */
public class SqlSessionFactory
{
 private InputStream configuration;
 public SqlSession openSession() throws IOException
 {
 SqlSessionImpl session = new SqlSessionImpl();
 loadConfigurations(session);
 return session;
 }
 /**
 *
 * 通过Dom4j读取配置文件信息
 *
 * @param session
 * @throws IOException
 */
 private void loadConfigurations(final SqlSessionImpl session) throws IOException
 {
 try
 {
 Document document = new SAXReader().read(configuration);
 Element root = document.getRootElement();
 List<Element> mappers = root.element("mappers").elements("mapper");
 for (Element mapper : mappers)
 {
 if (mapper.attribute("resource") != null)
 {
  session.setXmlSQLs(loadXMLConfiguration(mapper.attribute("resource").getText()));
 }
 if (mapper.attribute("class") != null)
 {
 }
 }
 }
 catch (Exception e)
 {
 System.out.println("读取配置文件错误!");
 }
 finally
 {
 configuration.close();
 }
 }
 /**
 *
 * 通过dom4j读取Mapper.xml中的信息
 *
 * @param resource
 * @return
 * @throws DocumentException
 * @throws IOException
 */
 private Map<String, Mapper> loadXMLConfiguration(String resource) throws DocumentException, IOException
 {
 Map<String, Mapper> map = new HashMap<String, Mapper>();
 InputStream is = null;
 try
 {
 is = this.getClass().getClassLoader().getResourceAsStream(resource);
 Document document = new SAXReader().read(is);
 Element root = document.getRootElement();
 if (root.getName().equalsIgnoreCase("mapper"))
 {
 String namespace = root.attribute("namespace").getText();
 for (Element select : (List<Element>) root.elements("select"))
 {
  Mapper mapperModel = new Mapper();
  mapperModel.setResultType(select.attribute("resultType").getText());
  mapperModel.setQuerySql(select.getText().trim());
  map.put(namespace + "." + select.attribute("id").getText(), mapperModel);
 }
 }
 }
 finally
 {
 is.close();
 }
 return map;
 }
 public InputStream getConfiguration()
 {
 return configuration;
 }
 public void setConfiguration(InputStream configuration)
 {
 this.configuration = configuration;
 }
} 

SqlSessionFactoryBuilder.java Mybatis模拟类(src/main/java/com/bjpowernode/practice/simulation目录下)

package com.bjpowernode.practice.simulation;
import java.io.InputStream;
/**
 *
 * 模拟SqlSessionFactoryBuilder
 *
 */
public class SqlSessionFactoryBuilder
{
 public SqlSessionFactory build(InputStream is)
 {
 SqlSessionFactory sessionFactory = new SqlSessionFactory();
 sessionFactory.setConfiguration(is);
 return sessionFactory;
 }
} 

SqlSessionImpl.java Mybatis模拟类(src/main/java/com/bjpowernode/practice/simulation目录下)

package com.bjpowernode.practice.simulation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 *
 * 模拟SqlSessionImpl
 *
 */
public class SqlSessionImpl implements SqlSession
{
 /** DB connection */
 public static Connection connection;
 private Map<String, Mapper> xmlSQLs;
 private List<String> annotationClasses;
 public SqlSessionImpl()
 {
 /**
 * driverString 和 connString 应该是从配置文件读取,这里简化了
 */
 final String driverString = "org.apache.derby.jdbc.ClientDriver";
 final String connString = "jdbc:derby://localhost:1527/bjpowernode;create=true";
 try
 {
 Class.forName(driverString);
 /** 获得DB连接 */
 connection = DriverManager.getConnection(connString);
 }
 catch (Exception e)
 {
 System.out.println("获取DBConnection出错!");
 }
 }
 /**
 * 基于Annotation的数据库操作
 *
 */
 @Override
 public <T> T getMapper(Class<T> clazz)
 {
 T clazzImpl =
 (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {clazz}, new SQLSelectProxy());
 return clazzImpl;
 }
 /**
 *
 * 基于XML的查询操作
 */
 @Override
 public <E> List<E> selectList(String query) throws Exception
 {
 PreparedStatement pstmt = null;
 ResultSet rs = null;
 try
 {
 /** 简单的PreparedStateme JDBC实现 */
 pstmt = connection.prepareStatement(xmlSQLs.get(query).getQuerySql());
 rs = pstmt.executeQuery();
 /** 执行查询操作 */
 return executeQuery(rs, xmlSQLs.get(query).getResultType());
 }
 finally
 {
 if (!rs.isClosed())
 {
 rs.close();
 }
 if (!pstmt.isClosed())
 {
 pstmt.close();
 }
 }
 }
 /**
 *
 * 执行查询操作,并将查询到的结果与配置中的ResultType根据变量名一一对应,通过反射调用Set方法注入各个变量的值
 *
 * @param rs
 * @param type
 * @return
 * @throws Exception
 */
 public static <E> List<E> executeQuery(ResultSet rs, String type) throws Exception
 {
 int count = rs.getMetaData().getColumnCount();
 List<String> columnNames = new ArrayList<String>();
 for (int i = 1; i <= count; i++)
 {
 columnNames.add(rs.getMetaData().getColumnName(i));
 }
 final List list = new ArrayList<Object>();
 while (rs.next())
 {
 Class modelClazz = Class.forName(type);
 Object obj = modelClazz.newInstance();
 for (Method setMethods : modelClazz.getMethods())
 {
 for (String columnName : columnNames)
 {
  if (setMethods.getName().equalsIgnoreCase("set" + columnName))
  {
  setMethods.invoke(obj, rs.getString(columnName));
  }
 }
 }
 list.add(obj);
 }
 return list;
 }
 public Map<String, Mapper> getXmlSQLs()
 {
 return xmlSQLs;
 }
 public void setXmlSQLs(Map<String, Mapper> xmlSQLs)
 {
 this.xmlSQLs = xmlSQLs;
 }
 public List<String> getAnnotationClasses()
 {
 return annotationClasses;
 }
 public void setAnnotationClasses(List<String> annotationClasses)
 {
 this.annotationClasses = annotationClasses;
 }
} 

UserMapper.xml 基于XML的Mapper配置文件(src/main/java/com/bjpowernode/practice/xml目录下)

<?xml version="1.0" encoding="UTF-8" ?>
 <!-- namespace 当基于XML进行配置的时候是根据namespace+id来拼接进行SQL操作 -->
<mapper namespace="com.bjpowernode.practice.UserMapper">
 <!-- select 查询 -->
 <select id="getUser" resultType="com.bjpowernode.practice.User">
 select *
 from USER_TEST_TB
 </select>
</mapper> 

TestMyBatis.java 测试类(src/test/java/com/bjpowernode/practice目录下)

package com.bjpowernode.practice;
import com.bjpowernode.practice.annotation.UserMapper;
import com.bjpowernode.practice.simulation.SqlSession;
import com.bjpowernode.practice.simulation.SqlSessionFactory;
import com.bjpowernode.practice.simulation.SqlSessionFactoryBuilder;
import com.bjpowernode.practice.simulation.SqlSessionImpl;
import java.io.InputStream;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestMyBatis
{
 /** 配置置文件 */
 private String source;
 private InputStream inputStream;
 private SqlSessionFactory sqlSessionFactory;
 @Before
 public void setUp()
 {
 source = "test-mybatis-configuration.xml";
 }
 /**
 *
 * 基于XML格式配置的测试方法
 *
 */
 @Test
 public void testXMLConfingure()
 {
 try
 {
 /**
 * 获得Session
 */
 inputStream = TestMyBatis.class.getClassLoader().getResourceAsStream(source);
 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
 SqlSession session = sqlSessionFactory.openSession();
 /**
 * 执行Query操作
 */
 List<User> users = (List) session.selectList("com.bjpowernode.practice.UserMapper.getUser");
 System.out.println("Query by XML configuration...");
 /**
 * 打印结果
 */
 this.printUsers(users);
 }
 catch (Exception e)
 {
 e.printStackTrace();
 }
 }
 /**
 *
 * 基于Annotation配置的测试方法
 *
 */
 @Test
 public void testAnnotationConfingure()
 {
 try
 {
 inputStream = TestMyBatis.class.getClassLoader().getResourceAsStream(source);
 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
 SqlSession session = sqlSessionFactory.openSession();
 UserMapper userMapper = session.getMapper(UserMapper.class);
 System.out.println("\r\nQuery by annotation configuration...");
 this.printUsers(userMapper.getUser());
 }
 catch (Exception e)
 {
 e.printStackTrace();
 }
 }
 @After
 public void clearUp() throws SQLException
 {
 if (SqlSessionImpl.connection != null && !SqlSessionImpl.connection.isClosed())
 {
 SqlSessionImpl.connection.close();
 }
 }
 private void printUsers(final List<User> users)
 {
 int count = 0;
 for (User user : users)
 {
 System.out.println(MessageFormat.format("==User[{0}]=================", ++count));
 System.out.println("User Id: " + user.getId());
 System.out.println("User UserName: " + user.getUsername());
 System.out.println("User Password: " + user.getPassword());
 System.out.println("User nickname: " + user.getNickname());
 }
 }
} 

以上就是基于XML以及Annotation的方式对Mybatis实现了一个简单的模拟。旨在理解Mybatis的工作原理。

笔者一直觉得当学习一个工具类技术的时候,路线应该是

1.实现一个小例子

2.找材料理解其中原理

3.学习技术细节,并动手全部实现

4.在全部学完之后动手做一个小项目,尽可能的使用这个在技术中的各个环节。

总结

以上所述是小编给大家介绍的模拟Mybatis的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • mybatis 插件: 打印 sql 及其执行时间实现方法

    Plugins 摘一段来自MyBatis官方文档的文字. MyBatis允许你在某一点拦截已映射语句执行的调用.默认情况下,MyBatis允许使用插件来拦截方法调用: Executor(update.query.flushStatements.commint.rollback.getTransaction.close.isClosed) ParameterHandler(getParameterObject.setParameters) ResultSetHandler(handleResult

  • 用Maven插件生成Mybatis代码的实现方法

    现在代码管理基本上是采用Maven管理,Maven的好处此处不多说,大家用百度搜索会有很多介绍,本文介绍一下用Maven工具如何生成Mybatis的代码及映射的文件. 一.配置Maven pom.xml 文件 在pom.xml增加以下插件: <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId>

  • MyBatis中insert操作返回主键的实现方法

    在使用MyBatis做持久层时,insert语句默认是不返回记录的主键值,而是返回插入的记录条数:如果业务层需要得到记录的主键时,可以通过配置的方式来完成这个功能 针对Sequence主键而言,在执行insert sql前必须指定一个主键值给要插入的记录,如Oracle.DB2,可以采用如下配置方式: <insert id="add" parameterType="vo.Category"> <selectKey resultType="

  • MyBatis Oracle 自增序列的实现方法

    mybatis oracle 自增序列的代码如下所示: <insert id=" insert " useGeneratedKeys="true" keyProperty="s_id" parameterType="xxxx" > <selectKey resultType="int" order="BEFORE" keyProperty="s_id"

  • Mybatis Generator自动生成对应文件的实现方法

    使用Generator自动生成我们需要的bean dao mapper xml等文件的过程(没有借助eclipse等编辑工具直接命令提示符生成) 第一步:在E盘新建一个文件夹generator,在这文件夹下创建一个test文件夹用来存放生成的文件,在创建一个generator.xml的配置文件 第二步:导入需要的jar包 mybatis-generator-core-1.3.2.jar 和mysql-connector-java-5.1.28-bin.jar 第三步:编写generator.xm

  • 模拟Mybatis的实现方法

    所需要用到的其他工具或技术: 项目管理工具 : Maven 测试运行工具 : Junit 数据库 : Derby XML操作工具:Dom4j 继续不废话 Maven Dependencies: <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> <scope>test</sc

  • Android编程实现获取标题栏、状态栏的高度、屏幕大小及模拟Home键的方法

    本文实例讲述了Android编程实现获取标题栏.状态栏的高度.屏幕大小及模拟Home键的方法.分享给大家供大家参考,具体如下: 1. 获取标题栏高度: /** * 获取标题栏的高度 * * @param activity * @return */ public int getTitleHeight(Activity activity) { Rect rect = new Rect(); Window window = activity.getWindow(); window.getDecorVi

  • Python模拟登录12306的方法

    本文实例讲述了Python模拟登录12306的方法.分享给大家供大家参考. 具体实现方法如下: 复制代码 代码如下: #!/usr/bin/python # -*- coding: utf-8 -*-   import re; import sys; import cookielib; import urllib; import urllib2; import optparse; import json; import httplib2; reload(sys) sys.setdefaulten

  • JavaScript模拟实现继承的方法

    本文实例讲述了JavaScript模拟实现继承的方法.分享给大家供大家参考.具体分析如下: 我们都知道,在JavaScript中只能模拟实现OO中的"类",也就意味着,在JavaScript中没有类的继承.我们也只能通过在原对象里添加或改写属性来模拟实现. 先定义一个父类, //父类 function ParentClass() { this.className = "ParentClass"; this.auth = "Auth"; this.

  • C#基于socket模拟http请求的方法

    本文实例讲述了C#基于socket模拟http请求的方法.分享给大家供大家参考.具体实现方法如下: using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; class HttpHelper { #region 模拟客户端socket连接

  • PHP模拟QQ登录的方法

    本文实例讲述了PHP模拟QQ登录的方法.分享给大家供大家参考.具体实现方法如下: 原理是用curl模拟发送post登录,cookie保存本地 这样理论上可以支持永久单挂QQ <?php //http://blog.qita.in 非技术[S.T] $qqno='你的QQ'; $qqpw='QQ密码'; $cookie = dirname(__FILE__).'/cookie.txt'; $post = array( 'login_url' => 'http://pt.3g.qq.com/s?s

  • JS实现窗口加载时模拟鼠标移动的方法

    本文实例讲述了JS实现窗口加载时模拟鼠标移动的方法.分享给大家供大家参考.具体实现方法如下: function judge(){ alert("mousemove"); document.onmousemove = null;//撤销鼠标移动模拟 } function simulateMouseMove(){//模拟鼠标移动 document.onmousemove = judge; } window.onload=simulateMouseMove;//窗口加载 希望本文所述对大家的

  • 基于MyBatis XML配置方法(全面了解)

    MyBatis 的配置文件包含了影响 MyBatis 行为甚深的设置(settings)和属性(properties)信息. 文档的顶层结构如下: configuration 配置 properties 属性 settings 设置 typeAliases 类型命名 typeHandlers 类型处理器 objectFactory 对象工厂 plugins 插件 environments 环境 environment 环境变量 transactionManager 事务管理器 dataSourc

  • jquery模拟进度条实现方法

    本文实例讲述了jquery模拟进度条实现方法.分享给大家供大家参考.具体如下: <!doctype html> <html> <head> <meta charset="utf-8"> <title>js模拟进度条练习</title> <script type='text/javascript' src="http://xiazai.jb51.net/201508/yuanma/jquery-1.8

  • mybatis generator 使用方法教程(生成带注释的实体类)

    引言: 最近的一个项目,由于数据库表巨多,导致需要创建N多个java实体.dao.mapper.xml映射文件,如果均使用纯手工编写,无疑需要耗费大量时间和精力.于是上网学习了mybatis generator的使用. 现在项目写完了,闲暇之余把干货奉上,供大家直接使用. 需求场景: 当你的java 项目数据库有N张表需要使用mybatis进行数据库操作时,建议使用mybatis generator 自动生成工具.可以自动帮助你生成java实体类.dao.mapper.xml等. 首先给大家分享

随机推荐