欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot中間件ORM框架實現(xiàn)案例詳解(Mybatis)

 更新時間:2023年07月26日 15:03:21   作者:看表該更新博客了  
這篇文章主要介紹了SpringBoot中間件ORM框架實現(xiàn)案例詳解(Mybatis),本篇文章提煉出mybatis最經(jīng)典、最精簡、最核心的代碼設計,來實現(xiàn)一個mini-mybatis,從而熟悉并掌握ORM框架的涉及實現(xiàn),需要的朋友可以參考下

源碼地址(已開源)https://gitee.com/sizhaohe/mini-mybatis.git 跟著源碼及下述UML圖來理解上手會更快,拒絕浮躁,沉下心來搞

定義:

ORM:Object Relational Mapping --> 對象關系映射,是一種程序設計技術,用于實現(xiàn)面向對象編程語言里面不同類型系統(tǒng)的數(shù)據(jù)之間的轉換

需求背景:

記不記得剛開始學JAVA時,編寫一大串JDBC相關代碼來進行與數(shù)據(jù)庫的交互,日后我們接觸到的MyBatis、MyBatisPlus等都是使用ORM組件來實現(xiàn)的框架。

本篇文章提煉出mybatis【最】經(jīng)典、【最】精簡、【最】核心的代碼設計,來實現(xiàn)一個【mini-mybatis】,從而熟悉并掌握ORM框架的涉及實現(xiàn)。

方案設計:

  • 中間的四部分處理是ORM框架的核心內容
  • 這個框架會提供出SqlSession工廠以及調用方式

代碼展示

UML圖

很重要,建議code前跟我一樣,先將類UML圖整理出來,整個類的依賴關系及代碼執(zhí)行流程會一目而然。

  • 以上為ORM框架實現(xiàn)核心類:加載mysql配置文件、對mapper-xml解析、獲取數(shù)據(jù)庫session、操作數(shù)據(jù)庫及封裝響應結果。

實現(xiàn)細節(jié)

1.定義sqlsession接口

對數(shù)據(jù)庫的定義和處理,本篇我們只封裝一個 T selectOne(Object param);

public interface SqlSession {
    <T> T selectOne(String statement, Object parameter);
    void close();
}

2.DefaultSqlSession(SqlSession的實現(xiàn))

使用rt.jar包下(java.lang.sql包下)

Connection接口(負責與數(shù)據(jù)庫進行連接)及PreparedStatement(執(zhí)行具體sql)接口來實現(xiàn)

