萬字長文!阿里P8技術官手寫Mybatis筆記,看完這篇去手撕面試官!

什么是 MyBatis?

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

使用步驟

1. Maven依賴

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

使用mysql的driver。

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.22</version>
</dependency>

2. XML中構建 SqlSessionFactory

XML 配置文件中包含了對 MyBatis 系統(tǒng)的核心設置,包括獲取數(shù)據(jù)庫連接實例的數(shù)據(jù)源(DataSource)以及決定事務作用域和控制方式的事務管理器(TransactionManager)。

<?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="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
    </mappers>
</configuration>

3. 編寫工具類

這就可以根據(jù)config.xml文件中數(shù)據(jù)庫的連接配置來創(chuàng)建SqlSessionFactory,并編寫提供sqlSession的方法。

public class MybatisUtils {
    private static  SqlSessionFactory sqlSessionFactory;
    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

4. 編寫實體類

根據(jù)數(shù)據(jù)庫中的數(shù)據(jù)編寫。

public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    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;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

5. 編寫DAO層

public interface UserDao {
    List<User> getUserList();
}

原本的JDBC中需要編寫具體的實現(xiàn)類,從而執(zhí)行SQL語句。但是Mybatis通過使用XML定義的方式取代了編寫實現(xiàn)類,并取名為Mapper,其中namespace實現(xiàn)接口綁定,select中的id屬性就是接口中的方法,resultType表示了返回值的類型,就是我們編寫的實體類。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zzy.dao.UserDao">
    <select id="getUserList" resultType="com.zzy.pojo.User">
    select * from mybatis.test
  </select>
</mapper>

此時還需要在Mybatis的config.xml中配置,指定mapper的路徑。


6. 編寫測試類

通過工具類MybatisUtils獲取SqlSession,getmapper執(zhí)行mapper中的配置,相當于構建接口的實現(xiàn)類,最后調用了getUserList,執(zhí)行getUserList方法,返回查詢的結果,最后一定記得將資源關閉。

@Test
public void test() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    List<User> userList = userDao.getUserList();
    for(User user : userList){
        System.out.println(user);
    }
    sqlSession.close();
}

生命周期和作用域

SqlSessionFactoryBuilder

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

SqlSessionFactory

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

SqlSession

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

try (SqlSession session = sqlSessionFactory.openSession()) {  
// 你的應用邏輯代碼
}

如果不及時關閉,會造成大量的資源浪費。


映射器實例

映射器是一些綁定映射語句的接口。映射器接口的實例是從 SqlSession 中獲得的。雖然從技術層面上來講,任何映射器實例的最大作用域與請求它們的 SqlSession 相同。但方法作用域才是映射器實例的最合適的作用域。 也就是說,映射器實例應該在調用它們的方法中被獲取,使用完畢之后即可丟棄。 映射器實例并不需要被顯式地關閉。盡管在整個請求作用域保留映射器實例不會有什么問題,但是你很快會發(fā)現(xiàn),在這個作用域上管理太多像 SqlSession 的資源會讓你忙不過來。 因此,最好將映射器放在方法作用域內。就像下面的例子一樣:

try (SqlSession session = sqlSessionFactory.openSession()) {  BlogMapper mapper = session.getMapper(BlogMapper.class);  
// 你的應用邏輯代碼
}

XML配置

enviroments

mybatis可以配置多種環(huán)境,這種機制有助于SQL映射到多種數(shù)據(jù)庫中, 現(xiàn)實情況下有多種理由需要這么做。例如,開發(fā)、測試和生產(chǎn)環(huán)境需要有不同的配置;或者想在具有相同 Schema 的多個生產(chǎn)數(shù)據(jù)庫中使用相同的 SQL 映射。還有許多類似的使用場景。

但是每個sqlsessionfactory只能對應一個環(huán)境,而每個數(shù)據(jù)庫對應一個sqlsessionfactory。

