专栏首页Java后端技术栈cwnait【原创】Spring Boot集成Mybatis的玩法

【原创】Spring Boot集成Mybatis的玩法

前言

前面我们讲过Spring Boot集成JPA,但是由于很多小伙伴的项目中用的并不是JPA,用的是Mybatis,并且我也调查过很多朋友,三个ORM框架使用比例大致为

Mybatis:JPA:Hibernate:其他=6:3:0.5:0.5

不接受反驳,因为没有多大意义。

面试题:Mybatis和Hibernate的区别

这题目答案网上多得很,可以用漫天非来形容。但是我们这里会关注一个点不同点:sql的优化。

由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而hibernate的sql很多都是自动生成的,无法直接维护sql;虽有hql,但功能还是不及sql强大,见到报表等变态需求时,hql也歇菜,也就是说hql是有局限的;hibernate虽然也支持原生sql,但开发模式上却与orm不同,需要转换思维,因此使用上不是非常方便。总之写sql的灵活度上hibernate不及mybatis。其实在Mybatis中我们也可以使用注解的方式来操作数据库(注解中写sql)。

xml方式集成

MyBatis 是现如今最流行的 ORM 框架之一,我们先来了解一下什么是 ORM 框架。

ORM框架

对象关系映射(Object Relational Mapping,ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单的说,ORM 是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

为什么需要 ORM?

当你开发一个应用程序的时候(不使用 O/R Mapping),可能会写不少数据访问层代码,用来从数据库保存、删除、读取对象信息等;在 DAL 中写了很多的方法来读取对象数据、改变状态对象等任务,而这些代码写起来总是重复的。针对这些问题 ORM 提供了解决方案,简化了将程序中的对象持久化到关系数据库中的操作。

ORM 框架的本质是简化编程中操作数据库的编码,在 Java 领域发展到现在基本上就剩两家最为流行,一个是宣称可以不用写一句 SQL 的 Hibernate,一个是以动态 SQL 见长的 MyBatis,两者各有特点。在企业级系统开发中可以根据需求灵活使用,会发现一个有趣的现象:传统企业大都喜欢使用 Hibernate,而互联网行业通常使用 MyBatis。

MyBatis 介绍

MyBatis 是一款标准的 ORM 框架,被广泛的应用于各企业开发中。MyBatis 最早是 Apache 的一个开源项目 iBatis,2010 年这个项目由 Apache Software Foundation 迁移到了 Google Code,并且改名为 MyBatis,2013 年 11 月又迁移到 Github。从 MyBatis 的迁移史,也可以看出源码托管平台的发展史,GitHub 目前已经成为世界上最大的开源软件托管平台,建议大家多多关注这个全球最大的同性社交网站。

MyBatis 支持普通的 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索封装。MaBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。

作为一款使用广泛的开源软件,它的特点有哪些呢?

优点

  • SQL 被统一提取出来,便于统一管理和优
  • SQL 和代码解耦,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰、更易维护、更易单元测试
  • 提供映射标签,支持对象与数据库的 ORM 字段关系映射
  • 提供对象关系映射标签,支持对象关系组件维护
  • 灵活书写动态 SQL,支持各种条件来动态生成不同的 SQL

缺点

  • 编写 SQL 语句时工作量很大,尤其是字段多、关联表多时,更是如此
  • SQL 语句依赖于数据库,导致数据库移植性差

MyBatis 几个重要的概念

Mapper 配置可以使用基于 XML 的 Mapper 配置文件来实现,也可以使用基于 Java 注解的 MyBatis 注解来实现,甚至可以直接使用 MyBatis 提供的 API 来实现。

Mapper 接口是指自行定义的一个数据操作接口,类似于通常所说的 DAO 接口。早期的 Mapper 接口需要自定义去实现,现在 MyBatis 会自动为 Mapper 接口创建动态代理对象。Mapper 接口的方法通常与 Mapper 配置文件中的 select、insert、update、delete 等 XML 结点存在一一对应关系。

Executor,MyBatis 中所有的 Mapper 语句的执行都是通过 Executor 进行的,Executor 是 MyBatis 的一个核心接口。

SqlSession,是 MyBatis 的关键对象,是执行持久化操作的独享,类似于 JDBC 中的 Connection,SqlSession 对象完全包含以数据库为背景的所有执行 SQL 操作的方法,它的底层封装了 JDBC 连接,可以用 SqlSession 实例来直接执行被映射的 SQL 语句。

SqlSessionFactory,是 MyBatis 的关键对象,它是单个数据库映射关系经过编译后的内存镜像。SqlSessionFactory 对象的实例可以通过 SqlSessionFactoryBuilder 对象类获得,而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出。

MyBatis 的工作流程如下:

  1. 首先加载 Mapper 配置的 SQL 映射文件,或者是注解的相关 SQL 内容。
  2. 创建会话工厂,MyBatis 通过读取配置文件的信息来构造出会话工厂(SqlSessionFactory)。
  3. 创建会话。根据会话工厂,MyBatis 就可以通过它来创建会话对象(SqlSession),会话对象是一个接口,该接口中包含了对数据库操作的增、删、改、查方法。
  4. 创建执行器。因为会话对象本身不能直接操作数据库,所以它使用了一个叫做数据库执行器(Executor)的接口来帮它执行操作。
  5. 封装 SQL 对象。在这一步,执行器将待处理的 SQL 信息封装到一个对象中(MappedStatement),该对象包括 SQL 语句、输入参数映射信息(Java 简单类型、HashMap 或 POJO)和输出结果映射信息(Java 简单类型、HashMap 或 POJO)。
  6. 操作数据库。拥有了执行器和 SQL 信息封装对象就使用它们访问数据库了,最后再返回操作结果,结束流程。

在我们具体的使用过程中,就是按照上述的流程来执行。

什么是 MyBatis-Spring-Boot-Starter?

mybatis-spring-boot-starter 是 MyBatis 帮助我们快速集成 Spring Boot 提供的一个组件包,使用这个组件可以做到以下几点:

  1. 构建独立的应用
  2. 几乎可以零配置
  3. 需要很少的 XML 配置

mybatis-spring-boot-starter 依赖于 MyBatis-Spring 和 Spring Boot,最新版 1.3.2 需要 MyBatis-Spring 1.3 以上,Spring Boot 版本 1.5 以上。

注意 :mybatis-spring-boot-starter 是 MyBatis 官方开发的 Starter,而不是 Spring Boot 官方开发的启动包,其实是 MyBatis 看 Spring Boot 市场使用度非常高,因此主动开发出 Starter 包进行集成,但这一集成确实解决了很多问题,使用起来比以前简单很多。mybatis-spring-boot-starter 主要提供了两种解决方案,一种是简化后的 XML 配置版,一种是使用注解解决一切问题。

MyBatis 以前只有 XML 配置这种使用的形式,到了后来注解使用特别广泛,MyBatis 也顺应潮流提供了注解的支持,从这里可以看出 MyBatis 一直都跟随着主流技术的变化来完善自己。接下来给大家介绍一下如何使用 XML 版本。

XML 版本保持映射文件的方式,最新版的使用主要体现在不需要实现 Dao 的实现层,系统会自动根据方法名在映射文件中找到对应的 SQL。

初始化脚本

为了方便项目演示,需要在 test 仓库创建 users 表,脚本如下:

CREATE TABLE `users` (
  `id` int(11) 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=1 DEFAULT CHARSET=utf8;
-- 初始化一条数据
INSERT INTO `my_jpa`.`users`(`id`, `userName`, `passWord`, `user_sex`, `nick_name`) VALUES (1, 'zhangsan', '123456', 'man', 'xiaosan');

添加依赖包

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

application.properties添加配置项

properties
#mysql配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/my_jpa?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=lwt123456@
#mybatis配置
mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
mybatis.type-aliases-package=com.tian.usercenter.entity

实体类

package com.tian.usercenter.entity;
public class UserEntity {
    private Integer id;
    private String userName;
    private String passWord;
    private String userSex;
    private String nickName;
    //set get
}

在创建一个UserMapper.java

java
import com.tian.usercenter.entity.UserEntity;

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

在resources目录下添加mybatis目录

1.在该目录下添加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="callSettersOnNulls" value="true"/>
        <setting name="cacheEnabled" value="true"/>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="true"/>
        <setting name="multipleResultSetsEnabled" value="true"/>
        <setting name="useColumnLabel" value="true"/>
        <setting name="useGeneratedKeys" value="false"/>
        <setting name="autoMappingBehavior" value="PARTIAL"/>
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="localCacheScope" value="SESSION"/>
        <setting name="jdbcTypeForNull" value="NULL"/>
    </settings>

    <typeAliases>
        <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>
</configuration>

2.在本目录下添加mapper目录,然后再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.tian.usercenter.dao.UserMapper" >
    <resultMap id="BaseResultMap" type="com.tian.usercenter.entity.UserEntity" >
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="userName" property="userName" jdbcType="VARCHAR" />
        <result column="passWord" property="passWord" jdbcType="VARCHAR" />
        <result column="user_sex" property="userSex" jdbcType="VARCHAR"/>
        <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.Integer" resultMap="BaseResultMap" >
        SELECT
        <include refid="Base_Column_List" />
        FROM users
        WHERE id = #{id}
    </select>

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

    <update id="update" parameterType="com.tian.usercenter.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.Integer" >
        DELETE FROM  users WHERE id =#{id}
    </delete>
</mapper>

启动类添加注解

@MapperScan("com.tian.usercenter.dao")扫描的**Mapper.java目录

@SpringBootApplication
@MapperScan("com.tian.usercenter.dao")
public class UserCenterApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserCenterApplication.class, args);
    }
}