public class DefaultSqlSession implements SqlSession{
    private Connection connection;
    private Map<String,XNode> mapperElement;
    public DefaultSqlSession(Connection connection, Map<String, XNode> mapperElement) {
        this.connection = connection;
        this.mapperElement = mapperElement;
    }
    @Override
    public <T> T selectOne(String statement, Object parameter) {
        XNode xNode = mapperElement.get(statement);
        Map<Integer, String> parameterMap = xNode.getParameter();
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql());
            buildParameter(preparedStatement, parameter, parameterMap);
            // SQL執(zhí)行結果集的行數(shù)據(jù)
            ResultSet resultSet = preparedStatement.executeQuery();
            List<T> objects = resultSet2Obj(resultSet, Class.forName(xNode.getResultType()));
            return objects.get(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    private <T> List<T> resultSet2Obj(ResultSet resultSet, Class<?> clazz) {
        List<T> list = new ArrayList<>();
        try {
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();
            // 每次遍歷行值
            while (resultSet.next()) {
                T obj = (T) clazz.newInstance();
                for (int i = 1; i <= columnCount; i++) {
                    Object value = resultSet.getObject(i);
                    String columnName = metaData.getColumnName(i);
                    String setMethod = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
                    Method method;
                    if (value instanceof Timestamp) {
                        method = clazz.getMethod(setMethod, Date.class);
                    } else {
                        method = clazz.getMethod(setMethod, value.getClass());
                    }
                    method.invoke(obj, value);
                }
                list.add(obj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }
    @Override
    public void close() {
        if (null == connection) return;
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    private void buildParameter(PreparedStatement preparedStatement, Object parameter, Map<Integer, String> parameterMap) throws SQLException, IllegalAccessException {
        int size = parameterMap.size();
        // 單個參數(shù)
        if (parameter instanceof Long) {
            for (int i = 1; i <= size; i++) {
                preparedStatement.setLong(i, Long.parseLong(parameter.toString()));
            }
            return;
        }else{
            // TODO 后面緊跟的章節(jié)繼續(xù)補充其他類型的入?yún)?
        }
    }
}

3.定義SqlSessionFactory接口

每次執(zhí)行一個SQL語句,應用程序都需要獲取一個SqlSession對象。SqlSession對象是執(zhí)行持久化操作的入口點,可以用于執(zhí)行SQL語句、刷新緩存、提交事務等操作。建議在使用完SqlSession后,及時關閉它來釋放資源。

public interface SqlSessionFactory {
    SqlSession openSession();
}

4.DefaultSqlSessionFactory(上述接口實現(xiàn)類)

構造方法中向下傳遞了Configuration配置文件

public class DefaultSqlSessionFactory implements SqlSessionFactory {
    private final Configuration configuration;
    public DefaultSqlSessionFactory(Configuration configuration) {
        this.configuration = configuration;
    }
    @Override
    public SqlSession openSession() {
        return new DefaultSqlSession(configuration.getConnection(), configuration.getMapperElement());
    }
}

5.SqlSessionFactoryBuilder

數(shù)據(jù)庫操作的核心類,負責解析Mapper文件(拿datasource,數(shù)據(jù)庫連接信息,mapper文件中sql的各個信息如id,入返參類型,sql)

public class SqlSessionFactoryBuilder {
    public DefaultSqlSessionFactory build(Reader reader) {
        SAXReader saxReader = new SAXReader();
        Document document = null;
        try {
            document = saxReader.read(new InputSource(reader));
            // 拿到根標簽元素
            Element rootElement = document.getRootElement();
            Configuration configuration = parseConfiguration(rootElement);
            return new DefaultSqlSessionFactory(configuration);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return null;
    }
    public Configuration parseConfiguration(Element rootElement) {
        Configuration configuration = new Configuration();
        configuration.setDataSource(dataSource(rootElement.selectNodes("http://dataSource")));
        configuration.setConnection(connection(configuration.getDataSource()));
        configuration.setMapperElement(mapperElement(rootElement.selectNodes("http://mappers")));
        return configuration;
    }
    private Map<String, String> dataSource(List<Element> list) {
        Map<String, String> dataSource = new HashMap<>(4);
        Element element = list.get(0);
        List content = element.content();
        for (Object o : content) {
            Element e = (Element) o;
            String name = e.attributeValue("name");
            String value = e.attributeValue("value");
            dataSource.put(name, value);
        }
        return dataSource;
    }
    private Connection connection(Map<String, String> dataSource) {
        try {
            return DriverManager.getConnection(dataSource.get("url"), dataSource.get("username"), dataSource.get("password"));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    private Map<String, XNode> mapperElement(List<Element> list) {
        Map<String, XNode> map = new HashMap<>();
        Element element = list.get(0);
        List content = element.content();
        try {
            for (Object o : content) {
                Element e = (Element) o;
                // 拿到mapper文件對應地址
                String resource = e.attributeValue("resource");
                Reader reader = Resources.getResourceAsReader(resource);
                SAXReader saxReader = new SAXReader();
                Document document = saxReader.read(new InputSource(reader));
                Element rootElement = document.getRootElement();
                String namespace = rootElement.attributeValue("namespace");
                List<Element> selectNodes = rootElement.selectNodes("select");
                for (Element ele : selectNodes) {
                    String id = ele.attributeValue("id");
                    String parameterType = ele.attributeValue("parameterType");
                    String resultType = ele.attributeValue("resultType");
                    String sql = ele.getText();
                    // ? 匹配
                    Map<Integer, String> parameter = new HashMap<>();
                    Pattern pattern = Pattern.compile("(#\\{(.*?)})");
                    Matcher matcher = pattern.matcher(sql);
                    for (int i = 1; matcher.find(); i++) {
                        String g1 = matcher.group(1);
                        String g2 = matcher.group(2);
                        parameter.put(i, g2);
                        sql = sql.replace(g1, "?");
                    }
                    XNode xNode = new XNode();
                    xNode.setId(id);
                    xNode.setNameSpace(namespace);
                    xNode.setParameterType(parameterType);
                    xNode.setResultType(resultType);
                    xNode.setSql(sql);
                    xNode.setParameter(parameter);
                    map.put(namespace + "." + id, xNode);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return map;
    }
}

測試驗證

建表

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` bigint(20) NOT NULL COMMENT '自增id',
  `userId` varchar(9) DEFAULT NULL COMMENT '用戶ID',
  `userNickName` varchar(32) DEFAULT NULL COMMENT '用戶昵稱',
  `userHead` varchar(255) DEFAULT NULL COMMENT '用戶頭像',
  `userPassword` varchar(255) DEFAULT NULL COMMENT '用戶密碼',
  `createTime` datetime DEFAULT NULL COMMENT '創(chuàng)建時間',
  `updateTime` datetime NOT NULL COMMENT '更新時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES (1, '001', 'xxx', '001', '123', '2023-07-14 17:33:55', '2023-07-14 17:33:58');
INSERT INTO `user` VALUES (2, '002', 'xxx2', '002', '123', '2023-07-14 17:33:55', '2023-07-14 17:33:58');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

定義POJO及DAO

@Data
public class User {
    private Long id;
    private String userId;          // 用戶ID
    private String userNickName;    // 昵稱
    private String userHead;        // 頭像
    private String userPassword;    // 密碼
    private Date createTime;        // 創(chuàng)建時間
    private Date updateTime;        // 更新時間
}
public interface IUserDao {
     User queryUserInfoById(Long id);
}

ORM配置文件--mybatis-config-datasource.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://172.17.1.245:3306/airticketbasedb?useUnicode=true"/>
                <property name="username" value="write"/>
                <property name="password" value="write123"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/User_Mapper.xml"/>
    </mappers>
</configuration>

Mapper配置

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.minimybatis.dao.IUserDao">
    <select id="queryUserInfoById" parameterType="java.lang.Long" resultType="com.example.minimybatis.po.User">
        SELECT id, userId, userNickName, userHead, userPassword, createTime
        FROM user
        where id = #{id}
    </select>
</mapper>

測試類

public class ApiTest {
    @Test
    public void test(){
        String resouce = "mybatis-config-datasource.xml";
        Reader reader;
        try{
            reader = Resources.getResourceAsReader(resouce);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            User user = sqlSession.selectOne(
                    "com.example.minimybatis.dao.IUserDao.queryUserInfoById",
                    1L);
            System.out.println(JSONObject.toJSONString(user));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

總結

比mybatis小很多,取其(mybaits)精華來達到掌握ORM框架的目的

到此這篇關于SpringBoot中間件ORM框架實現(xiàn)案例詳解(Mybatis)的文章就介紹到這了,更多相關SpringBoot中間件ORM內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot使用AOP記錄接口操作日志的方法

    SpringBoot使用AOP記錄接口操作日志的方法

    日志記錄量是很大的,所以只記錄關鍵地方并按期歸檔,最好是存在如elasticsearch中,如果存在數(shù)據(jù)庫中,分表是不錯的選擇,這篇文章主要介紹了SpringBoot使用AOP記錄接口操作日志的方法,需要的朋友可以參考下
    2022-08-08
  • Java語言資源國際化步驟解析

    Java語言資源國際化步驟解析

    這篇文章主要介紹了Java語言資源國際化步驟解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • Java中Flux類的使用方法和示例代碼

    Java中Flux類的使用方法和示例代碼

    在Java編程中Flux是一種處理響應式編程的庫,它提供了一種異步數(shù)據(jù)流處理的方式,這篇文章主要給大家介紹了關于Java中Flux類的使用方法和示例代碼,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-08-08
  • java synchronized 鎖機制原理詳解

    java synchronized 鎖機制原理詳解

    synchronized關鍵字是JAVA中常用的同步功能,提供了簡單易用的鎖功能。這篇文章主要介紹了Java中synchronized關鍵字引出的多種鎖問題,需要的朋友可以參考下
    2021-08-08
  • java httpclient設置超時時間和代理的方法

    java httpclient設置超時時間和代理的方法

    這篇文章主要介紹了java httpclient設置超時時間和代理的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • 用Java程序判斷是否是閏年的簡單實例

    用Java程序判斷是否是閏年的簡單實例

    下面小編就為大家?guī)硪黄肑ava程序判斷是否是閏年的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • 詳解spring自動掃描包

    詳解spring自動掃描包

    這篇文章主要介紹了spring自動掃描包的相關知識,本文通過實例相結合的形式給大家介紹的非常詳細,感興趣的朋友跟隨腳本之家小編一起看看吧
    2018-06-06
  • 一文搞懂Java的SPI機制(推薦)

    一文搞懂Java的SPI機制(推薦)

    Java定義了一套JDBC的接口,但并未提供具體實現(xiàn)類,而是在不同云廠商提供的數(shù)據(jù)庫實現(xiàn)包。這篇文章給大家介紹Java的SPI機制,感興趣的朋友一起看看吧
    2021-11-11
  • Java十大經(jīng)典排序算法圖解

    Java十大經(jīng)典排序算法圖解

    這篇文章主要介紹了Java十大經(jīng)典排序算法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-11-11
  • 實例分析Java Class的文件結構

    實例分析Java Class的文件結構

    今天把之前在Evernote中的筆記重新整理了一下,發(fā)上來供對java class 文件結構的有興趣的同學參考一下
    2013-04-04

最新評論