這大概就是公司一直用Mybatis的原因!真的太強了

01 什麼是MyBatis、Spring?MyBatis是什麼?

它是一個SQL Mapping框架,它是一個持久化技術框架。再說得簡單一點,它只不過是一個操作數據庫的框架。Spring是什麼?Spring就是一個大容器,不管是IoC還是AOP,都是以Spring容器爲基礎的,因此,Spring不管整合什麼框架,其關鍵都是利用Spring容器來管理其他框架的核心組件。那麼MyBatis編程的核心組件是什麼?就是以下三個

  • SqlSessionFactory
  • Mapper組件
  • SqlSession

###02 Java EE應用後端各層組件

此外,Java EE應用的後端大致可分爲如圖所示的幾層。

Java EE應用後端分層

Java EE應用後端各層組件的大致功能如下。

DAO(Data Access Object)層:本層組件主要負責操作數據庫,因此各種持久化技術(如MyBatis、JPA等)、索引技術(如Lucene、Solr等)主要集中在該層。

Service層:本層組件主要負責業務邏輯實現,該層組件向下依賴於DAO層的持久化功能,向上對控制器組件提供服務。

控制器層:本層組件主要負責分發、處理請求,該層組件向下依賴於Service層的業務邏輯功能。控制器組件既可對外提供RESTful API接口,也可直接與視圖技術結合生成Web頁面。

Spring框架是一個大容器,它的作用就是負責創建並管理容器中的所有DAO組件、Service組件、控制器組件等,並負責將DAO組件注入Service組件,將Service組件注入控制器組件。

MyBatis實現DAO組件的方式有兩種

  • 傳統的基於SqlSession實現DAO組件。
  • 使用Mapper組件充當DAO組件。

不管採用哪種方式,在整合Spring之後都會將DAO組件納入Spring容器管理之下,併爲DAO組件注入它所依賴的資源。比如基於SqlSession的DAO組件需要依賴SqlSession,而Mapper組件則需要依賴SqlSessionFactory—Spring會負責將SqlSessionFactory或SqlSession注入DAO組件。

此外,既然DAO組件和Service組件都在Spring容器管理之下,那麼Spring容器也會將DAO組件注入Service組件。

歸納起來,在MyBatis整合Spring之後,Spring可爲MyBatis完成如下事情。

  • Spring容器負責管理SqlSessionFactory。
  • Spring容器負責創建、管理Mapper組件或DAO組件。
  • Spring容器負責將Mapper組件或DAO組件注入Service組件。
  • Spring容器負責爲Mapper組件或DAO組件注入所依賴的SqlSessionFactory或SqlSession。
  • Spring的AOP機制還可負責管理Service層的事務。

###03 快速入門Spring與MyBatis的整合示例

