SpringBoot整合Mybatis,你真的了解原理吗?

2021-12-07 11:15:04 浏览数 (1)

前言

在前面的博文中,我们已经对SpringBoot的相关基础知识有了深入的了解,不仅知道了什么是SpringBoot,以及如何快速开发一个SpringBoot应用,例如(Spring Boot简介与快速搭建),而且深入的学习了它的自动配置原理,知道了SpringBoot中包含很多的Starter,但是这些Starter我们如何在项目中使用呢?这篇博文,我们重点介绍SpringBoot数据访问相关的内容,不仅仅是简单的整合,而是要明白其中的原理,开始吧。

了解Spring Data

从官网中,我们不难发现,SpringData整合了非常多的数据访问层的技术,例如:JDBC,JPA,MongoDB,Redis,Solr,Elasticsearch,Neoej,Hadoop,这些是我们比较熟悉的,其中一些组件甚至我们在工作中经常使用。那么Spring Data是干什么的呢?

什么是Spring Data

Spring Data的使命是为数据访问提供熟悉且一致的基于Spring的编程模型,同时仍保留底层数据存储的特殊特性。它使得使用数据访问技术,关系数据库和非关系数据库,map-reduce框架和基于云的数据服务变得容易。

说人话:

Spring Data 是为了简化构建基于 Spring 框架应用的数据访问技术,包括关系型数据库、NoSQL、Map-Reduce 框架、云数据服务等等,旨在提供一种通用、统一的编码模式(但是并不是代码完全一样),使得在Spring中使用任何数据库都变得非常容易。

再通俗一点:

Spring Data旨在统一和简化对数据库访问的操作,而不拘泥于是关系型数据库还是NoSQL数据存储。

无论是哪种持久化存储,数据访问对象(DAO,即Data Access Objects)通常都会提供对单一域对象的CRUD(创建、读取、更新、删除)操作、查询方法、排序和分页方法等。Spring Data则提供了基于这些层面的统一接口(CrudRepository,PagingAndSortingRepository)以及对持久化存储的实现。

使用 SpringData 可以大幅减少数据访问层 (DAO) 的开发量. 开发者唯一要做的,就是声明持久层接口,其他都交给 Spring Data 来帮你完成!

从上图,我们可以发现SpringData是更高层次的抽象,涵盖了数据库操作的方方面面,它具备的特性如下所示:

特性

  • 强大的存储库和自定义对象映射抽象
  • 从存储库方法名称派生动态查询
  • 实现域基类提供基本属性
  • 支持透明审核(创建,最后更改)
  • 可以集成自定义存储库代码
  • 通过JavaConfig和自定义XML命名空间轻松实现Spring集成
  • 与Spring MVC控制器的高级集成
  • 跨存储持久性的实验支持

如何选择

从上图可以看到,在Spring Data中操作关系型数据库的框架有两个,一个是Spring Data JDBC,另一个是Spring Data JPA,我们应该如何选择呢?

Spring Data JDBC

Spring Data JDBC,是Spring Data家族的一部分,它使得基于JDBC的存储库变得更加容易实现。本模块处理基于JDBC的数据访问层的增强支持。它使构建使用数据访问技术的Spring驱动的应用程序变得更容易。

Spring Data JDBC的目标是在概念上变得简单。为了实现这一点,它不提供缓存、延迟加载、write-behind或JPA的许多其他特性。这使得Spring Data JDBC成为一个简单、有限、固执己见的ORM。

Spring Data JPA

Spring Data JPA是更大的Spring数据家族的一部分,它使实现基于JPA的存储库变得更容易。本模块处理对基于JPA的数据访问层的增强支持。它使构建使用数据访问技术的Spring驱动的应用程序变得更容易。

两者如何选择

我们都知道Java持久层框架访问数据库的方式大致分为两种。

一种以SQL核心,封装一定程度的JDBC操作,比如:MyBatis。

另一种是以Java实体类为核心,将实体类的和数据库表之间建立映射关系,也就是我们说的ORM框架,如:Hibernate、Spring Data JPA。

