主頁 > 後端開發 > 一文全了解Mybatis

一文全了解Mybatis

2023-05-23 08:08:56 後端開發

初步了解

總體架構設計

Mybatis 整體框架如下:

img

介面層

MyBatis 和資料庫的互動有兩種方式:

  • 使用傳統的 MyBatis 提供的 API;
  • 使用 Mapper 介面;
使用傳統的 MyBatis 提供的 API

這是傳統的傳遞 Statement Id 和查詢引數給 SqlSession 物件,使用 SqlSession 物件完成和資料庫的互動;MyBatis 提供了非常方便和簡單的 API,供用戶實作對資料庫的增刪改查資料操作,以及對資料庫連接資訊和 MyBatis 自身配置資訊的維護操作,

img

使用 Mapper 介面

MyBatis 將組態檔中的每一個<mapper> 節點抽象為一個 Mapper 介面,而這個介面中宣告的方法和跟<mapper> 節點中的<select|update|delete|insert> 節點項對應,即<select|update|delete|insert> 節點的 id 值為 Mapper 介面中的方法名稱,parameterType 值表示 Mapper 對應方法的入參型別,而 resultMap 值則對應了 Mapper 介面表示的回傳值型別或者回傳結果集的元素型別,

img

根據 MyBatis 的配置規范配置好后,通過 SqlSession.getMapper(XXXMapper.class)方法,MyBatis 會根據相應的介面宣告的方法資訊,通過動態代理機制生成一個 Mapper 實體,我們使用 Mapper 介面的某一個方法時,MyBatis 會根據這個方法的方法名和引數型別,確定 Statement Id,底層還是通過 SqlSession.select("statementId",parameterObject);或者 SqlSession.update("statementId",parameterObject); 等等來實作對資料庫的操作, MyBatis 參考 Mapper 介面這種呼叫方式,純粹是為了滿足面向介面編程的需要,(其實還有一個原因是在于,面向介面的編程,使得用戶在介面上可以使用注解來配置 SQL 陳述句,這樣就可以脫離 XML 組態檔,實作“0 配置”),

資料處理層

資料處理層可以說是 MyBatis 的核心,從大的方面上講,它要完成兩個功能:

  • 通過傳入引數構建動態 SQL 陳述句;
  • SQL 陳述句的執行以及封裝查詢結果集成List<E>
通過傳入引數構建動態 SQL 陳述句;

動態陳述句生成可以說是 MyBatis 框架非常優雅的一個設計,MyBatis 通過傳入的引數值,使用 Ognl 來動態地構造 SQL 陳述句,使得 MyBatis 有很強的靈活性和擴展性,

引數映射指的是對于 java 資料型別和 jdbc 資料型別之間的轉換:這里有包括兩個程序:查詢階段,我們要將 java 型別的資料,轉換成 jdbc 型別的資料,通過 preparedStatement.setXXX() 來設值;另一個就是對 resultset 查詢結果集的 jdbcType 資料轉換成 java 資料型別,

SQL 陳述句的執行以及封裝查詢結果集成List<E>

動態 SQL 陳述句生成之后,MyBatis 將執行 SQL 陳述句,并將可能回傳的結果集轉換成List<E> 串列,MyBatis 在對結果集的處理中,支持結果集關系一對多和多對一的轉換,并且有兩種支持方式,一種為嵌套查詢陳述句的查詢,還有一種是嵌套結果集的查詢,

框架支撐層
  • 事務管理機制

事務管理機制對于 ORM 框架而言是不可缺少的一部分,事務管理機制的質量也是考量一個 ORM 框架是否優秀的一個標準,

  • 連接池管理機制

由于創建一個資料庫連接所占用的資源比較大, 對于資料吞吐量大和訪問量非常大的應用而言,連接池的設計就顯得非常重要,

  • 快取機制

為了提高資料利用率和減小服務器和資料庫的壓力,MyBatis 會對于一些查詢提供會話級別的資料快取,會將對某一次查詢,放置到 SqlSession 中,在允許的時間間隔內,對于完全相同的查詢,MyBatis 會直接將快取結果回傳給用戶,而不用再到資料庫中查找,

  • SQL 陳述句的配置方式

傳統的 MyBatis 配置 SQL 陳述句方式就是使用 XML 檔案進行配置的,但是這種方式不能很好地支持面向介面編程的理念,為了支持面向介面的編程,MyBatis 引入了 Mapper 介面的概念,面向介面的引入,對使用注解來配置 SQL 陳述句成為可能,用戶只需要在介面上添加必要的注解即可,不用再去配置 XML 檔案了,但是,目前的 MyBatis 只是對注解配置 SQL 陳述句提供了有限的支持,某些高級功能還是要依賴 XML 組態檔配置 SQL 陳述句,

