MyBatis 與 Spring 整合

MyBatis—Spring 項(xiàng)目

目前大部分的 Java 互聯(lián)網(wǎng)項(xiàng)目,都是用 Spring MVC + Spring + MyBatis 搭建平臺(tái)的。

使用 Spring IoC 可以有效的管理各類的 Java 資源,達(dá)到即插即拔的功能;通過 Spring AOP 框架,數(shù)據(jù)庫(kù)事務(wù)可以委托給 Spring 管理,消除很大一部分的事務(wù)代碼,配合 MyBatis 的高靈活、可配置、可優(yōu)化 SQL 等特性,完全可以構(gòu)建高性能的大型網(wǎng)站。

毫無(wú)疑問,MyBatis 和 Spring 兩大框架已經(jīng)成了 Java 互聯(lián)網(wǎng)技術(shù)主流框架組合,它們經(jīng)受住了大數(shù)據(jù)量和大批量請(qǐng)求的考驗(yàn),在互聯(lián)網(wǎng)系統(tǒng)中得到了廣泛的應(yīng)用。使用 MyBatis-Spring 使得業(yè)務(wù)層和模型層得到了更好的分離,與此同時(shí),在 Spring 環(huán)境中使用 MyBatis 也更加簡(jiǎn)單,節(jié)省了不少代碼,甚至可以不用 SqlSessionFactory、 SqlSession 等對(duì)象,因?yàn)?MyBatis-Spring 為我們封裝了它們。

摘自:《Java EE 互聯(lián)網(wǎng)輕量級(jí)框架整合開發(fā)》

第一步:創(chuàng)建測(cè)試工程

第一步,首先在 IDEA 中新建一個(gè)名為【MybatisAndSpring】的 WebProject 工程:

然后在【src】中創(chuàng)建 4 個(gè)空包:

  • cn.wmyskxz.dao(放置 DAO 數(shù)據(jù)交互層處理類)
  • cn.wmyskxz.mapper(放置 Mapper 代理接口)
  • cn.wmyskxz.pojo(放置 Java 實(shí)體類)
  • cn.wmyskxz.test(放置測(cè)試類)

接著新建源文件夾【config】,用于放置各種資源配置文件:

  • 在【config / mybatis】下創(chuàng)建一個(gè)空的名為 “SqlMapConfig.xml” 的 MyBatis 全局配置文件
  • 在【config / spring】下創(chuàng)建一個(gè)空的名為 “applicationContext.xml” 的 Spring 資源配置文件
  • 在【config / sqlmap】下創(chuàng)建一個(gè)空的名為 “UserMapper.xml” 的 Mapper 映射文件。
  • 在【config】下創(chuàng)建兩個(gè) properties 屬性文件,分別為 “db.properties” 和 “l(fā)og4j.properties”,用于數(shù)據(jù)庫(kù)連接和日志系統(tǒng)參數(shù)設(shè)置。

再在【web】文件夾下新建一個(gè)【W(wǎng)EB-INF】默認(rèn)安全文件夾,并在其下創(chuàng)建一個(gè)【classes】和【lib】,并將項(xiàng)目的輸出位置,改在【classes】下:

工程的完整初始結(jié)構(gòu)如下:

第二步:引入依賴 jar 包

第二步,就是要準(zhǔn)備項(xiàng)目的依賴 jar 包:

在【W(wǎng)EB-INF】文件夾下的【lib】文件夾中放置上面列舉的 jar 包,然后添加依賴。

第三步:編寫 Spring 配置文件

第三步,編寫 Spring 的配置文件:

  • 加載數(shù)據(jù)庫(kù)連接文件 “db.properties” 中的數(shù)據(jù),建立數(shù)據(jù)源
  • 配置 sqlSessionFactory 會(huì)話工廠對(duì)象