為了指定創(chuàng)建哪種環(huán)境,只要將它作為可選的參數(shù)傳遞給 SqlSessionFactoryBuilder 即可??梢越邮墉h(huán)境配置的兩個方法簽名是:

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);

如果沒有寫明指定的環(huán)境,就會使用默認環(huán)境,default=環(huán)境id,就是默認的環(huán)境。

事務管理器(transactionManager)

在 MyBatis 中有兩種類型的事務管理器(也就是 type="[JDBC|MANAGED]")

● JDBC – 這個配置直接使用了 JDBC 的提交和回滾設施,它依賴從數(shù)據(jù)源獲得的連接來管理事務作用域。
● MANAGED – 這個配置幾乎沒做什么。它從不提交或回滾一個連接,而是讓容器來管理事務的整個生命周期(比如 JEE 應用服務器的上下文)。 默認情況下它會關閉連接。然而一些容器并不希望連接被關閉,因此需要將 closeConnection 屬性設置為 false 來阻止默認的關閉行為。例如:

<transactionManager type="MANAGED">  
<property name="closeConnection" value="false"/>
</transactionManager>

數(shù)據(jù)源(dataSource)

dataSource 元素使用標準的 JDBC 數(shù)據(jù)源接口來配置 JDBC 連接對象的資源。

有三種內建的數(shù)據(jù)源類型(也就是 type="[UNPOOLED|POOLED|JNDI]"):

  • UNPOOLED–這個數(shù)據(jù)源的實現(xiàn)會每次請求時打開和關閉連接。雖然有點慢,但對那些數(shù)據(jù)庫連接可用性要求不高的簡單應用程序來說,是一個很好的選擇。
  • POOLED– 這種數(shù)據(jù)源的實現(xiàn)利用“池”的概念將 JDBC 連接對象組織起來,避免了創(chuàng)建新的連接實例時所必需的初始化和認證時間。這種處理方式很流行,能使并發(fā) Web 應用快速響應請求。
  • JNDI – 這個數(shù)據(jù)源實現(xiàn)是為了能在如 EJB或應用服務器這類容器中使用,容器可以集中或在外部配置數(shù)據(jù)源,然后放置一個 JNDI 上下文的數(shù)據(jù)源引用。

屬性(properties)

property可以通過編寫.properties文件來配置,或者直接在environment中聲明,如果使用.properties就需要在properties的resource中指明路徑,然后在環(huán)境中使用properties時,使用如下形式,${}里面對應的就是.properties文件中屬性名。


如果同時.properties和在xml文件配置,那么就會優(yōu)先使用.properties。

類型別名(typeAliases)

類型別名可為 Java 類型設置一個縮寫名字。 它僅用于 XML 配置,意在降低冗余的全限定類名書寫。兩種聲明方式:


給每一個類起一個具體的別名,這種方式的好處是可以自己指定。


掃描包下的類,自動給類起別名,別名默認為這個類的首字母小寫的名字。比如com.blog.User的別名為user,可以在類上添加Alias注解也可以實現(xiàn)自定義別名。

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

設置(settings)

這是 MyBatis 中極為重要的調整設置,它們會改變 MyBatis 的運行時行為。 下表描述了設置中各項設置的含義、默認值等。

主要掌握:


log4j

Log4j是Apache的一個開源項目,通過使用Log4j,我們可以控制日志信息輸送的目的地是控制臺、文件、GUI組件,甚至是套接口服務器、NT的事件記錄器、UNIX Syslog守護進程等;我們也可以控制每一條日志的輸出格式;通過定義每一條日志信息的級別,我們能夠更加細致地控制日志的生成過程。最令人感興趣的就是,這些可以通過一個配置文件來靈活地進行配置,而不需要修改應用的代碼。

使用步驟:
第一步:在maven中導入jar包

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

第二步:編寫log4j.properties文件

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/zzy.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{yy-MM-dd}][%c]%m%n