在開始整合之前,需要先下載MyBatis與Spring整合的插件,該插件由MyBatis團隊提供(不是由Spring提供的,MyBatis官網提供了一個MyBatis-Spring項目,該項目用於支持MyBatis與Spring的整合。

登錄 鏈接9 站點下載MyBatis-Spring的最新版本,不要下載1.x系列的最新版本(1.x支持Spring 3.2及以上版本和Java 1.6及以上版本),要下載2.x系列(2.x支持Spring 5.0及以上版本和Java 1.8及以上版本),本書下載的是MyBatis-Spring 2.0.2,下載完成後得到一個mybatis-spring-2.0.2.jar文件,它就是MyBatis整合Spring的插件JAR包。

此外,既然要讓Spring整合MyBatis,那麼當然還需要爲項目添加Spring的21個JAR包,以及MyBatis的核心JAR包:mybatis-3.5.2.jar。

接下來按照前面介紹的方式開發Mapper組件:Mapper接口+XML Mapper(或註解)。下面是Mapper接口的代碼。

public interface BookMapper
{
    int saveBook(Book book);

    Book getBook(int id);
}

該Mapper組件對應的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">
<mapper namespace="org.crazyit.app.dao.BookMapper">
    <insert id="saveBook">
        insert into book_inf values(null, #{title}, #{author}, #{price})
    </insert>
    <select id="getBook" resultType="book">
        select book_id id, book_title title, book_author author,
        book_price price from book_inf where book_id=#{id}
    </select>
</mapper>

爲了更好地模擬Java EE應用的架構,本示例也爲應用提供了Service組件(接口+實現類)。下面是BookService接口的代碼。

public interface BookService
{
    int saveBook(Book book);

    Book getBook(int id);
}

可能有讀者感到疑惑:該Service組件內定義的兩個方法與DAO組件內定義的兩個方法是完全相同的嗎?此時確實是這樣的,這是由於本例只是一個演示技術的示例,它不涉及業務邏輯。

對於實際項目而言,Service組件的每個方法應該負責處理、實現一個業務邏輯功能,這個業務邏輯功能通常需要組合調用多個DAO組件的方法—具體來說,比如實現一個轉賬邏輯,該Service方法要調用DAO組件修改轉出賬戶的餘額,還要修改轉入賬戶的餘額,還要調用DAO組件插入一條轉賬記錄。

總之,實現一個業務邏輯方法,通常需要按順序調用多個DAO組件的方法。

本示例的Service組件很簡單,它不涉及任何業務功能,因此它的每個方法只要調用一次DAO組件的方法即可。下面是該Service組件的實現類。

public class BookServiceImpl implements BookService
{
    private BookMapper bookMapper;
    //依賴注入Mapper組件所需的setter方法
    public void setBookMapper(BookMapper bookMapper){
    this.bookMapper = bookMapper;
    }
    @Override
    public int saveBook(Book book) {
        return bookMapper.saveBook(book);
    }
    @Override
    public Book getBook(int id) {
        return bookMapper.getBook(id);
    }
}

該Service組件定義了BookMapper變量代表它所依賴的DAO組件。爲了讓Spring容器爲Service組件注入它所依賴的DAO組件,程序還爲該DAO組件提供了setter方法—如果Service組件需要調用多個DAO組件的方法,就爲每個DAO組件都定義對應的成員變量,並提供setter方法即可。至此,本示例的Mapper組件(DAO組件)和Service組件都已開發完成。

接下來需要將它們配置在Spring容器中,並讓Spring容器來管理它們之間的依賴關係。下面是本示例的Spring配置文件。

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 定義數據源Bean,使用C3P0數據源實現 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close"
p:driverClass="com.mysql.cj.jdbc.Driver"
p:jdbcUrl="jdbc:mysql://localhost:3306/spring?serverTimezone=UTC"
p:user="root"
p:password="32147"/>
<!-- 配置MyBatis的核心組件:SqlSessionFactory,
        併爲該SqlSessionFactory配置它依賴的DataSource,
        還指定將類加載路徑下的mybatis-config.xml文件作爲MyBatis的核心配置文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="dataSource"
p:configLocation="classpath:mybatis-config.xml"/>
<!-- 使用MapperFactoryBean工廠Bean配置Mapper組件,
        併爲該Mapper組件配置它所依賴的SqlSessionFactory -->
<bean id="bookMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"
p:mapperInterface="org.crazyit.app.dao.BookMapper"
p:sqlSessionFactory-ref="sqlSessionFactory"/>
<!-- 配置Service組件,併爲該Service組件配置它所依賴的Mapper組件 -->
<bean id="bookService" class="org.crazyit.app.service.impl.BookServiceImpl"
p:bookMapper-ref="bookMapper"/>
</beans>

上面配置文件中一共配置了4個Bean,其中第一個Bean是一個基於C3P0的數據源Bean,這與前面配置的數據源Bean並沒有任何區別。

第二個Bean是SqlSessionFactoryBean,它是一個工廠Bean,它負責配置MyBatis的核心組件:SqlSessionFactory。

配置SqlSessionFactory爲它注入了兩個屬性:dataSource和configLocation,其中configLocation指定MyBatis的核心配置文件,本示例指定使用類加載路徑下的mybatis-config.xml作爲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>
<typeAliases>
<!-- 爲org.crazyit.app.domain包下的所有類指定別名 -->
<package name="org.crazyit.app.domain"/>
</typeAliases>
</configuration>

將該配置文件與MyBatis獨立應用的mybatis-config.xml進行對比,可以看到該文件主要少了兩個元素:<environments…/>和<mappers…/>—這是由於Spring已爲SqlSessionFactory注入了dataSource(數據源),不再需要配置數據源環境。另外,Spring容器接管了Mapper組件的發現、註冊,也就不需要在mybatis-config.xml文件中配置<mappers…/>元素了。

Spring配置文件中的第三個Bean是Mapper組件(DAO組件),此處使用MapperFactoryBean來配置Mapper組件—所有的Mapper組件都使用該工廠Bean配置,程序獲取該Bean時,實際返回的只是該工廠Bean的產品。

在使用MapperFactoryBean工廠Bean配置Mapper組件時,需要通過mapperInterface指定該Mapper組件的接口,並通過sqlSessionFactory屬性爲Mapper組件注入它所依賴的SqlSessionFactory。

Spring配置文件中的第四個Bean是Service組件,它已經沒有任何特別之處了,就是簡單地配置該Service組件,併爲它注入所依賴的Mapper組件。

接下來,主程序即可獲取Spring容器中配置的Service組件,並調用它的業務方法。

上面程序通過Spring容器獲取了Service組件,並調用了Service組件的方法—Service組件依賴於DAO組件(Mapper組件),而Mapper組件則由MyBatis實現,該程序運行完成後將會看到book_inf表多了一條記錄,並看到程序顯示了id爲1的Book實體的title、price,這說明Spring與MyBatis整合成功。

public class SpringTest {
public static void main(String[] args) throws Exception {
    var ctx = new ClassPathXmlApplicationContext("beans.xml");
    // 獲取容器中的Service組件
    var bookService = ctx.getBean("bookService", BookService.class);
    // 調用Service組件的方法
    bookService.saveBook(new Book(null, "瘋狂Java講義", "李剛", 109.0));
    var b = bookService.getBook(1);
    System.out.println(b.getTitle() + "-->" + b.getPrice());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章