<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 加載配置文件 -->
    <context:property-placeholder location="classpath:db.properties"/>

    <!-- 配置數(shù)據(jù)源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- sqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 加載 MyBatis 的配置文件 -->
        <property name="configLocation" value="mybatis/SqlMapConfig.xml"/>
        <!-- 數(shù)據(jù)源 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>
  • 頭部的信息就是聲明 xml 文檔配置標(biāo)簽的規(guī)則的限制與規(guī)范。
  • “context:property-placeholder” 配置是用于讀取工程中的靜態(tài)屬性文件,然后在其他配置中使用時(shí),就可以采用 “${屬性名}” 的方式獲取該屬性文件中的配置參數(shù)值。
  • 配置了一個(gè)名為 “dataSrouce” 的 bean 的信息,實(shí)際上是連接數(shù)據(jù)庫(kù)的數(shù)據(jù)源。
  • 設(shè)置 sqlSessionFactory 的 bean 實(shí)現(xiàn)類為 MyBatis 與 Spring 整合 jar 包中的 SqlSessionFactoryBean 類,在其中只需要注入兩個(gè)參數(shù):一個(gè)是 MyBatis 的全局配置文件,一個(gè)是上面配置的數(shù)據(jù)源 bean

第四步:編寫 MyBatis 配置文件

第四步,在【mybatis】包下編寫 MyBatis 的全局配置文件 SqlMapConfig.xml :

<?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>

    <!-- settings -->
    <settings>
        <!-- 打開延遲加載的開關(guān) -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 將積極加載改為消極加載(即按需加載) -->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!-- 打開全局緩存開關(guān)(二級(jí)緩存)默認(rèn)值就是 true -->
        <setting name="cacheEnabled" value="true"/>
    </settings>

    <!-- 別名定義 -->
    <typeAliases>
        <package name="cn.wmyskxz.pojo"/>
    </typeAliases>

    <!-- 加載映射文件 -->
    <mappers>
        <!-- 通過 resource 方法一次加載一個(gè)映射文件 -->
        <mapper resource="sqlmap/UserMapper.xml"/>
        <!-- 批量加載mapper -->
        <package name="cn.wmyskxz.mapper"/>
    </mappers>
</configuration>

在該配置文件中:

  • 通過 settings 配置了一些延遲加載和緩存的開關(guān)信息
  • typeAliases 中設(shè)置了一個(gè) package 的別名掃描路徑,在該路徑下的 Java 實(shí)體類都可以擁有一個(gè)別名(即首字母小寫的類名)
  • 在 mappers 配置中,使用 mapper 標(biāo)簽配置了即將要加載的 Mapper 映射文件的資源路徑,當(dāng)然也可以使用 package 標(biāo)簽,配置 mapper 代理接口所在的包名,以批量加載 mapper 代理對(duì)象。
  • 注意: 有了 Spring 托管數(shù)據(jù)源,在 MyBatis 配置文件中僅僅需要關(guān)注性能化配置。

第五步:編寫 Mapper 以及其他配置文件

第五步,編寫 Mapper 映射文件,這里依然定義 Mapper 映射文件的名字為 “UserMapper.xml” (與 SqlMapConfig.xml 中配置一致),為了測(cè)試效果,只配置了一個(gè)查詢類 SQL 映射:

<?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="test">
    <select id="findUserById" parameterType="_int" resultType="user">
    SELECT * FROM USER WHERE id = #{id}
</select>
</mapper>

在該配置中,輸出參數(shù)的映射為 “user” ,這是因?yàn)橹霸?SqlMapConfig.xml 中配置了 “cn.wmyskxz.pojo” 包下的實(shí)體類使用別名(即首字母小寫的類名),所以這里只需在 “cn.wmyskxz.pojo” 包下,創(chuàng)建 “finduserById” 對(duì)應(yīng)的 Java 實(shí)體類 User:

package cn.wmyskxz.pojo;

import java.io.Serializable;

public class User implements Serializable {
    private int id;
    private String username;

    /* getter and setter */
}
  • 實(shí)現(xiàn) Serializable 接口是為之后使用 Mapper 動(dòng)態(tài)代理做準(zhǔn)備,這里沒有使用動(dòng)態(tài)代理。

在數(shù)據(jù)庫(kù)資源 “db.properties” 中配置了數(shù)據(jù)庫(kù)的連接信息,以 “key=value” 的形式配置,String 正是使用 “${}” 獲取其中 key 對(duì)應(yīng)的 value 配置的:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root

另外日志配置和之前的配置一樣,我就直接黏貼了:

