Mybatis基礎知識大全!!!

来源:https://www.cnblogs.com/xiaoye-Blog/archive/2022/07/28/16528921.html
-Advertisement-
Play Games

1. 簡介 1.1什麼是Mybatis MyBatis 是一款優秀的持久層框架 它支持自定義 SQL、存儲過程以及高級映射。 MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數和獲取結果集的工作。 MyBatis 可以通過簡單的 XML 或註解來配置和映射原始類型、介面和 Java POJ ...


目錄

1. 簡介

1.1什麼是Mybatis

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

1.2 如何獲得Mybatis

1.3 使用Mybatis的好處:

  • 使用簡單,傳統的JDBC代碼太複雜
  • 簡單易學:沒有任何第三方依賴,最簡單安裝只要兩個jar文件+配置幾個sql映射文件。
  • 靈活
  • 解除sql與程式代碼的耦合
  • 提供映射標簽,支持對象與資料庫的orm欄位關係映射。
  • 提供對象關係映射標簽,支持對象關係組建維護。
  • 提供xml標簽,支持編寫動態sql。

2.初涉Mybatis

2.1環境搭建

  1. 使用navicat創建一個資料庫

  2. 新建項目

  3. 導入依賴

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.9</version>
    </dependency>
    

2.2、創建一個模塊(項目)

  1. 編寫mybatis的核心配置文件

    <?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.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis?&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=Asia/Shanghai"/>
            <property name="username" value="root"/>
            <property name="password" value="18227022334a"/>
          </dataSource>
        </environment>
      </environments>
      <mappers>
        <mapper resource="Mapper/UserMapper.xml"/>
      </mappers>
    </configuration>
    
    <!--註:xml文件中使用&符號需要改成使用 &amp; 代替-->
    
  2. 編寫mybatis工具類(封裝):

    public class MybatisUtils {
        private static SqlSessionFactory sqlSessionFactory;
        //第一步:獲取SqlSessionFactory對象
        static {
            try {
                String resource = "mybatis-config.xml";//路徑寫對
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //通過SqlSessionFactory對象獲取SqlSession對象
        //SqlSession:SqlSession 提供了在資料庫執行 SQL 命令所需的所有方法。你可以通過 SqlSession 實例來直接執行已映射的 SQL 語句。
        public static SqlSession getSqlSession(){return  sqlSessionFactory.openSession();}//當傳遞一個true參數時表示自動提交事務
    }
    
  3. 編寫

    • 編寫實體類

      //註;實體類的屬性名必須與資料庫的列名一致,否則無法進行匹配從而出現數據為空的現象,當然也可以在Mapper.xml配置中通過編寫一個resultMap來進行映射,此時名字可以不相同
      
      public class User {
          private int id;
          private String username;
          private String password;
      
          public User() {
          }
      
          public User(int id, String username, String password) {
              this.id = id;
              this.username = username;
              this.password = password;
          }
      
          public int getId() {
              return id;
          }
      
          public void setId(int 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;
          }
      }
      
    • 編寫Mapper介面(Dao)

      public interface UserMapper {
          public List<User> getUser();
      }
      
    • 編寫Mapper配置文件

      //註:每個Mapper文件都需要在mybatis-config.xml文件中去註冊
      //<mapper resource="Mapper/UserMapper.xml"/>
      //相當於Mapper的介面實現類
      
      <?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">
          
          //namespace:命名空間,指定要實現的Mapper介面,路徑映射
      <mapper namespace="com.study.dao.UserMapper">
          
          //id:唯一匹配於Mapper介面的方法名
          //resultType:返回類型,必須寫全限定名稱
          <select id="getUser" resultType="com.study.pojo.User">
              select * from user;
          </select>
      </mapper>
      
  4. 測試

    public class UserMapperTest {
        @Test
        public void test(){
            //獲得sqlSession對象
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            //獲取UserMapper的對象以調用介面內的方法
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            //調用方法
            List<User> users = userMapper.getUser();
            //遍歷結果集
            for (User user : users) {
                System.out.println(user.getId() + " " + user.getUsername() + " " + user.getPassword());
            }
            //關閉sqlSessoin
            sqlSession.close();
        }
    }
    

2.3、使用Mybatis的三個重要類

  1. SqlSessionFactoryBuilder:

    可以重用 SqlSessionFactoryBuilder 來創建多個 SqlSessionFactory 實例,但最好還是不要一直保留著它,以保證所有的 XML 解析資源可以被釋放給更重要的事情

  2. SqlSessionFactory:

    SqlSessionFactory 一旦被創建就應該在應用的運行期間一直存在,沒有任何理由丟棄它或重新創建另一個實例,最簡單的就是使用單例模式或者靜態單例模式

  3. SqlSession:

    SqlSession 的實例不是線程安全的,因此是不能被共用的,每次打開一個 SqlSession,記得關閉它, 這個關閉操作很重要

3.Mybatis的CRUD簡單實現

3.1、通過id查找用戶:

  1. 介面:

    public User getUserById(int id);
    
  2. Mapper配置文件

    <select id="getUserById" resultType="com.study.pojo.User">
        select * from user where id=#{id};
    </select>
    
  3. 測試

    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = userMapper.getUserById(1);
    sqlSession.close();
    

3.2、插入用戶:

  1. 介面:

    public void insertUser(User user);
    
  2. Mapper配置文件

    <insert id="insertUser">
        insert into user values (#{id},#{username},#{password});
    </insert>
    
  3. 測試

    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.insertUser(new User(5,"老六","1234"));
    sqlSession.commit();
    sqlSession.close();
    //註:在Mybatis中增刪改查找都需要使用事務,必須手動提交事務如果沒有配置自動管理事務的情況下
    

3.3、根據id更改用戶名字:

  1. 介面:

    public void insertUser(User user);
    
  2. Mapper配置文件

    <insert id="insertUser">
        insert into user values (#{id},#{username},#{password});
    </insert>
    
  3. 測試

    //當有多個參數的時候,可以使用@Param()註解指定名字
    //public void updateName(@Param("id") int id,@Param("username") String username);
    
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.updateName(3,"王五");
    sqlSession.commit();
    sqlSession.close();
    

3.4、 根據id刪除用戶:

  1. 介面:

    public void insertUser(User user);
    
  2. Mapper配置文件

    <insert id="insertUser">
        insert into user values (#{id},#{username},#{password});
    </insert>
    
  3. 測試

    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.deleteUserById(5);
    sqlSession.commit();
    sqlSession.close();
    

3.5、好用的Map

當介面中傳遞的對象有多個的時候,除了可以使用·@Param()註解之外,我們常常使用一個不算規範但是特別好用的方式,那就是傳遞Map

  1. 介面:

     public void updateNameById(Map<String,Object> map);
    
  2. mapper配置文件:

    <update id="updateNameById" >
        update user set username=#{username} where id=#{id};
    </update>
    
  3. 調用:

    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    Map<String,Object> map=new HashMap();
    map.put("username","戰三");
    map.put("id",2);
    userMapper.updateNameById(map);
    sqlSession.commit();
    sqlSession.close();
    

總結:

  • 當介面只傳遞一個參數的時候:可以直接在mapper文件使用,且不需要與參數名字對應
  • 當需要多個參數的時候:
    • 如果有一個實體類正好與之對應,那麼可以傳遞一個對象,然後在mapper文件中通過#{對象.屬性}調用
    • 通過使用註解的方式@Param()指定名字
    • 通過傳遞一個Map

3.6、模糊查詢

  1. 方式一:在java代碼在傳遞“%”

    userMapper.getUserLike("%張%");
    
  2. 方式二:在mapper文件的sql語句中實現

    <select id="getUserLike" resultType="com.study.pojo.User">
        select * from user where username like "%"#{name}"%" ;
    </select>
    

4.配置解析

MyBatis 的配置文件包含了會深深影響 MyBatis 行為的設置和屬性信息。 配置文檔的頂層結構如下:

  • configuration(配置)
    • properties(屬性)
    • settings(設置)
    • typeAliases(類型別名)
    • typeHandlers(類型處理器)
    • objectFactory(對象工廠)
    • plugins(插件)
    • environments(環境配置)
      • environment(環境變數)
        • transactionManager(事務管理器)
        • dataSource(數據源)
    • databaseIdProvider(資料庫廠商標識)
    • mappers(映射器)

4.1、environments 環境配置

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

environments 元素定義瞭如何配置環境。

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <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>
    
    <!--如果要切換環境只需要更改環境default,改成需要使用的環境的id-->
    <environment id="test">
    </environment>
</environments>

註意點:

  • 預設使用的環境 ID(比如:default="development")。
  • 每個 environment 元素定義的環境 ID(比如:id="development")。
  • 事務管理器的配置(比如:type="JDBC")。
  • 數據源的配置(比如:type="POOLED")。

4.2、properties(屬性)

可以從外部的資源環境讀取,也可以在內部定義,可以動態的替換環境中的配置信息

  1. 外部資源文件引入:

    1. db.properties

      driver=com.mysql.cj.jdbc.Driver
      url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
      username=root
      password=11111111
      
    2. 引入:

      <properties resource="db.properties"> </properties>
      
  2. 內部使用property定義:

    <properties resource="org/mybatis/example/config.properties">
      <property name="username" value="dev_user"/>
      <property name="password" value="F2Fa3!33TYyg"/>
    </properties>
    

設置好的屬性可以動態替換:

<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

註:如果同時使用了外部資源文件和內部定義的方式那麼會使用外部資源文件。

4.3、typeAliases(類型別名)

類型別名可為 Java 類型設置一個縮寫名字,降低冗餘的全限定類名書寫

  1. 方式一:使用具體的全限定類名

    <typeAliases>
      <typeAlias alias="Author" type="domain.blog.Author"/>
      <typeAlias alias="Blog" type="domain.blog.Blog"/>
    </typeAliases>
    

    註:設定之後在其他使用domain.blog.Author的地方就可以使用Author代替

  2. 方式二:使用實體類包名

    <typeAliases>
      <package name="domain.blog"/>
    </typeAliases>
    

    註:通過這種方式設定之後,在該包下所有的實體類的全限定類名可以使用該類名的首字母小寫來代替,比如User使用user代替

總結:兩種方式各有優劣,當類比較少的時候可以使用第一種方式,當類比較多的時候可以使用第二種方式,如果想在使用第二種方式的同時給特點的類設定指定名字,可以使用註解的方式,且如果同時使用了第一種方式和第二種方式那麼使用兩個別名都正確。

@Alias("author")
public class Author {}

4.4、settings(設置)

1.常用的一些設置:

設置名 描述 有效值 預設值
cacheEnabled 全局性地開啟或關閉所有映射器配置文件中已配置的任何緩存。 true | false true
lazyLoadingEnabled 延遲載入的全局開關。當開啟時,所有關聯對象都會延遲載入。 特定關聯關係中可通過設置 fetchType 屬性來覆蓋該項的開關狀態。 true | false false
useGeneratedKeys 允許 JDBC 支持自動生成主鍵,需要資料庫驅動支持。如果設置為 true,將強制使用自動生成主鍵。儘管一些資料庫驅動不支持此特性,但仍可正常工作(如 Derby)。 true | false False
mapUnderscoreToCamelCase 是否開啟駝峰命名自動映射,即從經典資料庫列名 A_COLUMN 映射到經典 Java 屬性名 aColumn。 true | false False
logImpl 指定 MyBatis 所用日誌的具體實現,未指定時將自動查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 未設置

日誌:

  • STDOUT_LOGGING (mybatis預設)
  • LOG4J (掌握)
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • SLF4J
  • NO_LOGGING:

4.5、mappers(映射器)

  1. 作用:告訴 MyBatis 到哪裡去找映射文件

  2. 實現方式:

    1. 方式一:resource(推薦)

      <!-- 使用相對於類路徑的資源引用 -->
      <mappers>
        <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
        <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
        <mapper resource="org/mybatis/builder/PostMapper.xml"/>
      </mappers>
      
    2. 方式二:url(極不推薦)

      <!-- 使用完全限定資源定位符(URL) -->
      <mappers>
        <mapper url="file:///var/mappers/AuthorMapper.xml"/>
        <mapper url="file:///var/mappers/BlogMapper.xml"/>
        <mapper url="file:///var/mappers/PostMapper.xml"/>
      </mappers>
      
    3. 方式三:class

      <!-- 使用映射器介面實現類的完全限定類名 -->
      <mappers>
        <mapper class="org.mybatis.builder.AuthorMapper"/>
        <mapper class="org.mybatis.builder.BlogMapper"/>
        <mapper class="org.mybatis.builder.PostMapper"/>
      </mappers>
      

      註:

      • 介面必須和mapper配置文件在同一個包下
      • 介面和mapper配置文件的名字必須相同
    4. 方式四:name

      <!-- 將包內的映射器介面實現全部註冊為映射器 -->
      <mappers>
        <package name="org.mybatis.builder"/>
      </mappers>
      

      註:

      • 介面必須和mapper配置文件在同一個包下
      • 介面和mapper配置文件的名字必須相同

4.6、其他(暫時瞭解)

  • typeHandlers(類型處理器)
  • objectFactory(對象工廠)
  • plugins(插件)(有用)
    • Mybatis PageHelper分頁插件
    • Mybatis通用Mapper插件
    • Mybatis Plus插件
    • 代碼生成插件mybatis-generator

5.拓展:當屬性名和列名不一致

假設存在一個資料庫user表,欄位如下:

一個User實體類如下:

public class User {
    private int id;
    private String username;
    private String password;
    }

那麼當查詢結果集為User類型的時候,會出現姓名為空的問題。

解決方式:

  1. 方式一:在sql語句中使用別名

    select id ,name as usernaem,password from user;
    
  2. 方式二:resultMap結果映射

    <resultMap id="userMap" type="user">
        <id property="id" column="id"/>
        <result property="username" column="name"></result>
        <result property="password" column="password"></result>
    </resultMap>
    
    <select id="getUserAll" resultMap="userMap">
        select * from user  ;
    </select>
    
    • resultMap 元素是 MyBatis 中最重要最強大的元素。

    • ResultMap 的設計思想是,對簡單的語句做到零配置,對於複雜一點的語句,只需要描述語句之間的關係就行了。

    • ResultMap 的優秀之處——你完全可以不用顯式地配置它們,如上面的resultMap可以改為

    <resultMap id="userMap" type="user">
        <result property="username" column="name"></result>
    </resultMap>
    

    即只需要顯示的配置不匹配的情況即可。

    註:其實第一種方法使用別名的本質上還是使用了resultMap的映射,因為在這些情況下,MyBatis 會在幕後自動創建一個 ResultMap,再根據屬性名來映射列到 JavaBean 的屬性上。

6.日誌

6.1、日誌工廠

  1. 當我們操作資料庫出現錯誤時,需要藉助一些手段進行排錯

    • 之前:sout,debug
    • 現在:日誌
  2. 日誌類別:

    • STDOUT_LOGGING(掌握)(預設的標準日誌工廠)
    • LOG4J(掌握)
    • LOG4J2
    • SLF4J
    • JDK_LOGGING
    • COMMONS_LOGGING
    • NO_LOGGING
  3. 配置日誌:

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

    使用了日誌之後,我們就可以查看到非常多的信息

6.2、Log4j

  1. 介紹:

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

    1. 導入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.layout=org.apache.log4j.PatternLayout
      log4j.appender.console.layout.ConversionPattern=%p:%c%n%m%l%n%m 
      
      
      #文件輸出的相關設置
      log4j.appender.file=org.apache.log4j.FileAppender
      log4j.appender.file.File=d:/log4jFile/mybatis.log
      log4j.appender.file.layout=org.apache.log4j.PatternLayout
      log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd   HH:mm:ss} %l %F %p %m%n
      log4j.appender.file.MaxFileSize=10mb
      
      #控制日誌的輸出鑒別
      log4j.logger.org.mybatis=DEBUG
      log4j.logger.java.sql.ResultSet=DEBUG
      log4j.logger.java.sql=DEBUG
      log4j.logger.java.sql.Statement=DEBUG
      log4j.logger.java.sql.PreparedStatement=DEBUG
      
    3. 在mybatis-config中配置log4j的使用

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

7.分頁

思考:為什麼要分頁

  • 減少數據的處理量

7.1、 limit分頁:

select * from user limit startIndex,pagesize;

select *from user limit pagesize; -- 當只有一個參數的時候,從第一個數據開始

7.2、 RowBounds分頁(不推薦使用)

  1. 介面:

    public List<User> getUser();
    
  2. mapper.xml:

    <select id="getUser" resultType="com.study.pojo.User">
        select * from user ;
    </select>
    
  3. 實現:

    SqlSession sqlSession = MybatisUtils.getSqlSession();
    
    RowBounds rowBounds=new RowBounds(1,2);
    List<User> list = sqlSession.selectList("com.study.dao.UserMapper.getUser", null, rowBounds);
    for (Object user : list) {
        System.out.println(user.toString());
    }
    

7.3、分頁插件

使用PageHelper分頁插件,https://pagehelper.github.io/,瞭解一下即可,如有需要再看使用文檔。

8.註解開發

  • 使用註解來映射簡單語句會使代碼顯得更加簡潔
  • 但對於稍微複雜一點的語句,Java 註解不僅力不從心,還會讓你本就複雜的 SQL 語句更加混亂不堪
  • 如果需要做一些很複雜的操作,最好用 XML 來映射語句。

使用建議:除非是很簡單的操作,否則儘量建議使用xml方式完成,一般而言我們都會使用xml。

8.1、常用的註解

  1. @Insert:

    插入記錄的時候麻煩的一點是主鍵如何生成,對此基本上有三種方案,分別是手動指定(應用層)、自增主鍵(數據層單表)、選擇主鍵(數據層多表)。(如想瞭解可以查)

    @Insert("insert into user values (#{id},#{username},null)")
    
  2. @Delete:

    @Delete("delete from user where id=#{id};")
    
  3. @Updata:

    @Update(" update user set username=#{username} where id=#{id};")
    
  4. @select:

    @Select("select * from user")
    
  5. @Param:

    在介面中傳遞多個參數的時候可以指定

     public void updateName(@Param("id") int id,@Param("username") String username);
    

    註:

    • 基本類型或者String類型需要加上
    • 引用類型不需要加
    • 如果只有一個基本類型的參數可以不加
    • 在mapper.xml中使用的就是它指定的名字
  6. @Results, @Result:

    當使用select標簽時,如果查詢的欄位與當前實體類不能進行很好的匹配那麼需要我們進行一個映射

    @Results(id = "userMap", value = {
        @Result(id=true, column = "id", property = "id"),
        @Result(column = "username", property = "username"),
        @Result(column = "passwd", property = "passwd"),
    })
    @Select("SELECT * FROM t_user WHERE id=#{id}")
    User loadByIdResultMap(Long id);
    
  7. @ResultMap:

    如果以及存在一個@Results,那麼可以通過@ResultMap指定id名字去引用它

    @ResultMap("userMap")
    @Select("SELECT * FROM t_user WHERE id=#{id}")
    User loadByIdResultMapReference(Long id);
    

8.2、使用註解開發

  1. 介面:

    public interface UserMapper {
        @Select("select * from user")
        public List<User> getUser();
        @Update(" update user set username=#{username} where id=#{id};")
        public void updateName(@Param("id") int id,@Param("username") String username);
        @Insert("insert into user values (#{id},#{username},null)")
        public void insertUser(User user);
        @Delete("delete from user where id=#{id};")
        public void deleteUserById(int id);
    }
    
  2. mybatis-config.xml註冊介面:

    <mappers>
        <mapper class="com.study.dao.UserMapper"/>
    </mappers>
    
  3. 測試:

    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> user = userMapper.getUser();
    //userMapper.insertUser(new User(6,"隨便","123123"));
    //userMapper.updateName(2,"還行");
    //userMapper.deleteUserById(1);
    for (User user1 : user) {
        System.out.println(user1);
    }
    sqlSession.commit();
    sqlSession.close();
    

本質:反射機制實現

底層:動態代理

8.3、關於#{}和${}的比較

  • 前者是占位,在使用時會將傳入的字元串加上引號當做一個整體,${}是拼接,在使用的時候會將傳入的字元串不做處理直接拼接
  • 使用#{}時會進行預編譯可以防止sql註入,使用${}不會預編譯不可以防止sql註入
  • 使用時#{}是編譯好SQL後語句再去取值,${}取值以後再去編譯SQL語句
  • 建議:一般能用#{}就不用${}

8.4、當註解開發和xml開發同時使用

註:雖然註解和xml配置文件可以同時使用,但是如果在介面中的同一個方法上既使用了註解,有在xml文件中進行了配置,也就是對同一個方法同時使用了註解配置文件兩種方式,那麼程式會報錯。

9.Lombok

Lombok項目是一個java庫,它可以自動插入到編輯器和構建工具中,增強java的性能。不需要再寫getter、setter或equals方法,只要有一個註解,你的類就有一個功能齊全的構建器、自動記錄變數等等.

  1. 常用註解:

    • Data:整合了Getter、Setter、ToString、EqualsAndHashCode、無參構造函數註解。
    • Getter:快速構建Getter方法。
    • Setter:快速構建Setter方法。
    • ToString:快速將當前對象轉換成字元串類型,便於log
    • EqualsAndHashCode:快速進行相等判斷
    • NonNull:判斷變數(對象)是否為空。
    • AllArgsConstructor:快速構建全部參數的構造函數
    • NoArgsConstructor:快速構建無參構造函數
  2. Lombok的使用:

    1. 在IDEA中安裝Lombok插件

      image-20220727153039855

    2. 在項目中導入lombok的jar包

      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.18.16</version>
      </dependency>
      
    3. 使用:

      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class Persosn {
          private String name;
          private int age;
      }
      

      註:由於使用@Data只含有無參構造函數,使用要結合@AllArgsConstructor使用,但是使用了@AllArgsConstructor之後@Data的無參構造函數就會消失,使用需要再搭配@NoArgsConstructor使用。

註:缺點:無法承載有各種參數的構造函數,但是我們可以手動的去添加。

10.複雜查詢

10.1、模擬場景環境搭建

  1. 新建項目,導入相關依賴
  2. 配置文件的編寫
  3. 新建實體類Student和Teacher
  4. 建立對應的Mapper介面
  5. 建立對應的Mapper配置文件
  6. 註冊配置文件
  7. 測試環境搭建是否成功

10.2、多對一實際應用:關聯

比如多個學生對應一個老師,就是多對一

實體類如下:

@Data
public class Student {
    private int id;
    private String name;
    private Teacher teacher;//多個學生一個老師
}

@Data
public class Teacher {
    private int id;
    private String name;
}

實現關鍵:association

10.2.1、嵌套查詢

<resultMap id="Student_t" type="student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
</resultMap>
<select id="getStudent" resultMap="Student_t">
    select * from student ;
</select>
<select id="getTeacher" resultType="teacher">
    select * from teacher where id=#{id}
</select

通過嵌套一個子查詢的方式,通過學生的tid去找到對應的老師

10.2.2、嵌套結果

<resultMap id="Student_t2" type="student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
    </association>
</resultMap>
<select id="getStudent2" resultMap="Student_t2">
    select s.id sid,s.name sname,t.id tid ,t.name tname from student s,teacher t where s.tid=t.id;
</select>

通過對結果集直接進行映射

10.3、一對多實際應用:集合

比如一個老師有多個學生,對於老師而言就是一對多

實體類如下:

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}

@Data
public class Teacher {
    private int id;
    private String name;
    private List<Student> students;
}

實現關鍵:collection

10.3.1、嵌套查詢

<resultMap id="teacher_s1" type="teacher">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <collection property="students" ofType="student" column="id" select="getStudent" javaType="ArrayList"/>
</resultMap>
<select id="getTeacher" resultMap="teacher_s1">
    select * from teacher t;
</select>
<select id="getStudent" resultType="student">
    select * from student where tid=#{id};
</select>

10.3.2、嵌套結果

<resultMap id="teacher_s2" type="teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <collection property="students" ofType="student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result column="tid" property="tid"/>
    </collection>
</resultMap>
<select id="getTeacher1" resultMap="teacher_s2">
    select s.id sid,s.name sname,t.id tid ,t.name tname from student s,teacher t where s.tid=t.id;
</select>

10.4、小結

  1. 關聯:association
  2. 集合:collection
  3. javaType:用來指定實體類中的屬性的類型
  4. ofType:用來指定映射到List或者集合中的pojo類型,泛型中的約束類型

附:面試高頻問題;

  • MySql引擎
  • InnoDB底層原理
  • 索引
  • 索引優化

11.動態SQL

11.1、簡單介紹

動態 SQL 是 MyBatis 的強大特性之一。如果你使用過 JDBC 或其它類似的框架,你應該能理解根據不同條件拼接 SQL 語句有多痛苦,例如拼接時要確保不能忘記添加必要的空格,還要註意去掉列表最後一個列名的逗號。利用動態 SQL,可以徹底擺脫這種痛苦。

種類:

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

11.2、實例項目的搭建

  1. 在資料庫中根據以下實體類創建blog表

    @Data
    public class Blog {
        private String id;
        private String title;
        private String author;
        private Date createTime;
        private int views;
    }
    

    拓展:實體類中的id類型是String,在具體的一個項目中其實我們可以使用UUID這個類來隨機生成一個唯一的ID,工具類簡單封裝如下:

    public class IDUtils {
        public static String getId(){
            return UUID.randomUUID().toString().replace("-","");
        }
    }
    
  2. 新建項目,導入相關依賴

  3. 配置文件的編寫

    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    

    註:開啟這個設置可以自動將資料庫的下劃線映射到實體類的駝峰命名屬性

  4. 新建實體類Blog

  5. 建立對應的Mapper介面

  6. 建立對應的Mapper配置文件

  7. 註冊配置文件

  8. 測試環境搭建是否成功

11.3動態SQL的使用

11.3.1、if

  • if提供了條件判斷的功能,可以根據情況決定是否要追加語句。
<select id="queryBlog" resultType="blog">
        select * from blog where 1=1
        <if test="id != null">
            and id=#{id}
        </if>
        <if test="title != null">
            and title =#{title}
        </if>
        <if test="author!='李四'">
            and author =#{author}
        </if>
        <if test="views  > 800 ">
            and views>#{views}
        </if>
    </select>

註:第一個where條件後面加一個1=1是為了方便後面的每一個判斷條件追加sql的第一個能寫and

11.3.2、choose (when, otherwise)

  • 有時候,我們不想使用所有的條件,而只是想從多個條件中選擇一個使用。針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。
<select id="queryBlog" resultType="blog">
    select * from blog
    <where>
        <choose>
            <when test="id != null">
                id=#{id}
            </when>
            <when test="title != null">
                and title =#{title}
            </when>
            <when test="author!='李四'">
                and author =#{author}
            </when>
            <otherwise>
                and views>#{views}
            </otherwise>
        </choose>
    </where>
</select>
  • 註:當同時滿足多個when的時候,按照順序選擇拼接,比如第一個when滿足那麼即是後面的滿足了也不會拼接,然後都不滿足那麼拼接otherwise裡面的內容,另外otherwise不是必須的

11.3.3、trim (where, set)

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

  • set:set 元素可以用於動態包含需要更新的列,忽略其它不更新的列

    <update id="updateAuthorIfNecessary">
      update Author
        <set>
          <if test="author != null">author=#{author},</if>
          <if test="title != null">title=#{title},</if>
          <if test="views >= 0">views=#{views}</if>
        </set>
    </update>
    
  • trim:

    • trim包含的屬性;

      • prefix:自定義首碼
      • prefixOverrides:需要被移除的首碼
      • suffix:自定義尾碼
      • suffixOverrides:需要被移除的尾碼
    • 可以自定義標簽的替換方式,比如與where等同效果的格式如下:

      <trim prefix="WHERE" prefixOverrides="AND |OR ">
        ...
      </trim>
      

      prefixOverrides 屬性會忽略通過管道符分隔的文本序列(註意此例中的空格是必要的)。上述例子會移除所有 prefixOverrides 屬性中指定的內容,並且插入 prefix 屬性中指定的內容。

    • 與set等同效果的格式如下:

      <trim prefix="SET" suffixOverrides=",">
        ...
      </trim>
      

11.3.4、foreach

  • foreach 元素的功能非常強大,它允許你指定一個集合,聲明可以在元素體內使用的集合項(item)和索引(index)變數。它也允許你指定開頭與結尾的字元串以及集合項迭代之間的分隔符。

  • 可以將任何可迭代對象(如 List、Set 等)、Map 對象或者數組對象作為集合參數傳遞給 foreach。當使用可迭代對象或者數組時,index 是當前迭代的序號,item 的值是本次迭代獲取到的元素。當使用 Map 對象(或者 Map.Entry 對象的集合)時,index 是鍵,item 是值。

    <select id="queryBlog" resultType="blog">
        select * from blog
        <where>
            <foreach collection="names" item="name" open="author in (" close=")" separator=",">
                #{name}
            </foreach>
        </where>
    </select>
    

    測試:

    @Test
    public void test() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        ArrayList<String> names = new ArrayList<>();
        names.add("張三");
        names.add("李四");
        Map<String,List> map=new HashMap<>();
        map.put("names",names);
        List<Blog> blogs = blogMapper.queryBlog(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }
    

11.3.5、sql片段

sql片段的作用就是可以將一部分sql代碼抽取出來,然後可以對他進行一個復用。

<select id="queryBlog" resultType="blog">
    select * from blog
    <where>
        <include refid="choose"></include>
    </where>
</select>
<sql id="choose">
    <choose>
        <when test="id != null">
            id=#{id}
        </when>
        <when test="title != null">
            and title =#{title}
        </when>
        <when test="author!='李四'">
            and author =#{author}
        </when>
    </choose>
</sql>

註意事項:

  • 儘量不要使sql片段太過複雜

11.3.6、小結

動態sql本質上就是拼接sql語句

建議:

  • 我們可以在mysql中去寫寫出我們需要的sql語句,然後再去拼接

12.Mybatis緩存

12.1、簡介

  1. 什麼是緩存
    • 存儲在記憶體中的臨時數據
    • 將經常查詢的信息從記憶體中複製一份到緩存,當再次查找時就直接從緩存中查找,從而提高效率,解決高併發的性能問題
  2. 使用緩存的好處
    • 減少資料庫的交互次數,減小系統的開銷,提高效率
  3. 什麼樣的資料庫可以使用緩存
    • 查詢比較頻繁並且不經常改動的資料庫

12.2、Mybatis緩存

mybatis本身有兩種緩存,分別為一級緩存和二級緩存

  1. 一級緩存:

    • MyBatis預設開啟了一級緩存,一級緩存是在 SqlSession 層面進行緩存的。即,同一個 SqlSession ,多次調用同一個 Mapper 和同一個方法的同一個參數,只會進行一次資料庫查詢,然後把數據緩存到緩衝中,以後直接先從緩存中取出數據,不會直接去查資料庫。
  2. 二級緩存:

    • 二級緩存需要手動開啟,他是基於namespce級別的緩存
    • 為了提高拓展性,mybatis定義了緩存介面Cache,我們可以通過該介面自定義二級緩存

12.3、一級緩存

  • 一級緩存也叫本地緩存:SqlSession
    • 在同一個SqlSession之間查詢到的數據會放到本地的緩存中
    • 之後如果想要獲取數據自己從本地緩存中取

測試步驟:

  1. 開啟日誌

    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    
  2. 測試在同一個SqlSession期間查詢相同的數據

  3. 查看日誌輸出

緩存失效的情況:

  1. 查詢不一樣的數據

  2. 增刪改操作,由於可能會改變原來的數據,所有緩存也會失效

  3. 查詢不同的Mapper.xml

  4. 手動清除緩存

    sqlSession.clearCache();
    

  5. 緩存會使用最近最少使用演算法(LRU, Least Recently Used)演算法來清除不需要的緩存。

  6. 緩存不會定時進行刷新(也就是說,沒有刷新間隔)

小結:一級緩存是預設開啟的,也關閉不掉,只能手動清理或者設置,一級緩存其實就相當於一個Map

12.4、二級緩存

  • 二級緩存也叫全局緩存,它的出現是為瞭解決一級緩存的作用域太低
  • 它是基於namespace級別的緩存,一個命名空間,對應一個二級緩存
  • 機制:
    • 一個SqlSession查詢一條數據,這個數據會被放到一級緩存中;
    • 當這個SqlSession斷開的時候,一級緩存就會消失,為了能夠繼續保存,我們就產生了二級緩存
    • 當其他的SqlSession查詢數據時,就可以先從二級緩存中查詢
    • 不同的mapper.xml文件查出的數據會放到自己的緩存(map)之中

測試步驟:

  1. 開啟二級緩存設置;

    <setting name="cacheEnabled" value="true"/>
    <!--註:二級緩存是預設開啟的,但是我們一般會顯示的寫出來-->
    
  2. 在要使用二級緩存的mapper.xml配置文件中開啟緩存:

    <!--直接開啟-->
    <cache/>
    
    <!--當然還可以給緩存設置一些屬性-->
    <cache
      eviction="FIFO"
      flushInterval="60000"
      size="512"
      readOnly="true"/>
    <!--該緩存的
    清除緩存策略:FIFO(最近最少使用)
    刷新間隔:60s
    最多存儲:結果對象或列表的 512 個引用
    返回的對象被認為是只讀的
    -->
    
  3. 測試

小結:

  1. 在使用二級緩存的時候可能會報錯:

    Error serializing object.  Cause: java.io.NotSerializableException
    

    解決:原因是沒有將實體類序列化,所以直接將類序列化即可

  2. 在mapper.xml文件中,對於查找標簽都可以手動設置是否開啟緩存

     useCache="true"
    
  3. 緩存清除的策略:

    • LRU – 最近最少使用:移除最長時間不被使用的對象。
    • FIFO – 先進先出:按對象進入緩存的順序來移除它們。
    • SOFT – 軟引用:基於垃圾回收器狀態和軟引用規則移除對象。
    • WEAK – 弱引用:更積極地基於垃圾收集器狀態和弱引用規則移除對象。
  4. 所有的數據都會先存到一級緩存,只有當會話提交或者關閉才會提交到二級緩存

12.5、緩存原理

12.6、自定義緩存(瞭解)

註:一般可以採用redis來做緩存!!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Java數組 9.稀疏數組 什麼是稀疏數組? 當一個數組中大部分元素為0,或者為同一值的數組時,可以使用稀疏數組來保存該數組。 稀疏數組的處理方式是: 記錄數組一共有幾行幾列,有多少個不同的值 把具有不同值 的元素和行列及值記錄在一個小規模的數組中,從而縮小程式的規模 如下圖:左邊是原始數組,右邊是 ...
  • 線程的生命周期 一、通用的java生命周期 ​ 線程的生命周期通常有五種狀態。這五種狀態分別是:新建狀態、就緒狀態、運行狀態、阻塞狀態和死亡狀態。 **新建狀態:**指的是線程已經被創建,但是還不允許分配 CPU 執行。 就緒狀態: 指的是線程可以分配 CPU 執行。在這種狀態下,真正的操作系統線程 ...
  • LVS+KeepAlived高可用部署實戰 1. 構建高可用集群 1.1 什麼是高可用集群 ​ 高可用集群(High Availability Cluster,簡稱HA Cluster),是指以減少服務中斷時間為目的得伺服器集群技術。它通過保護用戶得業務程式對外部間斷提供的服務,把因為軟體,硬體,認 ...
  • 註:本文所用到的版本 MySql 8.0.28 SpringBoot 2.7.2 準備工作 :建表 、pom.xml導入依賴 、application.yml 配置 建表 CREATE TABLE `rna` ( `id` int NOT NULL AUTO_INCREMENT, `name` va ...
  • NoSQL(Not Only SQL),即反SQL運動或者是不僅僅SQL,指的是非關係型的資料庫,是一項全新的資料庫革命運動,是一種全新的思維註入 NoSQL優點 資料庫高併發讀寫 海量數據高效率存儲和訪問 資料庫高擴展性和高可用性 NoSQL缺點 資料庫事務一致性需求 資料庫的寫實時性和讀實時性需 ...
  • 多線程簡介 1.Process與Thread 程式本身是指定和數據的有序集合,其本身沒有任何運行的含義,是一個靜態的概念。 而進程則是執行程式中的一次執行過程,是一個動態的概念。是系統能夠資源分配的單位。 通常在一個進程里,可以包含若幹個線程,當然一個進程至少有一個線程,不然沒有存在的意義。 線程是 ...
  • 作者:明明如月學長 鏈接:https://juejin.cn/post/7118073840999071751 一、背景 有些業務場景下需要將 Java Bean 轉成 Map 再使用。 本以為很簡單場景,但是坑很多。 二、那些坑 2.0 測試對象 import lombok.Data; impor ...
  • 前言 😋 嗨嘍,大家好呀~這裡是愛看美女的茜茜吶 本次採集網介紹:圖書頻道-全球最大中文網上書店 專業提供小說傳記,青春文學,成功勵志,投資理財等各品類圖書 暢銷榜最新報價、促銷、評論信息,引領最新網上購書體驗! 環境使用 🎈: Python 3.8 Pycharm 模塊使用 🎠: reque ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...