log4j.appender.org.mybatis=DEBUG
log4j.appender.java.sql=DEBUG
log4j.appender.java.sql.Statement=DEBUG
log4j.appender.java.sql.ResultSet=DEBUG
log4j.appender.java.sql.PreparedStatement=DEBUG

第三步:配置


注意要完全一樣,大小寫、空格等不同都會導致錯誤。

第四步:獲取當前使用類的對象。

static Logger logger = Logger.getLogger(xxx.class);

效果:


映射器(mappers)

既然 MyBatis 的行為已經(jīng)由上述元素配置完了,我們現(xiàn)在就要來定義 SQL 映射語句了。 但首先,我們需要告訴 MyBatis 到哪里去找到這些語句。


XML映射文件

參數(shù)映射

鑒于參數(shù)類型(parameterType)會被自動設置為int,這個參數(shù)可以隨意命名。

如果 User 類型的參數(shù)對象傳遞到了語句中,會查找 id、username 和 password 屬性,然后將它們的值傳入預處理語句的參數(shù)中。

<insert id="insertUser" parameterType="User">  
insert into users (id, username, password)  
values (#{id}, #{username}, #{password})
</insert>

提示 :JDBC 要求,如果一個列允許使用 null 值,并且會使用值為 null 的參數(shù),就必須要指定 JDBC 類型(jdbcType)。

盡管上面這些選項很強大,但大多時候,你只須簡單指定屬性名,頂多要為可能為空的列指定jdbcType,其他的事情交給 MyBatis 自己去推斷就行了。

#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}

使用@Param 可以指定mapper接收的參數(shù)名。

@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column,
@Param("value") String value);

結果映射

MyBatis 的真正強大在于它的語句映射,這是它的魔力所在。由于它的異常強大,映射器的 XML 文件就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 代碼進行對比,你會立即發(fā)現(xiàn)省掉了將近 95% 的代碼。MyBatis 致力于減少使用成本,讓用戶能更專注于SQL代碼。


在這里插入圖片描述

resultMap

resultmap元素是 MyBatis 中最重要最強大的元素。它可以讓你從 90% 的 JDBC resultset數(shù)據(jù)提取代碼中解放出來,并在一些情形下允許你進行一些 JDBC 不支持的操作。實際上,在為一些比如連接的復雜語句編寫映射代碼的時候,一份 resultmap 能夠代替實現(xiàn)同等功能的數(shù)千行代碼。ResultMap 的設計思想是,對簡單的語句做到零配置,對于復雜一點的語句,只需要描述語句之間的關系就行了。

<select id="selectUsers" resultMap="userResultMap">  
select user_id, user_name, hashed_password  from some_table  where id = #{id}
</select>

<resultMap id="userResultMap" type="User">  
<id property="id" column="user_id" />  
<result property="username" column="user_name"/>  
<result property="password" column="hashed_password"/>
</resultMap>

ResultMap的優(yōu)秀之處——你完全可以不用顯式地配置它們,當實體類的屬性名和數(shù)據(jù)庫的列名一樣時,就完全不需要使用(自動映射),只需要在不相同的時候配置即可。

動態(tài)SQL

if

使用動態(tài) SQL 最常見情景是根據(jù)條件包含 where 子句的一部分。比如:

<select id="findActiveBlogWithTitleLike" resultType="Blog">  SELECT * FROM BLOG  WHERE state = ‘ACTIVE’  
    <if test="title != null">    
      AND title like #{title}  
    </if>
</select>

如果希望通過 “title” 和 “author” 兩個參數(shù)進行可選搜索該怎么辦呢?首先,我想先將語句名稱修改成更名副其實的名稱;接下來,只需要加入另一個條件即可。

<select id="findActiveBlogLike" resultType="Blog">  
SELECT * FROM BLOG WHERE state = ‘ACTIVE’  
   <if test="title != null">    
   AND title like #{title}  
   </if>  
   <if test="author != null and author.name != null">    
   AND author_name like #{author.name}  
   </if>