# Global logging configuration
# 在開發(fā)環(huán)境下日志級(jí)別要設(shè)置成 DEBUG ,生產(chǎn)環(huán)境設(shè)為 INFO 或 ERROR
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

第六步:編寫 DAO 層

第六步,進(jìn)行數(shù)據(jù)庫(kù)交互(Data Access Object)層的編寫。

由于該項(xiàng)目只對(duì) User 用戶查詢,所以 DAO 層就只有一個(gè)類,在 “cn.wmyskxz” 包下創(chuàng)建 DAO 層的 interface 接口,其中定義了 findUserById 方法,參數(shù)為用戶的 id 值(int 類型):

package cn.wmyskxz.dao;

import cn.wmyskxz.pojo.User;

public interface UserDAO {

    // 根據(jù) id 查詢用戶信息
    public User findUserById(int id) throws Exception;
}

然后在同一個(gè)包下創(chuàng)建 UserDAO 接口的實(shí)現(xiàn)類 UserDAOImpl:

package cn.wmyskxz.dao;

import cn.wmyskxz.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;

public class UserDAOImpl extends SqlSessionDaoSupport implements UserDAO {

    @Override
    public User findUserById(int id) throws Exception {
        // 繼承 SqlSessionDaoSupport 類,通過 this.getSqlSession() 得到 sqlSession
        SqlSession sqlSession = this.getSqlSession();
        User user = sqlSession.selectOne("test.findUserById", id);
        return user;
    }
}
  • 有幾點(diǎn)解釋:
  • UserDAOImpl 不僅實(shí)現(xiàn)了 UserDAO 接口,而且繼承了 SqlSessionDaoSupport 類。
  • SqlSessionDaoSupport 類是 MyBatis 與 Spring 整合的 jar 包中提供的,在該類中已經(jīng)包含了 sqlSessionFactory 對(duì)象作為其成員變量,而且對(duì)外提供 get 和 set 方法,方便 Spring 從外部注入 sqlSessionFactory 對(duì)象。
  • UserDAOImpl 類要成功獲取 sqlSessionFactory 對(duì)象,還需要在 Spring 配置文件 applicationContext.xml 中添加 userDAO 的 bean 配置,將其中定義的 sqlSessionFactory 對(duì)象當(dāng)做參數(shù)注入進(jìn)去,這樣 UserDAOImpl 繼承 SqlSessionDaoSupport 類才會(huì)起到作用:
<!-- 原始 DAO 接口 -->
<bean id="userDAO" class="cn.wmyskxz.dao.UserDAOImpl">
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
  • 注意: DAO 實(shí)現(xiàn)類繼承了 SqlSessionDaoSupport 父類后,就無(wú)須自己定義獲取 SqlSession 會(huì)話實(shí)例類方法了,該父類會(huì)默認(rèn)加載數(shù)據(jù)源信息并提供獲取 SqlSession 類的方法。

第七步:編寫 Service 測(cè)試類

在 “cn.wmyskxz.test” 包下創(chuàng)建【UserServiceTest】測(cè)試類:

package cn.wmyskxz.test;

import cn.wmyskxz.dao.UserDAO;
import cn.wmyskxz.pojo.User;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserServiceTest {

    private ApplicationContext applicationContext;

    // 在執(zhí)行測(cè)試方法之前首先獲取 Spring 配置文件對(duì)象
    // 注解@Before在執(zhí)行本類所有測(cè)試方法之前先調(diào)用這個(gè)方法
    @Before
    public void setup() throws Exception {
        applicationContext = new
                ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
    }

    @Test
    public void testFindUserById() throws Exception {
        // 通過配置資源對(duì)象獲取 userDAO 對(duì)象
        UserDAO userDAO = (UserDAO) applicationContext.getBean("userDAO");
        // 調(diào)用 UserDAO 的方法
        User user = userDAO.findUserById(1);
        // 輸出用戶信息
        System.out.println(user.getId() + ":" + user.getUsername());
    }
}

運(yùn)行測(cè)試方法,輸出結(jié)果如下:


動(dòng)態(tài)代理 + 注解實(shí)現(xiàn)

