天天看點

SpringBoot系列: 內建MyBatis

本文主要修改自下面部落格:

​​http://www.ityouknow.com/springboot/2016/11/06/spring-boo-mybatis.html​​

​​http://tengj.top/2017/04/23/springboot9/​​

​​http://www.hifreud.com/2017/07/11/spring-boot-22-integrate-with-mybatis/​​

​​https://www.jianshu.com/p/2756e81d02ff ​​

SpringBoot 結合 Mybatis, 至少有下面兩種寫法:

1. mybatis-spring-boot-starter + SQL 的 XML 檔案方式

2. mybatis-spring-boot-starter + SQL 注解方式

這裡重點關注第一個寫法.

==========================

pom.xml 配置

==========================

增加 mybatis boot 依賴 MyBatis-Spring-Boot-Starter, 該包将會提供如下:

1. 自動檢測現有的 DataSource.

2. 将建立并注冊 SqlSessionFactory 的執行個體,該執行個體使用 SqlSessionFactoryBean 将該 DataSource 作為輸入進行傳遞.

3. 将建立并注冊從 SqlSessionFactory 中擷取的 SqlSessionTemplate 的執行個體.

4. 自動掃描您的 mappers,将它們連結到 SqlSessionTemplate 并将其注冊到 Spring 上下文,以便将它們注入到您的 bean 中.

就是說,使用了該 Starter 之後,隻需要定義一個 DataSource 即可(application.properties 中可配置),它會自動建立使用該 DataSource 的 SqlSessionFactoryBean 以及 SqlSessionTemplate.會自動掃描你的 Mappers,連接配接到 SqlSessionTemplate,并注冊到 Spring 上下文中.

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>      

我比較喜歡将 MyBatis 的 SQL xml 檔案和 Java interface 檔案放在同一個目錄下, 這樣檢查代碼比較友善. 對于 java 目錄, maven build 預設情況僅僅會編譯打包 java 檔案, xml 檔案将會被忽略, 是以需要特别将這些 xml 标示為資源檔案. 

<build>
    <finalName>mybatissample</finalName>
    <plugins>
        <!--optional, 加上 spring-boot-maven-plugin, 這樣 jar/war 打包是可以 executable 的 -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>

        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <configuration>
                <verbose>true</verbose>
                <overwrite>true</overwrite>
            </configuration>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>      

==========================

application.properties 的配置

==========================

不管是使用 Hibernate 還是 Mybatis 還是 JDBC, 預設情況下 springboot 都會自動加載 spring.datasource.* 相關配置.

spring.datasource.driverClassName = com.mysql.jdbc.Driver

spring.datasource.url = jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8

spring.datasource.username = root

spring.datasource.password = root

因為我們使用 mybatis-spring-boot-starter, 上面這些 spring.datasource 屬性還會用到 Mybatis 的 sqlSessionFactory 中, 而 sqlSessionFactory 會自動注入到 Mapper 中, 最終執行 SQL 時, 應用程式總是知道應該在哪個資料庫中執行.

除了上面通用的資料源配置外, mybatis-spring-boot-starter 會自動讀取一些 mybatis 開頭的屬性, 其中前三個屬性比較重要, 後幾個屬性一般不用管.

# 重要屬性:

mybatis.mapper-locations:

# mapper 配置檔案的路徑, 支援通配符方式.

mybatis.type-aliases-package:

# 用來掃描 Entity 的包.

mybatis.config-location:

# 指定 mybatis-config.xml 配置檔案的路徑, 其實所有的 mybatis 配置項都可以轉移到 mybatis-config.xml 檔案中, 這樣 application.properties 中 mybatis 的配置項就很清爽.

# 其他屬性

mybatis.type-handlers-package:

# 掃描 typeHandlers 的包

mybatis.checkConfigLocation:

# 檢查配置檔案是否存在

mybatis.executor-type:

# 設定執行模式, 取值有 SIMPLE/REUSE/BATCH,預設為 SIMPLE, REUSE 采用的 prepared statements 元件執行, BATCH 是批量執行模式.

configuration.map-underscore-to-camel-case:

# true 或 false, 是否開啟自動駝峰命名規則 (camel case) 映射,即從經典資料庫列名 A_COLUMN 到經典 Java 屬性名 aColumn 的類似映射.

configuration.default-fetch-size:

# 為驅動的結果集擷取數量(fetchSize)設定一個提示值,此參數隻可以在查詢設定中被覆寫.

configuration.default-statement-timeout:

# 設定逾時時間,它決定驅動等待資料庫響應的秒數.

configuration.auto-mapping-unknown-column-behavior:

# 指定發現自動映射目标未知列(或者未知屬性類型)的行為.取值有 NONE/WARNING/FAILING.

下面是一個 application.properties 的配置示例.

spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = root