使用(这里只是为了演示,所以controller就直接掉mapper了,具体开发中按照项目规范来)

@RestController
public class MybatisController {
    @Resource
    private UserMapper userMapper;

    @GetMapping("/mybatis")
    public Object mybatis(){
        List<UserEntity> userEntityList = userMapper.getAll();
        return userEntityList;
    }
}

启动项目,请求地址:http://localhost:8080/mybatis

OK,自此,xml方式的Springboot集成Mybatis就搞定了。下面继续搞注解方式:

注解方式集成

application.properties文件中的配置得删除掉xml相关的

#mybatis.config-location=classpath:mybatis/mybatis-config.xml
#mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
mybatis.type-aliases-package=com.tian.usercenter.entity

UserMapper.java修改

import com.tian.usercenter.entity.UserEntity;
import org.apache.ibatis.annotations.*;
import java.util.List;

public interface UserMapper {
    @Select("select * from users")
    List<UserEntity> getAll();
    @Select("select * from users where id= #{id}")
    UserEntity getOne(@Param("id") Long id);
    @Insert("insert into users (id,userName,passWord,user_sex,nick_name) values (#{id},#{userName}{,#{passWord},#{userSex},#{nickName})")
    void insert(UserEntity user);
    @Update("update users set username=#{userName} where userName=#{userName}")
    void update(UserEntity user);
    @Delete("delete from users where id=#{id}")
    void delete(@Param("id") Long id);
}