引導層

引導層是配置和啟動 MyBatis 配置資訊的方式,MyBatis 提供兩種方式來引導 MyBatis :基于 XML 組態檔的方式和基于 Java API 的方式,

主要構件及其相互關系

img

主要的核心部件解釋如下:

  • SqlSession 作為 MyBatis 作業的主要頂層 API,表示和資料庫互動的會話,完成必要資料庫增刪改查功能
  • Executor MyBatis 執行器,是 MyBatis 調度的核心,負責 SQL 陳述句的生成和查詢快取的維護
  • StatementHandler 封裝了 JDBC Statement 操作,負責對 JDBC statement 的操作,如設定引數、將 Statement 結果集轉換成 List 集合,
  • ParameterHandler 負責對用戶傳遞的引數轉換成 JDBC Statement 所需要的引數,
  • ResultSetHandler 負責將 JDBC 回傳的 ResultSet 結果集物件轉換成 List 型別的集合;
  • TypeHandler 負責 java 資料型別和 jdbc 資料型別之間的映射和轉換
  • MappedStatement MappedStatement 維護了一條<select|update|delete|insert>節點的封裝,
  • SqlSource 負責根據用戶傳遞的 parameterObject,動態地生成 SQL 陳述句,將資訊封裝到 BoundSql 物件中,并回傳
  • BoundSql 表示動態生成的 SQL 陳述句以及相應的引數資訊
  • Configuration MyBatis 所有的配置資訊都維持在 Configuration 物件之中,

流程簡解

準備

  1. /src/main/resources/mybatis-config.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>
    <properties>
        <property name="driver" value="https://www.cnblogs.com/jiuxialb/archive/2023/05/22/com.mysql.cj.jdbc.Driver"/>
        <property name="url"
                  value="https://www.cnblogs.com/jiuxialb/archive/2023/05/22/jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF8&useSSL=false&autoReconnect=true"/>
        <property name="username" value="https://www.cnblogs.com/jiuxialb/archive/2023/05/22/root"/>
        <property name="password" value="https://www.cnblogs.com/jiuxialb/archive/2023/05/22/123456"/>
    </properties>

    <!-- 環境,可以配置多個,default:指定采用哪個環境 -->
    <environments default="test">
        <environment id="test">
            <!-- 事務管理器,JDBC型別的事務管理器 -->
            <transactionManager type="JDBC"/>
            <!-- 資料源,池型別的資料源 -->
            <dataSource type="POOLED">
                <property name="driver" value="https://www.cnblogs.com/jiuxialb/archive/2023/05/22/${driver}"/> <!-- 配置了properties,所以可以直接參考 -->
                <property name="url" value="https://www.cnblogs.com/jiuxialb/archive/2023/05/22/${url}"/>
                <property name="username" value="https://www.cnblogs.com/jiuxialb/archive/2023/05/22/${username}"/>
                <property name="password" value="https://www.cnblogs.com/jiuxialb/archive/2023/05/22/${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="TeacherMapper.xml"/>
    </mappers>
</configuration>

  1. /src/main/resources/TeacherMapper.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:命名空間,隨便寫,一般保證命名空間唯一 -->
    <mapper namespace="TeacherMapper">
        <!-- statement,內容:sql陳述句,id:唯一標識,隨便寫,在同一個命名空間下保持唯一
           resultType:sql陳述句查詢結果集的封裝型別,tb_user即為資料庫中的表
         -->
        <select id="selectTest" resultType="org.apache.ibatis.test.Teacher">
            select *
            from teacher
            where id = #{id}
        </select>
    </mapper>
    
    
  2. /src/main/resources/log4j.properties

    log4j.rootLogger=DEBUG, stdout
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    
  3. /src/main/java/org/apache/ibatis/test/Teacher.java

    package org.apache.ibatis.test;
    
    
    public class Teacher {
        private Long id;
        private String name;
    
        public Long getId() {
            return id;
        }
     
        public void setId(Long id) {
            this.id = id;
        }
     
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
     
        @Override
        public String toString() {
            return "Teacher{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
    
  4. /src/main/java/org/apache/ibatis/test/Test.java

    package org.apache.ibatis.test;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            // 指定全域組態檔
            String resource = "mybatis-config.xml";
            // 讀取組態檔
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 構建sqlSessionFactory
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            // 獲取sqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 操作CRUD,第一個引數:指定statement,規則:命名空間+“.”+statementId
            // 第二個引數:指定傳入sql的引數:這里是用戶id
            Teacher test = sqlSession.selectOne("TeacherMapper.selectTest", 1);
            System.out.println(test.getName());
        }
    }
    