上面的實(shí)例程序并沒有使用 Mapper 動(dòng)態(tài)代理和注解來(lái)完成,下面我們就來(lái)試試如何用動(dòng)態(tài)代理和注解:

第一步:編寫 UserQueryMapper

在【mapper】下新建一個(gè)【UserQueryMapper】代理接口,并使用注解:

package cn.wmyskxz.mapper;

import cn.wmyskxz.pojo.User;
import org.apache.ibatis.annotations.Select;

public interface UserQueryMapper {

    @Select("SELECT * FROM USER WHERE id = #{id}")
    public User findUserById(int id) throws Exception;
}
  • 注意: 在默認(rèn)情況下,該 bean 的名字為 userQueryMapper(即首字母小寫)

現(xiàn)在有了代理類,我們需要通知 Spring 在這里來(lái)掃描到該類,Mapper 掃描配置對(duì)象需要用專門的掃描器:

<!-- Mapper 掃描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 掃描 cn.wmyskxz.mapper 包下的組件 -->
    <property name="basePackage" value="cn.wmyskxz.mapper"/>
</bean>

第二步:編寫測(cè)試類

這一次我們獲取的不再是 userDAO 對(duì)象,而是定義的 Mapper 代理對(duì)象 userQueryMapper:

package cn.wmyskxz.test;

import cn.wmyskxz.mapper.UserQueryMapper;
import cn.wmyskxz.pojo.User;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserServiceTest {

    private ApplicationContext applicationContext;

    // 在執(zhí)行測(cè)試方法之前首先獲取 Spring 配置文件對(duì)象
    // 注解@Before在執(zhí)行本類所有測(cè)試方法之前先調(diào)用這個(gè)方法
    @Before
    public void setup() throws Exception {
        applicationContext = new
                ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
    }

    @Test
    public void testFindUserById() throws Exception {
        // 通過配置資源對(duì)象獲取 userDAO 對(duì)象
        UserQueryMapper userQueryMapper = (UserQueryMapper) applicationContext.getBean("userQueryMapper");
        // 調(diào)用 UserDAO 的方法
        User user = userQueryMapper.findUserById(1);
        // 輸出用戶信息
        System.out.println(user.getId() + ":" + user.getUsername());
    }
}

運(yùn)行測(cè)試方法,得到正確結(jié)果:

可以看到,查詢結(jié)果和之前非 Mapper 代理的查詢結(jié)果一樣。

  • 原理: 在 applicationContext.xml 配置文件中配置的 mapper 批量掃描器類,會(huì)從 mapper 包中掃描出 Mapper 接口,自動(dòng)創(chuàng)建代理對(duì)象并且在 Spring 容器中注入。自動(dòng)掃描出來(lái)的 Mapper 的 bean 的 id 為 mapper 類名(首字母小寫),所以這里獲取的就是名為 “userQueryMapper” 的 mapper 代理對(duì)象。

參考資料:

  • 《Java EE 互聯(lián)網(wǎng)輕量級(jí)框架整合開發(fā)》
  • 《Spring MVC + MyBatis開發(fā)從入門到項(xiàng)目實(shí)戰(zhàn)》
  • 全能的百度和萬(wàn)能的大腦

歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處!
簡(jiǎn)書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關(guān)注公眾微信號(hào):wmyskxz_javaweb
分享自己的Java Web學(xué)習(xí)之路以及各種Java學(xué)習(xí)資料

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

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,564評(píng)論 19 139
  • 1.記一個(gè)坑:mybatis的xml mapper文件放在源碼目錄時(shí)會(huì)提示無(wú)法找到,原因是使用maven構(gòu)建時(shí),會(huì)...
    virturalMe閱讀 349評(píng)論 0 0
  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲(chǔ)過程以及高級(jí)映射的優(yōu)秀的...
    笨鳥慢飛閱讀 6,241評(píng)論 0 4
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,273評(píng)論 6 342
  • 不停留~在于心 【一】神一樣的你~神一般的存在 不知過了多久?時(shí)間是一個(gè)美麗的記者~給我寫出了一個(gè)個(gè)美麗的故事。 ...
    默姌or娟頭閱讀 334評(píng)論 0 0

友情鏈接更多精彩內(nèi)容