UserMapper.xml文件删掉。重启项目;

请求:http://localhost:8080/mybatis

认真的朋友看到了上面的返回结果中有两个字段userSex和nickName为Null。但是在xml方式中是正常返回的。

这里可以使用添加一个配置项来解决下换线与驼峰的问题

mybatis.configuration.map-underscore-to-camel-case=true

最后结果为:

好了,上面两种方式都成功实现,今天就分享到此。

本文分享自微信公众号 - Java后端技术全栈(jjs-2018),作者:田老师

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-08-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 面试官问:MySQL的自增ID用完了,怎么办?

    可以发现 AUTO_INCREMENT 已经自动变成2,这离用完还有很远,我们可以算下最大当前声明的自增ID最大是多少,由于这里定义的是 intunsigned...

    用户4143945
  • 面试再问ThreadLocal,别说你不会

    以前面试的时候问到ThreadLocal总是一脸懵逼,只知道有这个哥们,不了解他是用来做什么的,更不清楚他的原理了。表面上看他是和多线程,线程同步有关的一个工具...

    用户4143945
  • 5种JVM调优配置方法概览!!!

    来源:https://www.iteye.com/blog/pengjiaheng-538582

    用户4143945
  • 经验拾忆(纯手工)=> Python三

    GIL这个话题至今也是个争议较多的,对于不用应用场景对线程的需求也就不同,说下我听过的优点: 1. 我没有用过其他语言的多线程,所以无法比较什么,但是对于I/O...

    py3study
  • 架构设计 | 高并发流量削峰,共享资源加锁机制

    在互联网的业务架构中,高并发是最难处理的业务之一,常见的使用场景:秒杀,抢购,订票系统;高并发的流程中需要处理的复杂问题非常多,主要涉及下面几个方面:

    知了一笑
  • 安全科普:SQLi Labs 指南 Part 1

    译者:SQL Libs一直也没看到有人写过比较完整的指南,只有作者在自己的博客上帖了一些tip和一些视频,偶然看到一篇文章在写这个,便拿过来翻一下,以作参考,原...

    FB客服
  • 你真的了解AsyncTask?

    虽说现在做网络请求有了Volley全家桶和OkHttp这样好用的库,但是在处理其他后台任务以及与UI交互上,还是需要用到AsyncTask。但是你真的了解Asy...

    weishu
  • kafka单节点的安装,部署,使用

    1、kafka官网:http://kafka.apache.org/downloads

    别先生
  • 将MySQL去重操作优化到极致之三弹连发(一):巧用索引与变量

            元旦假期收到阿里吴老师来电,被告知已将MySQL查重SQL优化到极致:100万原始数据,其中50万重复,把去重后的50万数据写入目标表只需要9秒...

    用户1148526
  • PowerBI DAX 度量值管理 - 基本编写到高级管理

    我们会用几篇文章来描述这些问题如何在当前的 PowerBI 中实现。很多问题的解决并不是能用 PowerBI 内置功能解决,这也算是一个痛点,按照微软的表述,微...

    BI佐罗

扫码关注云+社区

领取腾讯云代金券