整體流程

<iframe id="embed_dom" name="embed_dom" frameborder="0" style="width: 100%; height: 300px" src="https://www.processon.com/embed/6462fcc6bb56a110e3ddb091"></iframe>
  1. 通過 mybatis-config.xml 進行初始化創建出 SqlSessionFactory,其內部是通過創建XMLConfigBuilder物件,然后自己進行決議 XML檔案,把檔案內容決議封裝為Configuration物件,最后由SqlSessionFactory進行封裝為SqlSessionFactory物件來完成SqlSessionFactory的創建,
  2. 通過SqlSessionFactory物件進行開啟一個SqlSession,其內部是通過獲取ConfigurationEnvironment資料進行構建TransactionFactory–>Executor,最后封裝為SqlSession回傳進行使用
  3. 通過SqlSession執行 XML 中對應的方法,其中是先通過statementXML 指定的類#方法名稱獲取MappedStatement物件,然后提交給Executor進行執行,

目錄詳解

exception

下圖是Mybatis中例外的關系圖:

image-20230522142059506

背景知識

  • 工廠模式
  • 例外的封裝

講解

工廠模式

public class ExceptionFactory {

    private ExceptionFactory() {
        // Prevent Instantiation
    }

    public static RuntimeException wrapException(String message, Exception e) {
        return new PersistenceException(ErrorContext.instance().message(message).cause(e).toString(), e);
    }

}
  • 私有建構式:導致該工廠無法創建出對應的物件
  • 靜態wrapException方法,用于通過例外資訊和例外型別進行封裝例外為Mybatis中的例外型別,全域通過ExceptionFactory.wrapException()進行生產出對應的例外物件

例外型別

  • IbatisException:Mybatis中最高的例外,但是直接繼承該類的子類只有PersistenceException,而且該類也添加了@Deprecated說明以后可能去除,

  • PersistenceException: 譯為持久化例外,Mybatis對應是持久化框架,后期可能該例外型別為Mybatis所有例外的父類,

  • TooManyResultsException:譯為多潭訓傳結果例外,用處為selectOne卻回傳多條記錄時所拋出的例外,

  • TypeException: 譯為型別例外,當 Mybatis 中需要型別轉化時,若轉換失敗則會拋出該例外,

  • CacheException: 譯為快取例外,當Mybatis讀取快取中資料出現問題時則會拋出該例外,

  • ParsingException: 譯為決議例外,當前代碼未看到使用,

  • ScriptingException: 譯為腳本例外,

  • ResultMapException: 譯為結果映射例外,在結果轉換為對應型別的物件時,若轉換失敗則會拋出例外,

  • DataSourceException: 譯為資料源例外,在初始化資料源時若出現錯誤則會拋出該例外,

  • TransactionException: 譯為事務例外,在給connection開啟事務時若失敗則會拋出該例外,

  • BuilderException: 譯為建造例外,在建造物件失敗時會拋出該例外,

  • SqlSessionException: 譯為SqlSession的例外,基本只會在SqlSessionManager中使用,主要是SqlSession使用程序中的例外,

  • ReflectionException: 譯為反射例外,基本只會在反射使用時會拋出該例外,

  • ExecutorException: 譯為執行器例外,會在執行緒操作資料庫的時候拋出該例外,

  • BatchExecutorException:譯為批量執行器例外,會在執行緒批量操作資料庫的時候拋出該例外,

  • BindingException: 譯為系結例外,主要是 mapper映射的時候會拋出該例外,

  • LogException: 譯為日志例外,目前只在LogFactory構建日志相關的時候才會拋出該例外,

  • PluginException: 譯為插件例外,目前只在Plugin中使用,在獲取插件資訊時候會拋出該例外,

Mybatis型別主要是根據業務相關包放在一起,所以命名絕大多數都能夠直觀的看到原因所在,

jdbc

背景知識

  • 模版模式
  • 易用性

講解

模版模式

某些類通用的一些處理方法一致,但是處理物件可能存在不同,此時可以使用模版方法,抽取父類撰寫通用處理方法,子類只需實作獲取物件的方法即可,

public class SQL extends AbstractSQL<SQL> {

    @Override
    public SQL getSelf() {
        return this;
    }

}
public abstract class AbstractSQL<T> {

    private static final String AND = ") \nAND (";
    private static final String OR = ") \nOR (";

    private final SQLStatement sql = new SQLStatement();

    public abstract T getSelf();

    public T UPDATE(String table) {
        sql().statementType = SQLStatement.StatementType.UPDATE;
        sql().tables.add(table);
        return getSelf();
    }

