【Spring Boot】14.整合Mybatis

簡介

MyBatis前身是apache的一個開源項目iBatis,2010年這個項目由apache software foundation 遷移到了google code,而且更名爲MyBatis2013年11月遷移到Github。html

他是一個支持普通SQL查詢,存儲過程和高級映射的優秀持久層框架。他消除了幾乎全部的JDBC代碼和參數的手工設置以及對結果集的檢索封裝,支持簡單的XML或註解用於配置和原始映射,將接口和Java的POJO(Plain Old Java Objects,普通的Java對象)映射成數據庫中的記錄。java

這一節,咱們將學習如何將mybatis整合到咱們的項目中,輔助數據庫操做。mysql

演示項目

建立項目

一樣採用SpringInitializer建立項目,選擇以下模塊:web

  • web 做爲web啓動
  • MySQL 做爲數據庫驅動
  • JDBC 爲咱們自動配置數據源(可不選擇,mybatis會依賴)
  • MyBatis 數據訪問框架

引入mybatis只需引入依賴spring

pom.xml
<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

從其artifactId咱們能夠了解到,這不是官方包。sql

配置基本環境信息

咱們按整合jdbc與數據源那一章節配置的方式將基礎環境配置好。docker

application.yml

server:
  port: 8086
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://10.21.1.47:3306/joyblack?characterEncoding=utf8&serverTimezone=GMT
    driver-class-name: com.mysql.cj.jdbc.Driver
    initialization-mode: always
    sql-script-encoding: utf-8
    schema:
      - classpath:sql/joyblack.sql

而後倒入咱們建立數據庫以及倒入數據的sql文件,爲了偷懶,咱們統一將其放在schema邏輯中。該腳本建立了兩張表user以及department,分別表明用戶信息以及用戶所在的部門信息,並導入了3個冒險者用戶以及2個工會部門。數據庫

sql/joyblack.sql

