Mybatis小白入門

来源:https://www.cnblogs.com/wutong666/archive/2023/08/23/17650699.html
-Advertisement-
Play Games

# Mybatis-9.28 環境: - JDK:1.8 - Mysql:8.032 - maven:3.9.2 - IDEA 回顧: - JDBC - Mysql - JavaSE - Maven - Junit ## 01 簡介 ### 1.1 什麼是MyBatis ![](https://im ...


Mybatis-9.28

環境:

  • JDK:1.8
  • Mysql:8.032
  • maven:3.9.2
  • IDEA

回顧:

  • JDBC
  • Mysql
  • JavaSE
  • Maven
  • Junit

01 簡介

1.1 什麼是MyBatis

  • MyBatis 是一款優秀的持久層框架。
  • 它支持自定義 SQL、存儲過程以及高級映射。
  • MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數和獲取結果集的工作。
  • MyBatis 可以通過簡單的 XML 或註解來配置和映射原始類型、介面和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為資料庫中的記錄。

如何獲得Mybatis?

  • maven倉庫:
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.13</version>
</dependency>

1.2 持久化

數據持久化

  • 持久化就是將程式的數據在持久狀態和瞬時狀態轉化的過程

  • 記憶體:斷電即失

  • 資料庫(jdbc),io文件持久化。

為什麼需要持久化?

  • 有一些對象,不能讓他丟掉。

  • 記憶體太貴了

1.3 持久層

Dao層 Service層 Controller層。。。

  • 幫助程式員將數據存入資料庫中
  • 方便
  • 傳統的JDBC太複雜了。簡化、框架、自動化。
  • 不用Mybatis也可以。但更容易上手。
  • 優點:
    • 簡單易學
    • 靈活
    • sql和代碼的分離,提高了可維護性。
    • 提供映射標簽,支持對象與資料庫的ORM欄位關係映射。
    • 提供對象關係映射標簽,支持對象關係組建維護。
    • 提供xml標簽,支持編寫動態sql。

02 第一個Mybatis程式

思路:搭建環境-->導入Mybatis-->編寫代碼-->測試

2.1 搭建環境

  • 搭建資料庫

  • 新建項目

    • 新建一個普通maven項目
    • 刪除src目錄,使該項目成為父工程
    • 導入maven依賴
     <dependencies>
            <!--資料庫連接-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.31</version>
            </dependency>
            <!--mybatis-->
            <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.13</version>
            </dependency>
            <!--junit測試包-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13.2</version>
            </dependency>
        </dependencies>
    

