MyBatis原理總結(代碼實現流程)


我們在實際開發中,越簡單越好,所以都是采用不寫Dao實現類的方式。不管是使用xml還是直接配置。

但是MyBatis是支持寫Dao實現類的

 注意sqlSession是這里面的一個靈魂,有很多執行api

 

目錄結構:

 

 方法:

/**
 * 用戶的持久層接口
 */
public interface IUserDao {
    List<User> findAll();
}

實現類:

public class UserDaoImpl implements IUserDao {

    private SqlSessionFactory factory;
    //覆蓋掉默認構造函數,這樣就有了工廠,可以進一步創建對象
    public UserDaoImpl(SqlSessionFactory factory){
        this.factory = factory;
    }
    @Override
    public List<User> findAll() {
        //1.使用工廠創建SqlSession對象
        SqlSession sqlSession = factory.openSession();
        //2.使用sqlSession執行查詢所有方法(此處需要的參數:(String statement)從配置文件中獲取) namespace + id
        List<User> userList = sqlSession.selectList("com.toov5.dao.IUserDao.findAll");
        //使用完后關閉掉
        sqlSession.close();
        return userList;
    }
}

實體類:

public class User implements Serializable {
  private Integer id;
  private String username;
  private Date birthday;
  private String sex;
  private String address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

 

全局配置文件:

<?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="mysql">
        <!-- 配置mysql的環境-->
        <environment id="mysql">
            <!-- 配置事務的類型-->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置數據源(也叫連接池) -->
            <dataSource type="POOLED">
                <!-- 配置連接數據庫的4個基本信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 指定映射配置文件的位置,映射配置文件指的是每個dao獨立的配置文件 -->
    <mappers>
        <!--resource目錄下 對應要創建相應的包 -->
        <mapper resource="com/toov5/dao/IUserDao.xml"/>
    </mappers>
</configuration>

 

映射文件:

 

<?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.toov5.dao.IUserDao">
<!--查詢所有-->
<select id="findAll" resultType="com.toov5.entity.User">
        select * from  user;
    </select>
</mapper>

 

測試類:

/**
 * MyBatis測試類
 */
public class MyBatisTest {
    public static void main(String[] args) throws IOException {
        //1.讀取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2. 創建SqlSessonFactory工廠
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //如何解析,如何封裝已經底層幫助實現了。細節封裝了。
        SqlSessionFactory factory = builder.build(in);
       // SqlSessionFactory 是個接口,需要找實現。這個工廠是用來創建對象的,創建過程省略了
        //3. 使用工廠生產SqlSession對象
        SqlSession sqlSession = factory.openSession();
        //不需要代理類了,SqlSession 是有查詢方法的.使用工廠創建Dao對象,傳入工廠
        IUserDao userDao = new UserDaoImpl(factory);
        //5.使用代理對象執行方法
        List<User> userList = userDao.findAll();
        userList.stream().forEach(
                user ->{
                    System.out.println(user);
                }
        );
        //6.釋放資源
        in.close();
    }
}

 

Mybatis在用動態代理dao方式時候,也是找到對應的sql語句的。

執行結果,一模一樣。

 

 

引申


 

 補充,對於絕對路徑和相對路徑,絕對路徑不准確,采用相對路徑。  

  相對路徑有兩種方案可以獲得。 1. 類加載器,只能讀取類路徑的配置文件     2. 使用ServletContext對象的getRealPath()

 

創建工廠,采用了構建這模式。隱藏了創建細節。使用戶直接調用方法就可以拿到對象了

使用工廠模式生產SqlSession。降低類間的依賴,解耦合。

創建dao接口實現類使用了代理模式。不修改源碼基礎上對已有的方法增強。

 

MyBatis原理分析:

MyBatis在使用代理Dao的方式實現增刪改查時候,做的什么事呢?

 兩件事: 

   一: 創建對象

   二: 在代理對象中調用selectList

 

從一開始就需要解析配置文件,

進而做如下操作:

 1. 根據配置文件的信息創建Connection對象,注冊驅動,獲取連接

 2. 獲取預處理對象PreparedStatement,此時需要SQL語句。 com.prepareStatement(sql)

 3. 執行查詢 ResultSet resultSet = preparedStatement.executeQuery();

 4.遍歷結果用於封裝

   List<E> list = new ArrayList();

  while(resultSet.next()){

     E element = xxx;   // 可以通過反射后去 class.forName("配置的全限定類名").newInstance();   使用反射封裝

 //  進行封裝。把每個rs的內容都添加到element中,把element加入到list中

   list.add(element);

  }

於是我們就可以把表的列名看成是實體類的屬性名稱,就可以使用反射的方式來根據名稱獲取每個屬性。

5.返回結果

 

綜上所述: 需要提供方法兩個信息

1. 連接信息

2. 映射信息,包含兩部分:  執行的sql語句; 封裝結果的實體類全限定類名。這兩個信息作為屬性定義對象。

     String  key  : nameSpace+id

     Mapper value :  String的sql語句    方法的全類名

通過方法:

 session.getMapper(IUserDao.class) 實現了代理對象的創建

 根據dao接口的字節碼創建到的代理對象

public <T> getMapper(Class<T> daoInterfaceClass){

}

使用的的參數是 : 類加載器(與被代理對象使用相同的類加載器), Class數組:代理對象要實現接口的字節碼數組, 如何代理(Handler)

Proxy.newProxyInstance()

此方法的封裝:

 s1.類加載器: 它使用的和被代理對象是相同的類加載器

 s2.代理對象要實現的接口: 和被代理對象實現相同的接口

 s3.如何代理: 它就是增強的方法,我們需要自己來提供

       此處是一個InvocationHandler的接口,我們需要寫一個該接口的實現類

       調用該類的selectList方法

 

 自定義MyBatis能通過入門案例看到的類:

  class Resources

  class SqlSessionFactoryBuilder

  interface SqlSessionFactory

 

 此時的pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.test</groupId>
    <artifactId>mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--<dependency>-->
            <!--<groupId>org.mybatis</groupId>-->
            <!--<artifactId>mybatis</artifactId>-->
            <!--<version>3.4.5</version>-->
        <!--</dependency>-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

 構建者構建工廠,工廠生產SqlSession。SqlSession可以做的事情很多。

 總結:讀取配置文件io流,解析出我們要的信息,交給構建者,構建者使用工具類,構建了工廠對象,工廠的openSession方法提供了sqlSession對象,sqlSession去干活。

下圖信息量很大:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM