前言
在前面的博文中,我们已经对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;
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依赖)
@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
作者:程序猿小亮