    public T SET(String sets) {
        sql().sets.add(sets);
        return getSelf();
    }
		......
}

以上代碼可知:

  1. 若用戶需要自定SQLExplainSQL,從而進行性能調優,此時只需要繼承 AbstractSQL即可,而無需撰寫原方法,
易用性

為了用戶使用方便和構建 SQL的直觀性,AbstractSQL命名采用了全大寫的模式,以此讓用戶更加易用,

image-20230522152141832

SqlRunner
    public int insert(String sql, Object... args) throws SQLException {
        PreparedStatement ps;
        if (useGeneratedKeySupport) {
            ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        } else {
            ps = connection.prepareStatement(sql);
        }

        try {
            setParameters(ps, args);
            ps.executeUpdate();
            if (useGeneratedKeySupport) {
                List<Map<String, Object>> keys = getResults(ps.getGeneratedKeys());
                if (keys.size() == 1) {
                    Map<String, Object> key = keys.get(0);
                    Iterator<Object> i = key.values().iterator();
                    if (i.hasNext()) {
                        Object genkey = i.next();
                        if (genkey != null) {
                            try {
                                return Integer.parseInt(genkey.toString());
                            } catch (NumberFormatException e) {
                                //ignore, no numeric key support
                            }
                        }
                    }
                }
            }
            return NO_GENERATED_KEY;
        } finally {
            try {
                ps.close();
            } catch (SQLException e) {
                //ignore
            }
        }
    }

    public int update(String sql, Object... args) throws SQLException {
        PreparedStatement ps = connection.prepareStatement(sql);
        try {
            setParameters(ps, args);
            return ps.executeUpdate();
        } finally {
            try {
                ps.close();
            } catch (SQLException e) {
                //ignore
            }
        }
    }

此類在Mybatis中沒有任何的使用,此類應該只是為了提供給用戶,讓用戶可以自定義執行相關 SQL,分析其方法本質為原始JDBC相關操作流程,

ScriptRunner
   private void executeFullScript(Reader reader) {
        StringBuilder script = new StringBuilder();
        try {
            BufferedReader lineReader = new BufferedReader(reader);
            String line;
            while ((line = lineReader.readLine()) != null) {
                script.append(line);
                script.append(LINE_SEPARATOR);
            }
            String command = script.toString();
            println(command);
            executeStatement(command);
            commitConnection();
        } catch (Exception e) {
            String message = "Error executing: " + script + ".  Cause: " + e;
            printlnError(message);
            throw new RuntimeSqlException(message, e);
        }
    }

    private void executeLineByLine(Reader reader) {
        StringBuilder command = new StringBuilder();
        try {
            BufferedReader lineReader = new BufferedReader(reader);
            String line;
            while ((line = lineReader.readLine()) != null) {
                handleLine(command, line);
            }
            commitConnection();
            checkForMissingLineTerminator(command);
        } catch (Exception e) {
            String message = "Error executing: " + command + ".  Cause: " + e;
            printlnError(message);
            throw new RuntimeSqlException(message, e);
        }
    }
    private void handleLine(StringBuilder command, String line) throws SQLException {
        String trimmedLine = line.trim();
        if (lineIsComment(trimmedLine)) {
            Matcher matcher = DELIMITER_PATTERN.matcher(trimmedLine);
            if (matcher.find()) {
                delimiter = matcher.group(5);
            }
            println(trimmedLine);
        } else if (commandReadyToExecute(trimmedLine)) {
            command.append(line.substring(0, line.lastIndexOf(delimiter)));
            command.append(LINE_SEPARATOR);
            println(command);
            executeStatement(command.toString());
            command.setLength(0);
        } else if (trimmedLine.length() > 0) {
            command.append(line);
            command.append(LINE_SEPARATOR);
        }
    }

此類的核心方法如上,可看出其本質和SqlRunner類一致,

datasource

背景知識

講解

transaction

背景知識

講解

cursor

背景知識

講解

io

背景知識

講解

reflection

背景知識

講解

logging

背景知識

講解

scripting

背景知識

講解

type

背景知識

講解

mapping

背景知識

講解

builder

背景知識

講解

parsing

背景知識

講解

binding

背景知識

講解

annotationslang

背景知識

講解

cache

背景知識

講解

plugin

背景知識

講解

session

背景知識

講解

流程詳解

總結

生活在失去所有的希望和期盼,才能一直做出納什均衡解

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/553067.html

標籤:其他

上一篇:Java基礎學習:尚硅谷 面向物件進階 客戶資訊管理軟體

下一篇:返回列表

