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

项目管理工具 : 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的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

02-08 16:22