溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

模擬Mybatis的實(shí)現(xiàn)方法

發(fā)布時(shí)間:2020-08-25 13:24:36 來源:腳本之家 閱讀:194 作者:動(dòng)力節(jié)點(diǎn) 欄目:編程語言

所需要用到的其他工具或技術(shù):

項(xiàng)目管理工具 : Maven

測(cè)試運(yùn)行工具 : Junit

數(shù)據(jù)庫 : Derby

XML操作工具:Dom4j

繼續(xù)不廢話

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 建表及數(shù)據(jù)插入(如果在第一節(jié)中作過,可以跳過此步):

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對(duì)象類(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; 
/** 標(biāo)注此注解只能用在方法上 */ 
@Target(ElementType.METHOD) 
/** 標(biāo)注此注解生命周期是在Runtime運(yùn)行時(shí) */ 
@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 對(duì)象類(src/main/java/com/bjpowernode/practice/simulation目錄下)

package com.bjpowernode.practice.simulation; 
/** 
 * 
 * 存儲(chǔ)查詢結(jié)果對(duì)象 
 * 
 */ 
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動(dòng)態(tài)代理類(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的返回對(duì)象類型,此處應(yīng)當(dāng)作判斷處理,當(dāng)List的時(shí)候,當(dāng)只返回一個(gè)對(duì)象的時(shí)候. 
 * 為了簡(jiǎn)單實(shí)現(xiàn)功能并與第一節(jié)中測(cè)試文件不發(fā)生沖突起見,此處當(dāng)作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 
 { 
 // 返回其他對(duì)象應(yīng)當(dāng)作其他處理,此處為了簡(jiǎn)單起見,暫不處理 
 } 
 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("讀取配置文件錯(cuò)誤!"); 
 } 
 finally 
 { 
 configuration.close(); 
 } 
 } 
 /** 
 * 
 * 通過dom4j讀?。停幔穑穑澹颍恚熘械男畔?
 * 
 * @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 應(yīng)該是從配置文件讀取,這里簡(jiǎn)化了 
 */ 
 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出錯(cuò)!"); 
 } 
 } 
 /** 
 * 基于Annotation的數(shù)據(jù)庫操作 
 * 
 */ 
 @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 
 { 
 /** 簡(jiǎn)單的PreparedStateme JDBC實(shí)現(xiàn) */ 
 pstmt = connection.prepareStatement(xmlSQLs.get(query).getQuerySql()); 
 rs = pstmt.executeQuery(); 
 /** 執(zhí)行查詢操作 */ 
 return executeQuery(rs, xmlSQLs.get(query).getResultType()); 
 } 
 finally 
 { 
 if (!rs.isClosed()) 
 { 
 rs.close(); 
 } 
 if (!pstmt.isClosed()) 
 { 
 pstmt.close(); 
 } 
 } 
 } 
 /** 
 * 
 * 執(zhí)行查詢操作,并將查詢到的結(jié)果與配置中的ResultType根據(jù)變量名一一對(duì)應(yīng),通過反射調(diào)用Set方法注入各個(gè)變量的值 
 * 
 * @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 當(dāng)基于XML進(jìn)行配置的時(shí)候是根據(jù)namespace+id來拼接進(jìn)行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 測(cè)試類(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格式配置的測(cè)試方法 
 * 
 */ 
 @Test 
 public void testXMLConfingure() 
 { 
 try 
 { 
 /** 
 * 獲得Session 
 */ 
 inputStream = TestMyBatis.class.getClassLoader().getResourceAsStream(source); 
 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 
 SqlSession session = sqlSessionFactory.openSession(); 
 /** 
 * 執(zhí)行Query操作 
 */ 
 List<User> users = (List) session.selectList("com.bjpowernode.practice.UserMapper.getUser"); 
 System.out.println("Query by XML configuration..."); 
 /** 
 * 打印結(jié)果 
 */ 
 this.printUsers(users); 
 } 
 catch (Exception e) 
 { 
 e.printStackTrace(); 
 } 
 } 
 /** 
 * 
 * 基于Annotation配置的測(cè)試方法 
 * 
 */ 
 @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的方式對(duì)Mybatis實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的模擬。旨在理解Mybatis的工作原理。

筆者一直覺得當(dāng)學(xué)習(xí)一個(gè)工具類技術(shù)的時(shí)候,路線應(yīng)該是

1.實(shí)現(xiàn)一個(gè)小例子

2.找材料理解其中原理

3.學(xué)習(xí)技術(shù)細(xì)節(jié),并動(dòng)手全部實(shí)現(xiàn)

4.在全部學(xué)完之后動(dòng)手做一個(gè)小項(xiàng)目,盡可能的使用這個(gè)在技術(shù)中的各個(gè)環(huán)節(jié)。

總結(jié)

以上所述是小編給大家介紹的模擬Mybatis的實(shí)現(xiàn)方法,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)億速云網(wǎng)站的支持!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI