模擬Mybatis的實現(xiàn)方法
所需要用到的其他工具或技術(shù):
項目管理工具 : Maven
測試運行工具 : 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對象類(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運行時 */
@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;
/**
*
* 存儲查詢結(jié)果對象
*
*/
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動態(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的返回對象類型,此處應(yīng)當(dāng)作判斷處理,當(dāng)List的時候,當(dāng)只返回一個對象的時候.
* 為了簡單實現(xiàn)功能并與第一節(jié)中測試文件不發(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
{
// 返回其他對象應(yīng)當(dāng)作其他處理,此處為了簡單起見,暫不處理
}
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讀?。停幔穑穑澹颍恚熘械男畔?
*
* @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)該是從配置文件讀取,這里簡化了
*/
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的數(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
{
/** 簡單的PreparedStateme JDBC實現(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ù)變量名一一對應(yīng),通過反射調(diào)用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 當(dāng)基于XML進行配置的時候是根據(jù)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();
/**
* 執(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配置的測試方法
*
*/
@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實現(xiàn)了一個簡單的模擬。旨在理解Mybatis的工作原理。
筆者一直覺得當(dāng)學(xué)習(xí)一個工具類技術(shù)的時候,路線應(yīng)該是
1.實現(xiàn)一個小例子
2.找材料理解其中原理
3.學(xué)習(xí)技術(shù)細節(jié),并動手全部實現(xiàn)
4.在全部學(xué)完之后動手做一個小項目,盡可能的使用這個在技術(shù)中的各個環(huán)節(jié)。
總結(jié)
以上所述是小編給大家介紹的模擬Mybatis的實現(xiàn)方法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
詳解java接口(interface)在不同JDK版本中的變化
這篇文章主要介紹了詳解java接口(interface)在不同JDK版本中的變化,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
SpringCloud之Feign代理,聲明式服務(wù)調(diào)用方式
這篇文章主要介紹了SpringCloud之Feign代理,聲明式服務(wù)調(diào)用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringMvc+Mybatis+Pagehelper分頁詳解
這篇文章主要介紹了SpringMvc+Mybatis+Pagehelper分頁詳解,非常不錯,具有參考借鑒價值,需要的朋友可以參考下的相關(guān)資料2017-01-01
springboot框架中如何整合mybatis框架思路詳解
這篇文章主要介紹了springboot框架中如何整合mybatis框架,本文通過示例圖文相結(jié)合給大家介紹的非常詳細,需要的朋友可以參考下2022-12-12
關(guān)于json序列化(javaBean轉(zhuǎn)Json的細節(jié)處理)
這篇文章主要介紹了關(guān)于json序列化(javaBean轉(zhuǎn)Json的細節(jié)處理),具有很好的參考價值,希望對大家有所幫助。2022-03-03
SpringBoot+SpringSecurity+jwt實現(xiàn)驗證
本文主要介紹了SpringBoot+SpringSecurity+jwt實現(xiàn)驗證,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