</select>

choose、when、otherwise

有時候,我們不想使用所有的條件,而只是想從多個條件中選擇一個使用。針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。

<select id="findActiveBlogLike" resultType="Blog">  
SELECT * FROM BLOG WHERE state = ‘ACTIVE’  
<choose>    
   <when test="title != null">      
   AND title like #{title}    
   </when>    
   <when test="author != null and author.name != null"> 
   AND author_name like #{author.name}    
   </when>    
   <otherwise>      
   AND featured = 1    
   </otherwise>  
</choose>
</select>

trim、where、set

現(xiàn)在看下面這個列子,當沒有一個匹配時,sql就為:select * from blog where;這種顯然時錯誤的語句,那么如果第二個語句成立時,語句變?yōu)椋簊elect * from blog where and title like #{title};顯然也是錯誤的語句。

<select id="findActiveBlogLike" resultType="Blog">  
SELECT * FROM BLOG  WHERE  
    <if test="state != null">    
    state = #{state}  
    </if>  
    <if test="title != null">    
    AND title like #{title}  
    </if>  
    <if test="author != null and author.name != null">    
    AND author_name like #{author.name}  
    </if>
</select>

MyBatis 有一個簡單且適合大多數(shù)場景的解決辦法。而在其他場景中,可以對其進行自定義以符合需求。而這,只需要一處簡單的改動:

<select id="findActiveBlogLike" resultType="Blog">  
SELECT * FROM BLOG  
<where>    
   <if test="state != null">         
   state = #{state}    
   </if>    
   <if test="title != null">        
   AND title like #{title}    
   </if>    
   <if test="author != null and author.name != null">        
   AND author_name like #{author.name}    
   </if> 
</where>
</select>

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

如果 where 元素與你期望的不太一樣,你也可以通過自定義 trim 元素來定制 where 元素的功能。比如,和 where 元素等價的自定義 trim 元素為:

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

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

用于動態(tài)更新語句的類似解決方案叫做 set。set 元素可以用于動態(tài)包含需要更新的列,忽略其它不更新的列。比如:

<update id="updateAuthorIfNecessary">  
update Author    
<set>      
  <if test="username != null">username=#{username},
  </if>      
  <if test="password != null">password=#{password},
  </if>      
  <if test="email != null">email=#{email},
  </if>      
  <if test="bio != null">bio=#{bio}
  </if>    
</set>  
where id=#{id}
</update>

這個例子中,set 元素會動態(tài)地在行首插入 SET 關鍵字,并會刪掉額外的逗號(這些逗號是在使用條件語句給列賦值時引入的)。

來看看與 set 元素等價的自定義 trim 元素吧:

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

foreach

動態(tài) SQL 的另一個常見使用場景是對集合進行遍歷(尤其是在構建 IN 條件語句的時候)。比如:

<select id="selectPostIn" resultType="domain.blog.Post">  SELECT *  FROM POST P WHERE ID in  
<foreach item="item" index="index" collection="list"     open="(" separator="," close=")">  

   #{item}  

</foreach>
</select>

foreach 元素的功能非常強大,它允許你指定一個集合,聲明可以在元素體內使用的集合項(item)和索引(index)變量。它也允許你指定開頭與結尾的字符串以及集合項迭代之間的分隔符。這個元素也不會錯誤地添加多余的分隔符,看它多智能!

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

bind

<select id="selectBlogsLike" resultType="Blog">  
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />  
SELECT * FROM BLOG  WHERE title LIKE #{pattern}
</select>

緩存

基本概念

MyBatis 內置了一個強大的事務性查詢緩存機制,它可以非常方便地配置和定制。 為了使它更加強大而且易于配置,我們對 MyBatis 3 中的緩存實現(xiàn)進行了許多改進。

