模拟Mybatis的实现方法

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

钟楼ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为成都创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:028-86922220(备注:SSL证书合作)期待与您的合作!

项目管理工具 : Maven

测试运行工具 : Junit

数据库 : Derby

XML操作工具:Dom4j

继续不废话

Maven Dependencies:

 
 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 建表及数据插入(如果在第一节中作过,可以跳过此步):

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" ?> 
 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
 

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 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 
 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 getMapper(Class clazz); 
 public  List 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 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 loadXMLConfiguration(String resource) throws DocumentException, IOException 
 { 
 Map map = new HashMap(); 
 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) 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 xmlSQLs; 
 private List 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 getMapper(Class clazz) 
 { 
 T clazzImpl = 
 (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {clazz}, new SQLSelectProxy()); 
 return clazzImpl; 
 } 
 /** 
 * 
 * 基于XML的查询操作 
 */ 
 @Override 
 public  List 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  List executeQuery(ResultSet rs, String type) throws Exception 
 { 
 int count = rs.getMetaData().getColumnCount(); 
 List columnNames = new ArrayList(); 
 for (int i = 1; i <= count; i++) 
 { 
 columnNames.add(rs.getMetaData().getColumnName(i)); 
 } 
 final List list = new ArrayList(); 
 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 getXmlSQLs() 
 { 
 return xmlSQLs; 
 } 
 public void setXmlSQLs(Map xmlSQLs) 
 { 
 this.xmlSQLs = xmlSQLs; 
 } 
 public List getAnnotationClasses() 
 { 
 return annotationClasses; 
 } 
 public void setAnnotationClasses(List annotationClasses) 
 { 
 this.annotationClasses = annotationClasses; 
 } 
} 

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

<?xml version="1.0" encoding="UTF-8" ?> 
  
 
  
  
 

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 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 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的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对创新互联网站的支持!


当前名称:模拟Mybatis的实现方法
转载来源:http://hbruida.cn/article/psepss.html