/*
Navicat MySQL Data Transfer

Source Server         : docker
Source Server Version : 50505
Source Host           : 10.21.1.47:3306
Source Database       : joyblack

Target Server Type    : MYSQL
Target Server Version : 50505
File Encoding         : 65001

Date: 2018-12-20 09:45:44
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `department`
-- ----------------------------
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
  `id` int(11) NOT NULL,
  `department_name` varchar(30) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of department
-- ----------------------------
INSERT INTO `department` VALUES ('1', '鄉下冒險者公會');
INSERT INTO `department` VALUES ('2', '城市冒險者公會');

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `user_name` varchar(20) NOT NULL,
  `login_name` varchar(20) NOT NULL,
  `deparment_id` int(11) NOT NULL DEFAULT 1,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '阿庫婭', 'akuya', '1');
INSERT INTO `user` VALUES ('2', '克里斯汀娜', 'crustina', '1');
INSERT INTO `user` VALUES ('3', '惠惠', 'huihui', '1');

咱們接下來跑一下應用程序,初始化數據庫信息。爲了運行快速一點,以後咱們應該把配置文件中的 schema:- classpath:sql/joyblack.sql給註釋掉,下次就不要在初始化了。apache

建立實體Bean

接下來咱們建立對應的Bean,關聯數據庫表實體。json

bean/User.class

package com.zhaoyi.mbweb.bean;

public class User {
    private Integer id;
    private String loginName;
    private String userName;
    private Integer departmentId;

    public Integer getId() {
        return id;
    }

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

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getDepartmentId() {
        return departmentId;
    }

    public void setDepartmentId(Integer departmentId) {
        this.departmentId = departmentId;
    }
}

bean/Department.class

package com.zhaoyi.mbweb.bean;

public class Department {
    private Integer id;
    private String departmentName;

    public Integer getId() {
        return id;
    }

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

    public String getDepartmentName() {
        return departmentName;
    }

    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }
}

準備工做完成了,咱們能夠準備使用mybatis了。

接下來咱們就可使用mybatis提供的便利操做數據庫了,不過也有不一樣的操做方式,咱們先一個一個的來。

使用mybatis:基於註解的方式

基於註解的方式無需指明任何配置,直接編寫相關的註解語句便可,咱們只專一本身的Mapper就能夠了。

接下來咱們測試一下怎麼使用基於註解的方式操做數據庫。咱們新建一個Mapper接口,裏面包括了基本的增刪查改操做:

mapper/DepartMentMapper.class

package com.zhaoyi.mbweb.mapper;

import com.zhaoyi.mbweb.bean.Department;
import org.apache.ibatis.annotations.*;

@Mapper
public interface DepartmentMapper {

    // insert a derpartment.
    // @Options(useGeneratedKeys = true, keyProperty = "id") may you want get insert data generated id.
    @Insert("insert into department(id,department_name) values(#{id}, #{departmentName})")
    int insertDepartment(Department department);

    // delete a department by id.
    @Insert("delete from department where id = #{id}")
    int deleteDepartment(Integer id);

    // query a department by id.
    @Select("select * from department where id = #{id}")
    Department getDepartmentById(Integer id);

    // update a department information.
    @Update("update department set department_name=#{departmentName} where id=#{id}")
    int updateDepartment(Department department);
}

其中:

  • @Mapper 指定這是一個操做數據庫的Mapper;
  • 若是你的表是自增類型的,想要得到返回id的信息,能夠在插入語句上方加入註解@Options(useGeneratedKeys = true, keyProperty = "id"),這樣,在插入後mybatis就會自動的將id屬性回寫到你的插入對象中了;
  • 能夠經過#{xxx}語法提取參數中傳遞的值;

而後,編寫一個controller來測試這些操做,爲了方便,咱們就只測試查詢和插入操做便可:

controller/DepartmentController.class

package com.zhaoyi.mbweb.controller;

import com.zhaoyi.mbweb.bean.Department;
import com.zhaoyi.mbweb.mapper.DepartmentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DepartmentController {
    @Autowired
    private DepartmentMapper departmentMapper;

    @GetMapping("/department/{id}")
    public Department getDepartment(@PathVariable("id") Integer id){
        return  departmentMapper.getDepartmentById(id);
    }

    @GetMapping("/department")
    public Department insertDepartment(Department department){
        departmentMapper.insertDepartment(department);
        return department;
    }

}

其中:

  • getDepartment映射/department/{id}的請求,用於處理查詢某個id的部門信息,id寫在路徑參數中;
  • insertDepartment映射/department?xxx=xxx的請求,用於插入get傳遞的參數中指定的部門信息;

一切完畢,運行項目後,咱們分別測試兩個操做的結果:

  1. 訪問: http://localhost:8086/department/2,咱們能夠獲得如下的輸出:
{"id":2,"departmentName":null}
  1. 訪問:http://localhost:8086/department?id=3&name=廣州冒險者公會,咱們獲得如下的輸出:
{"id":3,"departmentName":"廣州冒險者公會"}

並能夠在數據庫中看到該條數據。這就是基於註解的方式來使用mybatis操做數據庫。

開啓駝峯映射規則

細心的朋友應該會發現,查詢的部門信息的時候返回的數據的departmentName的值爲空。這顯然是不對的,咱們能夠留意到在數據庫中咱們的命名方式是下劃線的department_name,而bean中則是departmentName。這就須要咱們開啓駝峯映射規則,來提醒mybatis將數據庫的下劃線字段和bean的駝峯變量關聯起來。

如何修改呢?

咱們觀察mybatis的自動配置類

@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class MybatisAutoConfiguration {
    ...
    
    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
            factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
        }

        org.apache.ibatis.session.Configuration configuration = this.properties.getConfiguration();
        if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
            configuration = new org.apache.ibatis.session.Configuration();
        }

        // 從這裏能夠知道能夠經過配置ConfigurationCustomizer來操做mybatis的配置
        if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
            Iterator var4 = this.configurationCustomizers.iterator();

            while(var4.hasNext()) {
                ConfigurationCustomizer customizer = (ConfigurationCustomizer)var4.next();
                customizer.customize(configuration);
            }
        }

        factory.setConfiguration(configuration);
        if (this.properties.getConfigurationProperties() != null) {
            factory.setConfigurationProperties(this.properties.getConfigurationProperties());
        }

        if (!ObjectUtils.isEmpty(this.interceptors)) {
            factory.setPlugins(this.interceptors);
        }

        if (this.databaseIdProvider != null) {
            factory.setDatabaseIdProvider(this.databaseIdProvider);
        }

        if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
            factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        }

        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }

        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
            factory.setMapperLocations(this.properties.resolveMapperLocations());
        }

        return factory.getObject();
    }
    ...
}

能夠發現,咱們能夠經過增長ConfigurationCustomizer類型的Bean,就能夠修改mybatis的配置信息了。添加配置:

config/MyBatisConfig.class

package com.zhaoyi.mbweb.config;


import org.apache.ibatis.session.Configuration;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;

@org.springframework.context.annotation.Configuration
public class MyBatisConfig {

    @Bean
    public ConfigurationCustomizer configurationCustomizer(){
        return new ConfigurationCustomizer(){
            @Override
            public void customize(Configuration configuration) {
                // 開啓駝峯映射規則
                configuration.setMapUnderscoreToCamelCase(true);
            }
        };
    }
}

接下來,咱們重啓項目,就能夠發現,能夠正常的得到部門信息了,繼續訪問剛纔的地址http://localhost:8086/department/2,獲取id爲2的部門信息:

{"id":2,"departmentName":"城市冒險者公會"}

批量掃描Mapper接口

經過前面的介紹,咱們須要留意一點,就是編寫Mapper的時候要爲其添加@Mapper註解,這樣才能讓mybatis識別這些mapper。可是在實際的開發過程當中,Mapper確定是一個很多的量的,至少,爲了簡潔考慮,您須要爲每一個數據表映射一個Mapper,有沒有一種一勞永逸的方法呢?

有!

咱們只需在MyBaticConfig加上掃描註解或者SpringBoot的啓動類上添加@MapperScan(value="your mapper packagePath"),例如,咱們能夠在上面的mybatis配置類這樣寫:

config/MybatisConfig.class

// batch scan all mapper class.
@MapperScan(value = "com.zhaoyi.mbweb.mapper")
@org.springframework.context.annotation.Configuration
public class MyBatisConfig {

com.zhaoyi.mbweb.mapper 是個人mapper所在的包名,請按您本身的包名進行填寫。

使用mybatis:基於配置的方式

更多信息請參考: 官方文檔

前面咱們使用了基於註解的方式對數據庫進行了操做,如今,咱們試試另一種方式,經過配置文件的方式來使用mybatis操做數據庫。爲了方便,咱們接下來的這種方式就來操做user表進行演示便可。

編寫Mapper

首先,編寫一個user的mapper

mapper/UserMapper.class

package com.zhaoyi.mbweb.mapper;

import com.zhaoyi.mbweb.bean.User;

public interface UserMapper {

    int insertUser(User user);

    int deleteUser(Integer id);

    User getUserById(Integer id);

    int updateUser(User user);
}

和以前的DepartmentMapper不一樣的是,咱們這裏並無添加註解,由於,咱們將會把他們寫在對應的mybatis SQL映射文件中。

設置應用程序全局配置文件

接下來咱們要指定Mybatis配置文件以及Mybatis SQL映射文件的路徑,在配置文件中添加以下配置

application.yml

server:
  port: 8086
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://10.21.1.47:3306/joyblack?characterEncoding=utf8&serverTimezone=GMT
    driver-class-name: com.mysql.cj.jdbc.Driver
    initialization-mode: always
    sql-script-encoding: utf-8
    #schema:
    # - classpath:sql/joyblack.sql
mybatis:
  # mybatis配置文件
  config-location: classpath:mybatis/mybatis-config.xml
  # SQL映射文件路徑,查看源碼他是一個String數組,不過咱們直接配置"*"通配符便可,表明全部的xml文件
  mapper-locations: classpath:mybatis/mapper/*.xml

配置Mybatis配置文件

在資源文件夾下建立mybatis文件夾,並放入mybatis-config.xml(和全局配置指定的路徑一致)配置文件

resources/mybatis/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>
    <settings>
       <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>
</configuration>

裏面配置一些相關配置,例如數據庫鏈接信息等,但這些咱們已經在數據源配置了,這裏就無需配置。

若是咱們沒有在mybatis的主配置文件中配置mapUnderscoreToCamelCase,這時候咱們去查詢部門相關的信息,發現名字又爲空了。由於當使用配置文件以後,咱們的自定義配置中設置的駝峯式映射邏輯已經被配置文件的默認配置覆蓋掉了。所以,咱們須要在配置文件中指定駝峯時映射規則:

resources/mybatis/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>
    <settings>
       <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>
</configuration>

能夠發現,配置項mapUnderscoreToCamelCase和咱們使用配置文件的屬性名是如出一轍的。

從這裏能夠看出,兩種方式混用也是能夠的,可是問題很明顯,配置會衝突。因此你們在開發的時候最好仍是選擇其中一種方式,從始至終進行,避免管理上的複雜以及邏輯的混亂。

配置Mybatis SQL映射文件

對應配置文件建立一個mapper文件夾,用於放咱們的SQL映射文件,在這裏咱們建立一個UserMapper.xml便可.

resources/mybatis/mapper/UserMapper.xml

<?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.zhaoyi.mbweb.mapper.UserMapper">
    <!--     int insertUser(User user);

    int deleteUser(Integer id);

    User getUserById(Integer id);

    int updateUser(User user);-->
    <insert id="insertUser">
        insert into user(id, login_name, user_name, department_id) values (#{id}, #{loginName}, #{userName}, #{departmentId})
    </insert>

    <delete id="deleteUser">
        delete from user where id = #{id}
    </delete>

    <select id="getUserById" resultType="com.zhaoyi.mbweb.bean.User">
        select * from user where id = #{id}
    </select>

    <update id="updateUser">
        update user set user_name = #{userName} where id = #{id}
    </update>
</mapper>

接下來就是編寫controller測試curd4個操做了。

controller/UserController.class

package com.zhaoyi.mbweb.controller;

import com.zhaoyi.mbweb.bean.User;
import com.zhaoyi.mbweb.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @RequestMapping("/user/insert")
    public User insertUser(User user){
        userMapper.insertUser(user);
        return user;
    }

    @RequestMapping("/user/delete/{id}")
    public Integer insertUser(@PathVariable("id") Integer id){
        return userMapper.deleteUser(id);
    }

    @RequestMapping("/user/select/{id}")
    public User getUser(@PathVariable("id") Integer id){
       return userMapper.getUserById(id);
    }

    @RequestMapping("/user/update")
    public User updateUser(User user){
        userMapper.updateUser(user);
        return user;
    }
}

測試:

  1. 訪問:http://localhost:8086/user/insert?id=4&loginName=youyou&userName=悠悠&departmentId=2,插入第4個主角的名字:
{"id":4,"loginName":"youyou","userName":"悠悠","departmentId":2}

這時候查看數據庫,記錄已經增長。 2. 訪問:http://localhost:8086/user/update?id=4&userName=悠悠改,修改新增長的悠悠的信息 {"id":4,"loginName":null,"userName":"悠悠","departmentId":null} 由於咱們返回的是傳入的參數,因此其餘兩個字段的空值是正常的。

  1. 訪問:http://localhost:8086/user/delete/4,將新增長的主角悠悠記錄刪除:
1

返回的是操做影響的記錄條數,顯然是1條,而且數據庫中記錄已經被刪除。

  1. 訪問http://localhost:8086/user/select/2,查詢id爲2的主角信息
{"id":2,"loginName":"crustina","userName":"克里斯汀娜","departmentId":1}

以上就是基於配置方式整合mybatis了,能夠根據本身的須要,選擇本身喜歡的開發方式。以前開發的項目差很少也是兩種方式的混合體,可是時代在進步,既然用了springboot就不能少了JPA相關的理念,接下來,咱們就學習JPA相關的東西,看看spring data還有什麼有趣的內容。

相關文章
相關標籤/搜索