默認情況下,只啟用了本地的會話緩存,它僅僅對一個會話中的數(shù)據(jù)進行緩存。 要啟用全局的二級緩存,只需要在你的 SQL 映射文件中添加一行:

<cache/>

同時還需要在settings中聲明cacheEnable,雖然是默認為true的。

基本上就是這樣。這個簡單語句的效果如下:

  • 映射語句文件中的所有 select 語句的結果將會被緩存。
  • 映射語句文件中的所有 insert、update 和 delete語句會刷新緩存。
  • 緩存會使用最近最少使用算法(LRU, Least Recently Used)算法來清除不需要的緩存。
  • 緩存不會定時進行刷新(也就是說,沒有刷新間隔)。
  • 緩存會保存列表或對象(無論查詢方法返回哪種)的 1024 個引用。
  • 緩存會被視為讀/寫緩存,這意味著獲取到的對象并不是共享的,可以安全地被調用者修改,而不干擾其他調用者或線程所做的潛在修改。

提示:緩存只作用于 cache 標簽所在的映射文件中的語句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的語句將不會被默認緩存。你需要使用 @CacheNamespaceRef 注解指定緩存作用域。

這些屬性可以通過 cache 元素的屬性來修改。

<cache  eviction="FIFO"  flushInterval="60000"  size="512"  readOnly="true"/>

這個更高級的配置創(chuàng)建了一個 FIFO 緩存,每隔 60 秒刷新,最多可以存儲結果對象或列表的 512 個引用,而且返回的對象被認為是只讀的,因此對它們進行修改可能會在不同線程中的調用者產(chǎn)生沖突。

可用的清除策略有:


默認的清除策略是 LRU。

flushInterval(刷新間隔)屬性可以被設置為任意的正整數(shù),設置的值應該是一個以毫秒為單位的合理時間量。 默認情況是不設置,也就是沒有刷新間隔,緩存僅僅會在調用語句時刷新。

size(引用數(shù)目)屬性可以被設置為任意正整數(shù),要注意欲緩存對象的大小和運行環(huán)境中可用的內存資源。默認值是 1024。

readOnly(只讀)屬性可以被設置為 true 或 false。只讀的緩存會給所有調用者返回緩存對象的相同實例。 因此這些對象不能被修改。這就提供了可觀的性能提升。而可讀寫的緩存會(通過序列化)返回緩存對象的拷貝。 速度上會慢一些,但是更安全,因此默認值是 false。

工作流程

二級緩存臟讀

由于二級緩存作用于namesace級別,也就是說不同mapper有自己獨立一套的緩存,那么當不同mapper對同一表進行操作時,就會出現(xiàn)臟讀。

比如mapper A 查詢了 M 表 ,然后mapper B 對 M表修改并提交事務,只要mapper A這段時間內沒有執(zhí)行update、delete、insert操作,mapper A的緩存就不會被刷新,當mapper A再次select時,由于Mybatis緩存工作機制,會先從二級緩存中拿取數(shù)據(jù),此時mapper A select出的數(shù)據(jù)就是臟數(shù)據(jù)。

因此在開啟二級緩存后,所有的對同一表的增刪改查應該在同一mapper下。

Mybatis執(zhí)行流程

  1. resource讀取配置文件


  2. 解析配置文件流XML


  3. Configuration


  4. 實列化SqlSessionFactory


  5. transactionManager


  6. executor


  7. 創(chuàng)建SqlSession


  8. 實現(xiàn)CRUD


結語

感謝你看到這里,文章有什么不足還請指正,覺得文章對你有幫助的話記得給我點個贊,每天都會分享java相關技術文章或行業(yè)資訊,歡迎大家關注和轉發(fā)文章!

歡迎關注公眾號:前程有光,領取一線大廠Java面試題總結+各知識點學習思維導+一份300頁pdf文檔的Java核心知識點總結!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容