Spring Data JDBC是所有ORM框架底层的技术实现,用于操作关系型数据库。而Spring Data JPA是在JDBC之上的抽象,为了使基于JPA规范的数据访问层实现起来更加容易,Hibernate才是具体的实现框架。

这两种方式各有优缺点,大家根据自己的业务特点,选择合适的框架就好了。由于现在的互联网公司中使用Mybatis框架居多,下面我主要介绍如何使用SpringBoot2.4.4来整合Spring Data JDBC和Mybatis访问MySQL。

知道,该选择什么框架了吧?

下面我们创建一个user表,分别使用Spring Data JDBC和Mybatis来访问MySQL数据库。

建表语句:

代码语言:javascript复制
CREATE DATABASE IF NOT EXISTS user_db_test;

DROP TABLE IF EXISTS t_user;

CREATE TABLE `t_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `username` varchar(64) NOT NULL COMMENT '用户姓名',
  `age` int(11) NOT NULL COMMENT '用户年龄',
  `mobile` varchar(11) DEFAULT NULL COMMENT '手机号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
使用Spring Data JDBC

1、添加依赖

代码语言:javascript复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>

2、添加数据库驱动

代码语言:javascript复制
<!-- MYSQL 默认版本<mysql.version>8.0.23</mysql.version>-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

注意:由于我们使用的SpringBoot2.4.4,底层规定的mysql版本是8.0.23,大家可以替换成自己数据库对应的版本。

3、添加配置文件

代码语言:javascript复制
server:
  port: 8081

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/user_db_test
    username: root
    password: admin123
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
  application:
    name: springboot-jdbc

4、数据访问层代码

代码语言:javascript复制
@Repository
public class UserRepository implements IUserRepository{

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Override
    public Integer getTotalCount() {
        Integer userCount = jdbcTemplate.queryForObject("select count(*) from t_user", Integer.class);
        return userCount;
    }

    @Override
    public User getUser(Integer userId) {
        return jdbcTemplate.queryForObject("select id,username,age,mobile from t_user where id = "   userId, new RowMapper<User>(){
            @Override
            public User mapRow(ResultSet resultSet, int i) throws SQLException {
                User user = new User();

                user.setId(resultSet.getInt("id"));
                user.setUsername(resultSet.getString("username"));
                user.setAge(resultSet.getInt("age"));
                user.setMobile(resultSet.getString("mobile"));

                return user;
            }
        });
    }
    @Override
    public Integer insertUser(User u) {
        return jdbcTemplate.update("insert into t_user (username,age,mobile) values(?,?,?)", u.getUsername(), u.getAge(),u.getMobile());

    }

    @Override
    public Integer updateUser(Integer userId, String name) {
        return jdbcTemplate.update("update t_user set username=? where id=?", name, userId);
    }

    @Override
    public Integer deleteUser(Integer userId) {
        return jdbcTemplate.update("delete from t_user where id = ?", userId);
    }
}

5、其他代码,详见

代码语言:javascript复制
<module>springboot-jdbc</module>

CodeChina: https://codechina.csdn.net/jiuqiyuliang/springboot-learning

原理

1、分析依赖关系

Spring Data JDBC的依赖关系如下图所示:

Spring Data JDBC底层依赖于spring-boot-starter-jdbc,spring-boot-starter-jdbc自动配置了spring-jdbc以及HikariCP数据库连接池。

2、分析自动配置

在spring-boot-autoconfigure下的jdbc包中,可以看到自动配置类DataSourceAutoConfiguration。

  • DataSourceAutoConfiguration : 数据源的自动配置类
    • 修改数据源相关的配置DataSourceProperties,以spring.datasource开头
    • 数据库连接池的配置,是自己容器中没有DataSource才自动配置的
      • 底层配置好的连接池是:HikariDataSource(底层添加了HikariCP依赖)
代码语言:javascript复制
    @Configuration(proxyBeanMethods = false)
    @Conditional(PooledDataSourceCondition.class)
    @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
            DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
            DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
    protected static class PooledDataSourceConfiguration
  • DataSourceTransactionManagerAutoConfiguration: 事务管理器的自动配置
  • JdbcTemplateAutoConfiguration: JdbcTemplate的自动配置,可以来对数据库进行crud
    • 可以修改这个配置项@ConfigurationProperties(prefix = “spring.jdbc”) 来修改JdbcTemplate
    • @Bean@Primary JdbcTemplate;自定义组件
  • JndiDataSourceAutoConfiguration: jndi的自动配置
  • XADataSourceAutoConfiguration: 分布式事务相关的

使用mybatis

1、添加依赖

代码语言:javascript复制
<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>2.1.4</version>
</dependency>

2、添加数据库驱动

代码语言:javascript复制
<!-- MYSQL-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

3、添加配置文件

代码语言:javascript复制
server:
  port: 8082

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/user_db_test
    username: root
    password: admin123
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
  application:
    name: springboot-mybatis


# 配置mybatis规则
mybatis:
  config-location: classpath:mybatis/mybatis-config.xml  #全局配置文件位置
  mapper-locations: classpath:mybatis/mapper/*.xml  #sql映射文件位置

4、数据访问层代码

代码语言:javascript复制
@Mapper
public interface UserMapper {

    int getTotalCount();

    User getUser(Integer userId);

    int insertUser(User u);

    int updateUser(Integer userId, String name);

    int deleteUser(Integer userId);
}
代码语言:javascript复制
<?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.liang.boot.mapper.UserMapper">

    <select id="getTotalCount" resultType="int">
      select count(*) from t_user
    </select>

    <sql id="Base_Column_List">
       id,username,age,mobile
    </sql>

    <resultMap id="BaseResultMap" type="com.liang.boot.domain.User">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="username" jdbcType="VARCHAR" property="username"/>
        <result column="age" jdbcType="INTEGER" property="age"/>
        <result column="mobile" jdbcType="VARCHAR" property="mobile"/>
    </resultMap>

    <select id="getUser" parameterType="int" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List" />
        from  t_user where id = #{userId,jdbcType=INTEGER}
    </select>

    <insert id="insertUser" parameterType="com.liang.boot.domain.User">
        insert into t_user (username,age,mobile) values(#{username,jdbcType=VARCHAR},#{age,jdbcType=INTEGER},#{mobile,jdbcType=VARCHAR})
    </insert>

    <update id="updateUser">
        update t_user set username= #{name,jdbcType=VARCHAR} where id = #{userId,jdbcType=INTEGER}
    </update>
    <delete id="deleteUser" parameterType="java.lang.Integer">
        delete from t_user where id = #{userId,jdbcType=INTEGER}
    </delete>

</mapper>

5、其他代码,详见

原理

1、分析依赖关系

mybatis-spring-boot-starter底层依赖于spring-boot-starter-jdbc,以及mybatis-spring-boot-autoconfigure。

2、分析自动配置

在mybatis-spring-boot-autoconfigure下可以看到自动配置类MybatisAutoConfiguration。

最佳实战

  • 导入mybatis-spring-boot-starter依赖
  • 配置application.yaml中,指定mapper-location位置即可
  • 在mybatis-config中添加mybatis的公共配置,例如缓存
  • 编写Mapper接口并标注@Mapper注解
  • 简单方法直接使用注解方式编写SQL
  • 复杂方法编写mapper.xml进行绑定映射

总结

mybatis是一款半自动化的ORM框架,是jdbc的具体实现框架,它能够帮助我们实现了缓存、延迟加载等特性,这也是为什么我们在项目中更多的是使用springboot整合mybatis,而原生的jdbc。

代码示例

本文示例读者可以通过查看下面仓库中的项目,如下所示:

代码语言:javascript复制
<module>springboot-jdbc</module>
<module>springboot-mybatis</module>
  • CodeChina: https://codechina.csdn.net/jiuqiyuliang/springboot-learning

作者:程序猿小亮

0 人点赞