mybatis.mapper-locations:classpath:mapper/*.xml
mybatis.type-aliases-package:com.springbootmybatis.mybatissample.entity
mybatis.config-location=classpath:mybatis-config.xml      

==========================

mybatis-config.xml 檔案配置

==========================

mybatis-config.xml 一般和 application.properties 放在同一個目錄下. 對于 mybatis 的一些進階配置參數, 不推薦放到 application.properties 中, 最好還是放到 mybatis-config.xml 檔案中. 具體配置項目說明, 可以參考博文<<mybatis 全局配置檔案 mybatis-config.xml>>, 連結是 https://www.jianshu.com/p/2756e81d02ff

下面 mybatis-config.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>
    <typeAliases>
        <!-- 下面的 type alias 其實可以省略 --> 
        <typeAlias alias="Integer" type="java.lang.Integer" />
        <typeAlias alias="Long" type="java.lang.Long" />
        <typeAlias alias="HashMap" type="java.util.HashMap" />
        <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
        <typeAlias alias="ArrayList" type="java.util.ArrayList" />
        <typeAlias alias="LinkedList" type="java.util.LinkedList" />
    </typeAliases>
    
    <mappers>
      <!--因為已經在 application.properties 中指定了 mybatis.mapper-locations 屬性, 是以這裡無需再指定 mapper 位置  -->
        <!-- 方式一:通過 classpath 相對路徑進行指定 -->
        <!-- <mapper resource="mybatis/mapper/StudentMapper.xml"/> -->
         
        <!-- 方式二:通過檔案系統的絕對路徑進行指定 -->
        <!-- <mapper url="file:///D:/mybatisTest/src/mybatis/mapper/StudentMapper.xml"/> -->
         
        <!-- 方式三:通過 mapper java 接口的方式 -->
        <!-- <mapper class="mybatis.mapper.StudentMapper"/> -->
         
        <!-- 方式四:通過将指定包下面的所有 java mapper 接口進行映射的方式來實作 -->
        <!-- <package name="mybatis.mapper" />   -->    
    </mappers>
</configuration>      

=========================

UserMapper.java

=========================

package com.springbootmybatis.mybatissample.dao;
import java.util.List;
import com.springbootmybatis.mybatissample.entity.UserEntity;

public interface UserMapper {
    List<UserEntity> getAll();
    UserEntity getOne(Long id);
    void insert(UserEntity user);
    void update(UserEntity user);
    void delete(Long id);
}      

=========================

UserMapper.xml

=========================

将 UserMapper.xml 放到 UserMapper.java 同一目錄下.

<?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.springbootmybatis.mybatissample.dao.UserMapper" >
    <resultMap id="BaseResultMap" type="com.springbootmybatis.mybatissample.entity.UserEntity" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="userName" property="userName" jdbcType="VARCHAR" />
        <result column="passWord" property="passWord" jdbcType="VARCHAR" />
        <result column="user_sex" property="userSex" javaType="com.springbootmybatis.mybatissample.enums.UserSexEnum"/>
        <result column="nick_name" property="nickName" jdbcType="VARCHAR" />
    </resultMap>

    <sql id="Base_Column_List" >
        id, userName, passWord, user_sex, nick_name
    </sql>

    <select id="getAll" resultMap="BaseResultMap"  >
       SELECT
       <include refid="Base_Column_List" />
       FROM users
    </select>

    <select id="getOne" parameterType="java.lang.Long" resultMap="BaseResultMap" >
        SELECT
       <include refid="Base_Column_List" />
       FROM users
       WHERE id = #{id}
    </select>

    <insert id="insert" parameterType="com.springbootmybatis.mybatissample.entity.UserEntity" >
       INSERT INTO
               users
               (userName,passWord,user_sex)
           VALUES
               (#{userName}, #{passWord}, #{userSex})
    </insert>

    <update id="update" parameterType="com.springbootmybatis.mybatissample.entity.UserEntity" >
       UPDATE
               users
       SET
           <if test="userName != null">userName = #{userName},</if>
           <if test="passWord != null">passWord = #{passWord},</if>
           nick_name = #{nickName}
       WHERE
               id = #{id}
    </update>

    <delete id="delete" parameterType="java.lang.Long" >
       DELETE FROM
                users
       WHERE
                id =#{id}
    </delete>
</mapper>      

=========================

Spring 主程式

=========================

@SpringBootApplication
@MapperScan("com.springbootmybatis.mybatissample.dao")
public class App extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(App.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(App.class, args);
    }
}      

在啟動類上增加@MapperScan 注解, 該注解的參數是 mapper java interface 所在的 package 名. 如果在主程式中省略了@MapperScan 注解, 則需要在每個 mapper java interface 上加注解 @Mapper.

=========================

UserMapperTest 程式

=========================

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper UserMapper;

    @Test
    public void testInsert() throws Exception {
        UserMapper.insert(new UserEntity("aa", "a123456", UserSexEnum.MAN));
        UserMapper.insert(new UserEntity("bb", "b123456", UserSexEnum.WOMAN));
        UserMapper.insert(new UserEntity("cc", "b123456", UserSexEnum.WOMAN));

        Assert.assertEquals(3, UserMapper.getAll().size());
    }

    @Test
    public void testQuery() throws Exception {
        List<UserEntity> users = UserMapper.getAll();
        System.out.println(users.toString());
    }
    
    @Test
    public void testUpdate() throws Exception {
        UserEntity user = UserMapper.getOne(3l);
        System.out.println(user.toString());
        user.setNickName("neo");
        UserMapper.update(user);
        Assert.assertTrue(("neo".equals(UserMapper.getOne(3l).getNickName())));
    }
}      

=========================

MySQL users 表

=========================

本示例 Mysql table 的 DDL.

DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵 id',
  `userName` varchar(32) DEFAULT NULL COMMENT '使用者名',
  `passWord` varchar(32) DEFAULT NULL COMMENT '密碼',
  `user_sex` varchar(32) DEFAULT NULL,
  `nick_name` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;