標籤雲
其他(159453) Python(38162) JavaScript(25441) Java(18096) C(15230) 區塊鏈(8267) C#(7972) AI(7469) 爪哇(7425) MySQL(7204) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5871) 数组(5741) R(5409) Linux(5340) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4574) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2433) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1975) 功能(1967) Web開發(1951) HtmlCss(1940) C++(1919) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1878) .NETCore(1861) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • 一文全了解Mybatis

    ## 初步了解 ### 總體架構設計 Mybatis 整體框架如下: ![img](https://zhangjiahao-blog.oss-cn-beijing.aliyuncs.com/picgo/202305161021323.png) ##### 介面層 MyBatis 和資料庫的互動有兩種 ......

    uj5u.com 2023-05-23 08:08:56 more
  • Java基礎學習:尚硅谷 面向物件進階 客戶資訊管理軟體

    ### 1. Customer.java ``` package chapter07.pinExer; // 客戶類 public class Customer { private String name; private char gender; //性別 private int age; pri ......

    uj5u.com 2023-05-23 08:08:46 more
  • freemodbus移植進STM32(包含HAL庫和標準庫兩種方法)

    #freemodbus移植 >基于freemodbus1.6 >使用HAL庫 >軟體:stm32cubemx stm32cubeide >>后續會更新標準庫的移植。以及rtos下的移植(盡量) ##下載freemodbus1.6 這個獲取方法網上到處都是,不細說了。 ##cubemx新建工程 新建工 ......

    uj5u.com 2023-05-23 08:08:17 more
  • MyBatis-Plus 可視化代碼生成器來啦,讓你的開發效率大大提速!!

    ## **前言** 在基于Mybatis的開發模式中,很多開發者還會選擇Mybatis-Plus來輔助功能開發,以此提高開發的效率。雖然Mybatis也有代碼生成的工具,但Mybatis-Plus由于在Mybatis基礎上做了一些調整,因此,常規的生成工具生成的代碼還有一些不太符合預期。而且對于多數 ......

    uj5u.com 2023-05-23 08:07:35 more
  • django 計算兩個TimeField的時差

    在 Django 中,你可以使用 datetime 模塊來計算兩個 TimeField 欄位的時間差。以下是一個示例: from datetime import datetime, timedelta # 假設有兩個 TimeField 欄位 time1 = obj.time_field1 time ......

    uj5u.com 2023-05-23 08:07:19 more
  • 【Java】參考傳遞?值傳遞?

    參考傳遞和值傳遞,從上學那會兒就開始強調的概念,不管你是計算機相關專業還是自學Java,一定聽過這么一句話: 方法呼叫引數如果是物件,那就是參考傳遞,如果是基本資料型別,就是值傳遞。 比如:function(Object o)就是參考傳遞,function(int i)就是值傳遞。這兩個概念似乎很好 ......

    uj5u.com 2023-05-23 08:07:13 more
  • Java入門9(HashSet,File檔案類)

    ## HashSet 1. jdk1.7之前,使用陣列加鏈表的方式實作 2. jdk1.8之后,在鏈表長度大于8并且陣列長度超過32的情況下,會轉成紅黑樹結構 3. HashSet的本質是一個HashMap,它所有的value都是一致的,傳入的引數作為key,因此HashSet中不允許重復資料 4. ......

    uj5u.com 2023-05-23 08:06:47 more
  • java 外殼加密,完美解決

    圣天諾LDK加密鎖(加密狗),對war包加密的測驗,測驗war包(或jar包)防止被反編譯的效果。 http://chinadlp.com/?list-DriveDownload.html 下載最新開發套件:Sentinel HASP/LDK9.0開發套件。完全默認安裝。 如果是有主鎖的正式用戶請導 ......

    uj5u.com 2023-05-23 08:06:25 more
  • Java使用HttpClient以multipart/form-data向介面上傳檔案

    ## 前言 對接某公司的介面,涉及到資質上傳等業務。需要對接他們的上傳附件介面。 JDK1.8 httpclient 4.x ## 封裝httpclient方法 ```java public static String postFileMultiPart(String url,Map reqPara ......

    uj5u.com 2023-05-23 08:06:11 more
  • Java集合中Set都有哪些特性?看這篇就夠了!

    **本文將為大家詳細講解Java中的,這是我們進行開發時經常用到的知識點,也是大家在學習Java中很重要的一個知識點,更是我們在面試時有可能會問到的問題。** **文章較長,干貨滿滿,建議大家收藏慢慢學習。文末有本文重點總結,主頁有全系列文章分享。技術類問題,歡迎大家和我們一起交流討論!** ### ......

    uj5u.com 2023-05-23 08:06:07 more