2.2 創建一個模版

  • 編寫mybatis核心配置文件

    • 記住修改driver、url、username和password
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "https://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
      <environments default="development">
        <environment id="development">
          <transactionManager type="JDBC"/>
          <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
          </dataSource>
        </environment>
      </environments>
      <mappers>
        <mapper resource="你自己配置的xml文件路徑"/>
      </mappers>
    </configuration>
    
  • 編寫mybatis工具類

        /*提升對象作用域*/
        private static SqlSessionFactory sqlSessionFactory;
    
        static{
            try {
                //使用mybatis第一步,獲取sqlSessionFactory對象
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
    
        //既然有了SqlSessionFactory,顧名思義,我們就可以從中獲得SqlSession的實例了。
        //SqlSession完全包含了面向資料庫執行SQL命令所需的全部方法。
    
        public static SqlSession getsqlSession(){
            return sqlSessionFactory.openSession();
        }
    
    

2.3 編寫代碼

  • 實體類(註意和資料庫表保持一致)

     private int id;
    
        private String name;
    
        private String pwd;
    
        private Date createTime;
    
        private Date modifyTime;
    
        public User() {
    
        }
    
        public User(int id, String name, String pwd, Date createTime, Date modifyTime) {
            this.id = id;
            this.name = name;
            this.pwd = pwd;
            this.createTime = createTime;
            this.modifyTime = modifyTime;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPwd() {
            return pwd;
        }
    
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
    
        public Date getCreateTime() {
            return createTime;
        }
    
        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    
        public Date getModifyTime() {
            return modifyTime;
        }
    
        public void setModifyTime(Date modifyTime) {
            this.modifyTime = modifyTime;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", pwd='" + pwd + '\'' +
                    ", createTime=" + createTime +
                    ", modifyTime=" + modifyTime +
                    '}';
        }
    
  • Dao介面

     List<User> getUserList();
    
  • Dao介面實現類由原來的UserDaoImpl轉變為一個Mapper配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <!--綁定一個對應的Dao/Mappper介面-->
    <mapper namespace="com.wu.dao.UserDao">
        <!--select查詢語句-->
        <select id="getUserList" resultType="com.wu.pojo.User">
            select * from mybatis.user
        </select>
    </mapper>
    

2.4 測試

註意點!!!!

首先需要註意一個需要修改的地方,即2.2創建模版中有一處需要配置自己xml地址的地方,在正式運行前需要更改文件路徑。路徑格式為:

<mapper resource="org/mybatis/example/BlogMapper.xml"/>

在test中編寫測試類方法:

    public void test(){

        //第一步:獲得SqlSession對象
        SqlSession sqlSession = MybatisUtils.getsqlSession();
        //執行SQL
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.getUserList();

        for (User user:userList){
            System.out.println(user);
        }
        //關閉SqlSession
        sqlSession.close();

    }

常見易錯問題:

1、配置文件沒有註冊

2、綁定介面有問題

3、方法名不對

4、返回類型不對

5、Maven導出資源問題

補充:作用域和生命周期

  • SqlSessionFactoryBuilder

    • 這個類可以被實例化、使用和丟棄,一旦創建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 實例的最佳作用域是方法作用域(也就是局部方法變數)。 你可以重用 SqlSessionFactoryBuilder 來創建多個 SqlSessionFactory 實例,但最好還是不要一直保留著它,以保證所有的 XML 解析資源可以被釋放給更重要的事情。
  • SqlSessionFactory

    • SqlSessionFactory一旦被創建就應該在應用的運行期間一直存在,沒有任何理由丟棄它或重新創建另一個實例。 使用 SqlSessionFactory 的最佳實踐是在應用運行期間不要重覆創建多次,多次重建 SqlSessionFactory 被視為一種代碼“壞習慣”。因此 SqlSessionFactory 的最佳作用域是應用作用域。 有很多方法可以做到,最簡單的就是使用單例模式或者靜態單例模式。
  • SqlSession

    • 每個線程都應該有它自己的SqlSession實例。SqlSession的的實例不是線程安全的,因此是不能被共用的,所以它的最佳的作用域是請求或方法作用域。 絕對不能將 SqlSession 實例的引用放在一個類的靜態域,甚至一個類的實例變數也不行。 也絕不能將 SqlSession 實例的引用放在任何類型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你現在正在使用一種 Web 框架,考慮將 SqlSession 放在一個和 HTTP 請求相似的作用域中。 換句話說,每次收到 HTTP 請求,就可以打開一個SqlSession,返回一個響應後,就關閉它。 這個關閉操作很重要,為了確保每次都能執行關閉操作,你應該把這個關閉操作放到 finally 塊中。

03 CRUD

3.1 Select

  • 選擇,查詢語句
    • id:就是對應的namespace中的方法名;
    • resultType:Sql語句執行的返回值
    • parameterType:傳入的參數類型

註意:增刪改需要提交事務!!

3.2-3.4 Insert Update Delete(暫缺,後續補齊)

3.5 分析錯誤

  • 標簽註意不要配錯
  • resource綁定mapper,需要使用路徑(需要註意resource地址採取“/”和mapper中關於parameterType的配置採取“.”)
  • 程式的配置文件必須符合規範
  • NullPointerException,沒有註冊到資源!
  • 輸出的xml文件中存在中文亂碼問題!
  • maven資源節點導出問題!

3.6 Map和模糊查詢

3.6.1 Map

假設,實體類或者資料庫中的表,欄位或者參數過多,應當考慮使用Map!(主要在修改update類型中使用)

int addUserByMap(Map<String, Object> map);
 <insert id="addUserByMap" parameterType="map">
        insert into mybatis.user values(#{id},#{name},#{pwd},#{createTime},#{modifyTime});
 </insert>
@Test
    public void test6(){
        SqlSession sqlSession = MybatisUtils.getsqlSession();

        UserMapper map = sqlSession.getMapper(UserMapper.class);
        Map<String, Object> user = new HashMap<String,Object>();
        user.put("id",4);
        user.put("name","liutianbo");
        user.put("pwd","666666");
        user.put("createTime",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date().getTime()));
        int i = map.addUserByMap(user);
        if(i>0){
            sqlSession.commit();
            System.out.println("添加成功,影響"+i+"行");
        }
        sqlSession.close();
    }

Map傳遞參數,直接在sql中取出key即可!【parameterType="map"】

對象傳遞參數,直接在sql中取對象的屬性即可!【parameterType="Object"】

只有一個基本類型參數的情況下,可以直接在sql中取到(即無須定義傳入參數類型)

多個參數用Map,或者註解!

3.6.2 模糊查詢

模糊查詢怎麼寫?

1、Java代碼執行的時候,傳遞通配符%%

List<User> userList = mapper.getLikeUser("%張%");

2、在sql拼接中使用通配符!

select * from mybatis.user where name like "%"#{value}"%"
  • 但需要註意的是,在sql拼接種可能會帶來sql註入問題,可能會給系統帶來一些安全性問題

04 配置解析

4.1 核心配置文件

  • mybatis-config.xml
  • MyBatis的配置文件包含了會深深影響Mybatis新聞的設置和屬性信息

4.2 環境配置(Enviroments)

  • MyBatis 可以配置成適應多種環境

  • 不過要記住:儘管可以配置多個環境,但每個 SqlSessionFactory 實例只能選擇一種環境。

  • Mybatis的預設事務管理器就是JDBC,連接池:POOLED

4.3 屬性(properties)

我們可以通過properties屬性來實現引用配置文件。

這些屬性都是可外部配置且可動態替換的,既可以在典型的Java屬性文件中配置,亦可通過properties元素的子元素來傳遞。【db.properties】

編寫一個配置文件

db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username = root
password = 12345

在核心配置文件中引入,但需要註意

    <!--引入外部配置文件-->
    <properties resource="db.properties"></properties>
  • 可以直接引入外部文件
  • 可以在xml中增加一些屬性配置
  • 如果外部文件和xml中有對同一個欄位進行配置,優先使用外部配置文件的!

4.4 類型別名(typeAliases)

  • 類型別名可為 Java 類型設置一個縮寫名字。

  • 它僅用於 XML 配置,意在降低冗餘的全限定類名書寫。

        <typeAliases>
            <typeAlias alias="User" type="com.wu.pojo.User"/>
        </typeAliases>
    
  • 也可以指定一個包名,Mybatis會在包名下麵搜索需要的Java Bean,然後使用 Bean 的首字母小寫的非限定類名來作為它的別名,或者直接使用註解作為其別名

        <typeAliases>
            <!--<typeAlias alias="User" type="com.wu.pojo.User"/>-->
            <package name="com.wu.pojo"/>
        </typeAliases>
    

    在實體類比較少的時候,使用第一種方式。

    如果實體類十分多,建議使用第二種方式。

    第一種可以自定義別名;第二種則不行,除非使用@Alias註解,例如:

    @Alias("user")
    public class User{
        
    }
    

4.5 設置(Settings)

這是 MyBatis 中極為重要的調整設置,它們會改變 MyBatis 的運行時行為。

比較重要的設置:

4.6 其他設置

  • typeHandlers(類型處理器)
  • objectFactory(對象工廠)
  • plugins插件
    • mybatis-generator-core
    • mybatis-plus
    • 通用mapper

4.7 映射器(mappers)

MapperRegistry:註冊綁定我們的Mapper文件;

方式一:使用相對於類路徑的資源引用

 <!--每一個Mapper.xml都需要在Mybatis核心配置文件中註冊!-->
 <mappers>
       <!-- <mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
        <mapper resource="com/wu/dao/UserMapper.xml"/>
 </mappers>

方式二:使用完全限定資源定位符(URL)

    <!--每一個Mapper.xml都需要在Mybatis核心配置文件中註冊!-->
    <mappers>
        <!--<mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
        <!--<mapper resource="com/wu/dao/UserMapper.xml"/>-->
        <mapper class="com.wu.dao.UserMapper"></mapper>
    </mappers>

方式三:將包內的映射器介面全部註冊為映射器

    <!--每一個Mapper.xml都需要在Mybatis核心配置文件中註冊!-->
    <mappers>
        <!--<mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
        <!--<mapper resource="com/wu/dao/UserMapper.xml"/>-->
        <!--<mapper class="com.wu.dao.UserMapper"></mapper>-->
        <package name="com.wu.dao"/>
    </mappers>

但需要註意的是,方式二和方式三有兩個需要註意的地方:

  • Interface類文件必須和成對的Mapper配置文件同名
  • Interface文件和它配對的Mapper文件必須在同一個包下

4.8 生命周期和作用域

生命周期和作用域,是指關重要的,因為錯誤的使用會導致非常嚴重的併發問題

SqlSessionFactoryBuilder

  • 一旦創建了SqlSessionFactoryBuilder,就不再需要;
  • 因此作為局部變數

SqlSessionFactory:

  • 可以想象為資料庫連接池
  • SqlSessionFactory一旦被創建就應該在應用的運行期間一直存在,沒有任何理由丟棄她或重新創建另一個實例。

05 ResultMap結果集映射

5.1 問題

前面所述實體類的各個屬性名稱和資料庫欄位是一一對應的,因此輸出的結果都是正常的。

如果對應不上會發生什麼?比如將pwd改成password?

結果很明顯,這個欄位的信息讀不出來。

回看一下mapper中編寫的sql語句

 select * from mybatis.user

實際上星號部分省略了

 select id,name,pwd,createtime,modifytime from mybatis.user

因此,這個欄位名取出後進行映射時自然找不到password名的欄位。

5.2 解決方法一(修改sql語句)

解決這個問題有兩種常見方法,第一種就是修改語句,給資料庫欄位pwd取別名。

select id,name,pwd as password,createtime,modifytime from mybatis.user

運行後發現,確實可以取出來:

但這個方法並不好,原因在於如果sql語句較多,就需要每一個都配置相關的別名,會極大增加工作量。

5.3 解決方法二(使用ResultMap映射集)

在Mapper文件中配置resultMap(註意各個部分的順序問題!)

   <resultMap id="UserMap" type="User">
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="pwd" property="password"/>
        <result column="createtime" property="createTime"/>
        <result column="modifytime" property="modifyTime"/>
    </resultMap>

column指的是資料庫的欄位,property指的是對象中的屬性名

註意,除了配置resultmap外,還有一處需要修改:

紅框圈出部分原來是resultType,再使用結果集映射後需要換為resultMap

  • resultmap元素是mybatis中最重要最強大的元素
  • resultmap的設計思想是,對於簡單的語句根本不需要配置顯式的結果映射,而對於複雜一點的雨具只需要描述它們之間的關係就行了
  • ResultMap的最優秀之處在於,雖然你已經對他相當瞭解了,但是根本就不需要現實的用到它們。

06 日誌

6.1 日誌工廠

如果一個資料庫操作出現了異常,需要人為排錯,日誌就是非常好的幫手。

曾經:debug、sout

現在:日誌工廠

  • SLF4J
  • LOG4J(3.5.9 起廢棄) (重點)
  • LOG4J2 (重點)
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING (重點)
  • NO_LOGGING

在mybatis中具體使用哪一種日誌,在config.xml文件中配置

註意:還記得前面說的配置順序問題嗎,需要註意!

    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

  • 可以看到,黃色部分是mybatis打開JDBC連接,以及創建資料庫連接的過程,同時將自動提交設置為否。
  • 紅框部分包含所執行的sql語句以及在資料庫中的查詢結果
  • 紅框和藍框間是查詢結果
  • 藍框是執行完sql後一些設置,包括重新開啟自動提交以及斷開JDBC連接

6.2 LOG4J

什麼是Log4j?

  • Log4j是Apache的一個開源項目,通過使用Log4j,我們可以控制日誌信息輸送的目的地是控制台、文件、GUI組件等等。
  • 我們也可以控制每一條日誌的輸出格式;
  • 通過定義每一條日誌信息的級別,可以使我們更加細緻的控制日誌的生成過程。
  • 通過一個配置文件來靈活地進行配置,而不需要修改應用的代碼

如何快速開始?

1、先導入log4j的jar包

 <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

2、配置log4j.properties

#將等級為DEBUG的日誌信息輸出到console和file兩個目的地,console和file的定義在下麵代碼
log4j.rootLogger = DEBUG,console,file

#控制台輸出的相關設置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold = DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%c]-%m%n


#文件輸出的相關設置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File =  ./log/wu.log
log4j.appender.file.MaxFileSize = 10mb
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = [%p][%d{yyyy-MM-dd}][%c]%m%n


#日誌輸出級別
log4j.logger.org.mybatis = DEBUG
log4j.logger.java.sql = DEBUG
log4j.logger.java.sql.Statement = DEBUG
log4j.logger.java.sql.ResultSet = DEBUG
log4j.logger.java.sql.PreparedStatement = DEBUG

3、配置log4j為日誌的實現

 <settings>
        <setting name="logImpl" value="LOG4J"/>
 </settings>

如何使用日誌?

  • 在要使用Log4j的類中,導入包import org.apache.log4j.Logger

  • 創建日誌對象,參數為當前類的class

    static  Logger logger = Logger.getLogger(XXX.class);
    
  • 日誌級別

    logger.info("info:進入了log4j");
    logger.error("error:進入了log4j");
    logger.debug("debug:進入了log4j");
    logger.warn("warn:進入了log4j");
    

07 分頁

7.1 使用Limit分頁

思考:為什麼要分頁?

  • 減少數據的處理量,提高速度

使用Limit分頁

SELECT * FROM `user` limit startIndex,pageSize;

使用Mybatis實現分頁 ,核心SQL

1、介面

   List<User> getUserByLimit(Map<String,Integer> map);

2、Mapper.xml

 <select id="getUserByLimit" resultMap="UserMap" parameterType="map">
        select * from mybatis.user limit #{startIndex},#{pageSize}
 </select>

3、編寫測試方法

 @Test
    public void testPage(){
        SqlSession sqlSession = MybatisUtils.getsqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String,Integer> map = new HashMap<String,Integer>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> userByLimit = mapper.getUserByLimit(map);
        for (User user : userByLimit) {
            System.out.println(user);
        }
        sqlSession.close();
    }

7.2 使用RowBounds分頁

不再使用sql實現分頁,使用一個對象實現分類。

新建一個RowBounds對象,然後傳入兩個參數,分別是偏差(起始位=偏差+1)和條數限制

RowBounds bounds = new RowBounds(1,2);

介面:

List<User> getUserByRowBounds();

mapper.xml:

    <select id="getUserByRowBounds" resultMap="UserMap">
        select * from mybatis.user
    </select>

測試:

 @Test
    public void testRowBounds(){
        SqlSession sqlSession = MybatisUtils.getsqlSession();
        /*新建bounds對象*/
        RowBounds bounds = new RowBounds(1,2);

        /*通過java代碼層面實現分頁*/
        List<User> userlist = sqlSession.selectList("com.wu.mapper.UserMapper.getUserByRowBounds",null,bounds);
        for (User user : userlist) {
            System.out.println(user);
        }
        sqlSession.close();
    }

7.3 分頁插件

08 使用註解開發

8.1 面向介面編程

  • 學習Java,相比於c語言,一個比較大的區別在於編程思路上。Java是一門面向對象的編程語言,同時隨著對架構的學習,也知道了包括介面等其他知識。在真正開發中,相比於面向對象,大多數時候人們會選擇面向介面編程
  • 根本原因:解耦,可拓展,提高復用,分層開發中,上層不用管具體的實現,開發人員遵守共同的標準,使得開發變得容易,規範性更好
  • 在一個面向對象的系統中,系統的各種功能時由許許多多的不同對象協作完成的。在這種情況下,各個對象內部是如何實現自己的,對於系統設計人員來講就並不重要。
  • 但與此同時,各個對象之間的協作關係則成為系統設計的關鍵。小到不同類之間的通信,大到各模塊之間的交互,在系統設計之初便是要著重考慮的,這也是系統設計的主要工作內容。面向介面編程就是指按照這種思想來編程。

關於介面的理解

  • 介面從更深層次的理解,應是定義(規範,約束)與實現(名實分離的原則)的分離
  • 介面的本身反映了系統設計人員對系統的抽象理解
  • 介面應有2類:
    • 第一類是對一個個體的抽象,它可對應為一個抽象體(abstract class)
    • 第二類是對一個個體某一方面的抽象,即形成一個抽象面(interface)
  • 一個個體有可能有多個抽象面。抽象體與抽象面是有區別的。

三個面向的區別

  • 面相對象是指,我們考慮問題時,以對象為單位,考慮它的屬性和方法
  • 面向過程是指,我們考慮問題時,以一個具體的流程(事務過程)為單位,考慮它的實現。
  • 介面設計與非介面設計是針對復用技術而言的,與面向對象(過程)不是一個問題。更多的體現就是對系統整體的架構的思考。

8.2 使用註解開發

也就是說,不需要配置xml實現介面中的sql,直接在介面文件中使用註解編寫sql。

介面:

    @Select("select * from user")
    List<User> getUserList();

修改映射文件配置:

 <mappers>
        <!--<mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
        <!--<mapper resource="com/wu/mapper/UserMapper.xml"/>-->
        <!--<mapper class="com.wu.dao.UserMapper"></mapper>-->
        <!--<package name="com.wu.dao"/>-->
        <mapper class="wu.mapper.UserMapper"></mapper>
    </mappers>

編寫測試方法:

 public void test(){
        SqlSession sqlSession = MybatisUtils.getsqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

​ 但是可以發現,由於先前更改了實體類中的pwd為password,因此在採取註解編程時,就無法採取在xml中配置結果集映射的方式。使用註解來映射簡單語句會使代碼顯得更加簡潔,但對於稍微複雜一點的語句,Java 註解不僅力不從心,還會讓本就複雜的 SQL 語句更加混亂不堪。 因此,如果需要做一些很複雜的操作,最好用 XML 來映射語句。

本質:反射機制!

底層:動態代理!

8.3 Mybatis的詳細執行流程(暫缺,後續補齊)

8.4 CRUD

首先,為了方便起見,在創建sqlsession時便設置自動提交事務

public static SqlSession getsqlSession(){
        return sqlSessionFactory.openSession(true);
    }

編寫介面,用註解實現增刪改查

@Select("select * from user")
    List<User> getUserList();


    /*@Param 如果方法存在多個參數,則所有的參數前面必須加上@Param*/
    @Select("select * from user where id = #{id}")
    User getUserById(@Param("id") int id /*,@Param("name") String name*/);

    @Insert("insert into user(id,name,pwd,createtime,modifytime) values(#{id},#{name},#{password},#{createTime},#{modifyTime})")
    int addUser(User user);


    @Update("update `user` set name = #{name} , pwd = #{password} , createtime = #{createTime} , modifytime = #{modifyTime} where id = #{id}")
    int updateUser(User user);


    @Delete("delete from `user` where id = #{id}")
    int deleteUser(@Param("id") int  id);

編寫測試類,驗證相關功能

[註意,每新建一個mapper,都要綁定相關的介面文件]

對於多個mapper.xml文件,可以在前面採取*方式進行通配

<mapper resource="com/wu/mapper/*Mapper.xml"/>
@Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getsqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
/*        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }*/
/*        User user = mapper.getUserById(1);*/
        User user = new User();
        user.setId(7);
        user.setName("張恩普");
        user.setPassword("123456");
        user.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        int i = mapper.addUser(user);
        if(i>0) {
            System.out.println("添加成功!影響"+i+"行");
        }
        sqlSession.close();
    }


    @Test
    public void test2(){
        SqlSession sqlSession = MybatisUtils.getsqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user1 = mapper.getUserById(4);
        User user2 = new User(4,"劉天博","987654321", user1.getCreateTime(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date().getTime()));
        int i = mapper.updateUser(user2);
        if (i>0){
            System.out.println("修改完成,影響"+i+"行");
        }
        sqlSession.close();
    }

    @Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.getsqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.deleteUser(5);
        if(i>0){
            System.out.println("修改完成,影響"+i+"行");
        }
        sqlSession.close();
    }

8.5 Param註解

關於@Param()註解

  • 基本類型的參數或者String類型,需要加上
  • 引用類型不需要加
  • 如果只有一個基本類型的話,可以忽略,但是建議大家都加上
  • 我們在SQL中引用的就是我們這裡的@Param()中設定的屬性名!

09 Lombok

9.1 什麼是lombok

  • 官網英文介紹:
  Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.
  Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
  • 翻譯一下:

    Lombok項目是一個java庫,它可以自動插入你的編輯器和構造工具,從而實現簡化代碼和提高java程式的趣味。使用lombk將讓你不需要再另寫一個getter或setter方法。使用一個註釋,你的類就將有一個完整功能的構造器,同時還可以實現包括自動配置你的日誌變數等等其他更多功能。

  • 各種註釋欄位

    @Setter 註解在類或欄位,註解在類時為所有欄位生成setter方法,註解在欄位上時只為該欄位生成setter方法。
    @Getter 使用方法同上,區別在於生成的是getter方法。
    @ToString 註解在類,添加toString方法。
    @EqualsAndHashCode 註解在類,生成hashCode和equals方法。
    @NoArgsConstructor 註解在類,生成無參的構造方法。
    @RequiredArgsConstructor 註解在類,為類中需要特殊處理的欄位生成構造方法,比如final和被@NonNull註解的欄位。
    @AllArgsConstructor 註解在類,生成包含類中所有欄位的構造方法。

    @Data 註解在類,生成setter/getter、equals、canEqual、hashCode、toString、無參構造方法,如為final屬性,則不會為該屬性生成setter方法。
    @Slf4j 註解在類,生成log變數,嚴格意義來說是常量。private static final Logger log = LoggerFactory.getLogger(UserController.class);

  • 使用步驟:

    • 在IDEA中安裝Lombok插件

    • 在項目中導入lombok的jar包

      <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <version>1.18.24</version>
              </dependency>        
      
    • 在實體類中使用lombok

      @Data
      @AllArgsConstructor
      public class User {
          private Integer id;
      
          private String name;
      
          private String password;
      
          private String createTime;
      
          private String modifyTime;
      
      
      }
      
    • 在pojo的user類添加@Data後:

10 複雜查詢環境(多對一處理和一對多處理)

10.1 測試環境搭建

  • 資料庫建表

    CREATE TABLE `teacher` (
      `id` INT(10) NOT NULL,
      `name` VARCHAR(30) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8;
    
    INSERT INTO teacher(`id`, `name`) VALUES (1, '吳老師'); 
    INSERT INTO teacher(`id`, `name`) VALUES (2, '袁老師'); 
    
    CREATE TABLE `student` (
      `id` INT(10) NOT NULL,
      `name` VARCHAR(30) DEFAULT NULL,
      `tid` INT(10) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `fktid` (`tid`),
      CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8;
    
    INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); 
    INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小紅', '1'); 
    INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小張', '1'); 
    INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '2'); 
    INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '2');
    

  • 導入lombok(具體操作見第9章)

  • 新建實體類Teacher和Student

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Teacher {
    
        private int id;
    
        private String name;
        
    }
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Student {
    
        private int id;
    
        private String name;
    
        /*學生需要關聯一個老師*/
        private Teacher teacher;
        
    }
    
  • 在dao文件下建立Mapper介面以及Mapper.xml文件

  • 在核心配置文件中綁定註冊Mapper介面或者文件(我這裡給出兩種,要麼用包定義,要麼用下麵那兩個去調Mapper.xml)

  • 測試一下是否能夠成功查詢

10.2 多對一處理

  • 首先在資料庫中嘗試實現查詢學生和關聯老師姓名:

    select s.id,s.name,t.name from student s ,teacher t where s.tid=t.id;
    

  • 但是,這樣的sql放到mybatis中卻並不好使。

     <select id="getStudent" resultType="student">
            select s.id,s.name,t.name from student s ,teacher t where s.tid=t.id;
        </select>
    

很簡單,因為在資料庫中查不到teacher屬性的數據。因此查出來為空很好理解

  • 解決辦法:
    • 按照查詢嵌套處理
    • 按照結果嵌套處理

10.2.1 按照查詢嵌套處理

    <!--
    思路:
    查詢所有的學生信息
    根據查詢出來的學生的tid,尋找對應的老師
    方式一:按照查詢嵌套處理
    -->
    
    <select id="getStudent1" resultMap="StudentTeacher">
       select * from student
    </select>

    <resultMap id="StudentTeacher" type="student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--複雜的屬性,我們需要單獨處理 對象association 集合collection-->
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>

    <select id="getTeacher" resultType="teacher">
        select * from teacher where id = #{tid}
    </select>

10.2.2 按照結果嵌套處理

<!--
       思路二:
       直接在查詢的結果中,將student中teacher的名字屬性映射到teacher表的name上不就行了?
    -->

    <select id="getStudent2" resultMap="StudentTeacher2">
       select s.id sid,s.name sname,t.id tid ,t.name tname from student s ,teacher t where s.tid=t.id;
    </select>

    <resultMap id="StudentTeacher2" type="student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <!--複雜的屬性,我們需要單獨處理 對象association 集合collection-->
        <association property="teacher" javaType="Teacher">
            <result property="id" column="tid"/>
            <result property="name" column="tname"/>
        </association>
    </resultMap>

回顧Mysql多對一查詢方式:

  • 子查詢
  • 聯表查詢

10.3 一對多處理

  • 環境搭建和10.1類似,但是需要適當修改實體類

    public class Student {
    
        private int id;
    
        private String name;
        
        private int tid;
    
    }
    
    public class Teacher {
    
        private int id;
    
        private String name;
    
        /*一個老師關聯多個學生*/
        private List<Student> studentList;
    
    }
    

10.3.1 按照結果嵌套處理

首先梳理一下思路,按照結果嵌套處理,和10.2.2一樣,就是只查詢一次,然後在查詢過程中配置好映射關係即可。

 <!--按結果嵌套查詢-->
    <resultMap id="TeacherStudent1" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!--針對複雜的屬性,我們需要單獨處理 對象:association 集合:collection
        javaType="" 指定屬性的類型
        集合中的泛型信息,使用ofType獲取
        -->
        <collection property="student" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>
Teacher getTeacher1(@Param("tid") int id);

10.3.2 按照查詢嵌套處理

​ 相比於按照結果嵌套查詢處理,按照查詢嵌套處理會出現多次查詢,然後對映射關係的配置相比之下略微簡單。但註意此時在collection中需要額外配置許多其它參數,而且實際上在對映射關係的理解上更加複雜。

    <!--按查詢嵌套處理-->
    <select id="getTeacher2" resultMap="TeacherStudent2">
        select * from teacher where id = #{tid}
    </select>
    <resultMap id="TeacherStudent2" type="Teacher">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <collection property="student" column = "id" javaType="ArrayList" ofType="Student" select="getStudent"/>
    </resultMap>
    <select id="getStudent" resultType="Student">
        select * from student where tid = #{id}
    </select>
Teacher getTeacher2(@Param("tid") int id);

10.4 總結

1、關聯-association【多對一】

2、集合-collection【一對多】

3、javaType & ofType

    1. JavaType 用來指定實體類中屬性的類型
    1. ofType 用來指定映射到List或者集合中的pojo類型,是在使用泛型時對所傳內容的類型進行約束

4、註意點

  • 保證SQL可讀性,儘量保證通俗易懂
  • 註意一對多和多對一中,屬性名和欄位的問題
  • 如果問題不好排查錯誤,可以使用日誌,建議使用Log4j

面試高頻:

  • Mysql引擎
  • InnoDB底層原理
  • 索引
  • 索引優化!

11 動態SQL

什麼是動態SQL:動態SQL就是根據不用的條件生成不同的SQL語句。

動態 SQL 是 MyBatis 的強大特性之一。如果你使用過 JDBC 或其它類似的框架,你應該能理解根據不同條件拼接 SQL 語句有多痛苦,例如拼接時要確保不能忘記添加必要的空格,還要註意去掉列表最後一個列名的逗號。利用動態 SQL,可以徹底擺脫這種痛苦。
使用動態 SQL 並非一件易事,但藉助可用於任何 SQL 映射語句中的強大的動態 SQL 語言,MyBatis 顯著地提升了這一特性的易用性。 -Mybatis官網

if

choose(when,otherwise)

trim(where,set)

foreach

新建一個工程用於接下來學習(導入jar包和修改配置文件略):

  1. 新建一張表
CREATE TABLE `blog`(
	`id` VARCHAR(50) NOT NULL COMMENT '博客id',
	`title` varchar(100) NOT NULL COMMENT '博客標題',
	`author` varchar(30) NOT NULL COMMENT '博客作者',
	`create_time` datetime NOT NULL COMMENT '創建時間',
	`views` int(30) NOT NULL COMMENT '瀏覽量'
)ENGINE=INNODB DEFAULT CHARSET=utf8;
  1. 編寫實體類
@Data
public class Blog {

    private String id;

    private String title;


    private String author;

    private Date createTime;

    private int views;
    
}
  1. 啟用駝峰命名映射
    <settings>
        <!--是否開啟駝峰命名自動映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
  1. 編寫測試方法寫入數據
    //插入數據
    int addBook(Blog blog);
    <insert id="addBook" parameterType="blog">
        insert into mybatis.blog (id,title,author,create_time,views)
        Values (#{id},#{title},#{author},#{createTime},#{views});
    </insert>
@Test
    public void addBlogTest(){
        SqlSession sqlSession = MybatisUtils.getsqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        Blog blog = new Blog();

        blog.setId(IdUtils.getId());
        blog.setTitle("Mybatis");
        blog.setAuthor("wutong");
        blog.setCreateTime(new Date());
        blog.setViews(10);

        int i = mapper.addBook(blog);


        blog.setId(IdUtils.getId());
        blog.setTitle("Java");
        blog.setAuthor("wutong");
        blog.setViews(100);
        i+=mapper.addBook(blog);

        blog.setId(IdUtils.getId());
        blog.setTitle("Spring");
        blog.setAuthor("tianbo");
        blog.setViews(1000);
        i+= mapper.addBook(blog);

        blog.setId(IdUtils.getId());
        blog.setTitle("微服務");
        blog.setAuthor("jibo");
        blog.setViews(9999);
        i+=mapper.addBook(blog);

        System.out.println("執行完成!影響"+i+"行");
        sqlSession.close();
    }

11.1 IF使用

利用傳入的map內的值來判斷是否增加如下的條件語句。

    <select id="queryBlogIf" parameterType="map" resultType="blog">
        select * from mybatis.blog where 1=1
        <if test="title!=null">
            and title = #{title}
        </if>
        <if test="author!=null">
            and author = #{author}
        </if>
    </select>

思考:為什麼要加入"1=1"這種恆等式?

這樣做的目的是在sql進行拼接時,不會出現由於前面沒有其他條件直接出現"where and"的情況,致使sql語句報錯。使用1=1將使得其他額外查詢條件採取統一的 "and+條件"的格式。當然也有別的解決方法,如使用11.3中的where語句。

11.2 Choose(when,otherwise)

Choose配合when使用更加近似於Java中的switch case語句,看下麵這個例子:

<select id="queryBlogChoose" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <choose>
                <when test="title != null">
                    and title = #{title}
                </when>
                <when test="author != null">
                    and author =#{author}
                </when>
                <when test="views!=null">
                    and views >= #{views}
                </when>
                <otherwise>
                    1=1
                </otherwise>
            </choose>
        </where>
    </select>

註意,當傳入的條件從上到下進入一個when後,就不會再走更下麵的的when,即使條件同樣滿足。(類似java的break)

11.3 Trim(where,set)

11.3.1 where

    <select id="queryBlogIf2" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <if test="title!=null">
                title = #{title}
            </if>
            <if test="author!=null">
                and author = #{author}
            </if>
        </where>
    </select>

where 元素只會在子元素返回任何內容的情況下才插入 “WHERE” 子句。而且,若子句的開頭為 “AND” 或 “OR”,where 元素也會將它們去除。

大白話就是,如果只有一個查詢條件,會自動去掉條件前面的and。如果子句前面有and/or,而且前面無其他條件時,也會去掉。

如果寫成下麵這種的,也對。但註意,or和and只能多不能少。如果少了會出現報錯!

  <select id="queryBlogIf2" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <if test="title!=null">
                and title = #{title}
            </if>
            <if test="author!=null">
                and author = #{author}
            </if>
        </where>
    </select>

11.3.2 set

<update id="updateBlog" parameterType="blog">
        update mybatis.blog
        <set>
             <if test="title!=null">
                 title = #{title},
             </if>
            <if test="views!=0">
                views = #{views},
            </if>
        </set>
        where author = #{author}
    </update>
    @Test
    public void test4(){
        SqlSession sqlSession = MybatisUtils.getsqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        Blog blog = new Blog();
        /*blog.setViews(10001);*/
        blog.setTitle("學習神經網路");
        blog.setAuthor("jibo");
        int i = mapper.updateBlog(blog);
        if(i>0){
            System.out.println("執行完成!影響"+i+"行");
        }
        sqlSession.close();
    }

所謂的動態sql,本質還是SQL語句,只是我們可以在SQL層面,去執行一個邏輯代碼。

if

where ,set,choose,when

11.4 SQL片段(可插拔腳本)和Foreach

11.4.1 SQL片段

有的時候,我們可能會講一些功能的部分抽取出來,方便復用!

  1. 使用SQL標簽抽取公共的部分

     <sql id="testSqlPart">
            <if test="title!=null">
                and title = #{title}
            </if>
            <if test="author!=null">
                and author = #{author}
            </if>
        </sql>
    
  2. 在需要使用的地方使用include標簽引用即可

    <select id="queryBlogIf" parameterType="map" resultType="blog">
            select * from mybatis.blog
            <where>
                <include refid="testSqlPart"></include>
            </where>
        </select>
    
  • 註意事項:
    • 最好基於單表來定義SQL片段!
    • SQL片段內不要存在where標簽,where放在主體內

11.4.2 Foreach

<select id="queryBlogForeach" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>

 @Test
    public void test6(){
        SqlSession sqlSession = MybatisUtils.getsqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap map = new HashMap();

        ArrayList< String> ids = new ArrayList<String>();
        ids.add("2f49a219363a49fd9714697b342db31a");
        map.put("ids",ids);
        List<Blog> blogs = mapper.queryBlogForeach(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

動態SQL就是在拼接SQL語句,我們主要保證SQL的 正確性,按照SQL的格式,去排列組合即可

建議:

  • 先在Mysql中寫出完整的SQL再對應修改成為我們的動態SQL實現通用即可!

12 緩存

12.1簡介

1、什麼是緩存(Cache)

  • 存在記憶體中的臨時數據
  • 將用戶經常查詢的數據放在緩存(記憶體)中,用戶查詢數據就不用從磁碟上(關係型資料庫數據文件)查詢,從緩存中查詢,從而提高查詢效率,解決高併發系統的性能問題。

2、為什麼使用緩存?

  • 減少和資料庫的交互次數,減少系統開銷,提高系統效率。

3、什麼樣的數據能使用緩存?

  • 經常查詢並且不經常改變的數據。

12.2 Mybatis緩存

  • Mybatis包含一個非常強大的查詢緩存特性,它可以非常方便的定製和配置緩存。緩存可以極大的提升查詢效率。
  • Mybatis系統中預設定義了兩級緩存:一級緩存二級緩存
    • 預設情況下,只有一級緩存開啟。(sqlsession級別的緩存,也稱為本地緩存。一旦關閉sqlsession,則緩存內容丟失。)
    • 二級緩存需要手動開啟和配置,其是基於namespace級別的緩存。
    • 為了提高擴展性,Mybatis定義了緩存介面Cache。我們可以通過實現Cache介面來自定義二級緩存。

12.3 一級緩存

  • 一級緩存也叫本地緩存:
    • 與資料庫同一次會話期間查詢到的數據會放在本地緩存中。
    • 以後如果需要獲取想用的數據,則直接從緩存中拿,沒必要再去查詢資料庫。

測試步驟:

  • 1、開啟日誌

    <settings>
            <!--是否開啟駝峰命名自動映射-->
            <setting name="mapUnderscoreToCamelCase" value="true"/>
            <!--標準日誌工廠配置-->
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
    
  • 2、測試在一個session中查詢兩次相同的sql。

    public void test1(){
            SqlSession sqlSession = MybatisUtils.getsqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            Integer id = 1;
            User user1 = mapper.queryUserById(id);
            System.out.println(user1);
            Integer id2 = 1;
            System.out.println("=====================");
            User user2 = mapper.queryUserById(id2);
            System.out.println(user2);
            System.out.println("=====================");
            System.out.println(user1==user2);
            sqlSession.close();
        }
    
  • 3、查看日誌輸出

緩存失效的情況:

  1. 增刪改操作,可能會改變原來的數據,因此必定會刷新緩存!

  2. 查詢不同sql(條件不一致也會失效)

  3. 查詢不同的Mapper.xml

  4. 手動清理緩存(操作如下,可以看到會執行兩次查詢操作)

    sqlSession.clearCache();
    

小結:

  • 一級緩存預設是開啟的,只在一次SqlSession中有效,也就是拿到連接到關閉連接這個區間段!

12.4 二級緩存

  • 二級緩存也叫全局緩存,一級緩存作用域太低了,所以誕生了二級緩存
  • 基於namespace級別的緩存,一個名稱空間,對應一個二級緩存

  • 工作機制
    • 一個會話查詢一條數據,這個數據就會被放在當前會話的一級緩存中;
    • 如果當前會話關閉了,這個會話對應的一級緩存就沒了;但是我們想要的是,會話關閉了,一級緩存中的數據會被保存到二級緩存中。
    • 新的會話查
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 因為我用的是windows伺服器,因此需要一臺虛擬機,用來安裝centos,虛擬機的安裝網上好多教程,這裡不做過多介紹 這次同樣是按步操作 在本地伺服器創建下載目錄 -> 將yum文件下載到本地 -> 在遠程伺服器上創建目錄 -> 上傳文件到遠程伺服器目錄 -> 使用命令安裝yum到伺服器上 這次的 ...
  • # 任務與協程 ## 區別 > 一個程式可以只有任務、只有協程、二者都有,但不可以通過隊列/信號量互相傳遞數據 ## 任務特點 1. 任務之間可以互相獨立 2. 每個任務分配自己的堆棧,提高了RAM使用率 3. 操作簡單、按優先順序搶占式執行 4. 搶占容易導致重入(執行任務時被其他線程或進程調用了) ...
  • ![](https://img2023.cnblogs.com/blog/3076680/202308/3076680-20230822115524099-438612716.png) # 1. 在執行語句之前,會先檢查下列事項 ## 1.1. 是否有許可權執行該語句 ## 1.2. 是否有許可權訪問指 ...
  • 排序查詢:select 欄位列表 from [表名] order by [欄位名1] [asc升序/desc降序,預設值為升序],[欄位名2] [排序方式];//欄位名1為優先順序排序,如果欄位名1有相同的,再以欄位名2排序 聚合函數: count 統計數量(一般不選null的列) max 最大值 m ...
  • ## 1、字元集概述 - Oracle語言環境的描述包括三部分:language、territory、characterset(語言、地域、字元集) - language:主要指定伺服器消息的語言,提示信息顯示中文還是英文 - territory:主要指定伺服器的數字和日期的格式 - charact ...
  • 在日常工作中,有時會遇到一次性往頁面中插入大量數據的場景,在數棧的[離線開發](https://www.dtstack.com/dtinsight/batchworks?src=szsm)(以下簡稱離線)產品中,就有類似的場景。本文將通過分享一個實際場景中的[前端開發](https://www.dt ...
  • 第14屆中國資料庫技術大會(DTCC2023)上,華為雲資料庫GaussDB首席架構師馮柯對華為雲GaussDB資料庫的高級壓縮技術進行了詳細的解讀。 ...
  • 最近接到了一個新需求,要求提供查詢關註對象的粉絲列表介面功能。該功能的難點就是關註對象的粉絲數量過多,不少店鋪的粉絲數量都是千萬級別,並且有些大V粉絲數量能夠達到上億級別 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...