Spring|Spring Boot数据操作集成!

1 前言 对于后端服务器接口的开发,其实就是对数据的增、删、改、查操作。最早的数据库是关系型数据库,如Oracle和MySQL等。随着数据类型的多样化发展,又诞生了诸如MongoDB和Redis等非关系型数据库,以及时序型数据库,如InfluxDB和Prometheus等。内存型数据库一般用于缓存,如EhCache和Couchbase等。Spring Boot作为一款优秀的框架,提供了数据库集成的Starter模块,让开发者可以更方便地操作数据库。
Spring支持JdbcTemplate的数据库访问模式,但这个用法一直未被很多企业采用。不过正如Spring所倡导的理念,它并不排斥其他优秀的框架,而是通过提供各种各样的模板,使得这些框架能够整合到Spring中来,并且更加方便开发者的使用。根据当前时代的背景,本书将介绍JdbcTemplate和JPA(在Spring Boot中默认的JPA实现是Hibernate)的简单结合,并详细阐述MyBatis的整合,在后续章节中我们将以MyBatis为主整合数据库的应用。
在Spring Boot中,已经自动默认数据源的配置,下面让我们开启Spring Boot的数据库之旅。
2 使用数据库 数据库分为两种,即关系型数据库和非关系型数据库。关系型数据库是指通过关系模型组织数据的数据库,并且可以利用外键等保持一致性;而非关系型数据库其实不像是数据库,更像是一种以key-value模式存储对象的结构。
2.1 使用MySQL MySQL数据库(官网地址:https://www.mysql.com)是一种关系型数据库,由瑞典的一家公司开发,现在是Oracle公司旗下的产品。MySQL使用C和C++语言开发,提供多种存储引擎,提供多种连接途径,例如ODBC、JDBC、TCP/IP等,并且支持多线程,是当今最流行的数据库之一,并且免费提供给开发者使用。同时,MySQL数据库是一个高性能的数据库,并且支持多种开发语言,如C、C++、Python、Java、PHP等。并且,MySQL支持大型的数据库,可以处理拥有上千万条记录的大型数据库。
在Spring Boot中使用MySQL很简单,大致分为两步:
(1)在pom文件中加入依赖,如下所示:

mysql mysql-connector-java runtime

(2)在配置文件application.yml中配置数据库信息,如下所示:
spring: datasource: url: jdbc:mysql://127.0.0.1:3306/fullset?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root

2.2 使用SQL Server SQL Server是微软公司推出的关系型数据库(官网地址:https://www.microsoft.com/zh-...),SQL Server数据库同样提供了很多优点,如易用性、适合分布式组织的可伸缩性、用于决策支持的数据仓库功能、与许多其他服务器软件紧密关联的集成性、良好的性价比等。但是相较于MySQL,其有一定的缺点,如局限性(只能运行在Windows系统上)、当连接数过高时性能不够稳定等。
Spring Boot使用SQL Server数据库也很简单,分为两步:
(1)在pom文件中加入依赖,如下所示:
com.microsoft.sqlserver mssql-jdbc runtime

(2)在配置文件中配置数据库信息,如下所示:
spring: datasource: url: jdbc:sqlserver://127.0.0.1:1433; DatabaseName=fullset driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver username: root password: root

2.3 使用MongoDB MongoDB(官网地址:https://www.mongodb.com)是一种非关系型数据库,它是一个基于分布式文件存储的数据库。MongoDB由C++语言编写,有高性能、容易部署等优点。
Spring Boot使用MongoDB数据库很简单,分为两步:
(1)在pom文件加入依赖,如下所示:
org.springframework.boot spring-boot-starter-data-mongodb

(2)在配置文件中加入MongoDB配置,如下所示:
spring: data: mongodb: host: localhost#同127.0.0.1 port: 27017 database: fullset#指定操作的数据库

2.4 使用Redis Redis(官网地址:https://redis.io/)是一种非关系型数据库,使用ANSI C语言开发,是一种Key-Value模式的数据库,支持多种value类型,如string(字符串)、list(链表)、set(集合)、zset(sorted set,有序集合)和hash(哈希类型)。
Spring Boot使用Redis数据库分为两步:
【Spring|Spring Boot数据操作集成!】(1)在pom文件中加入依赖,如下所示:
org.springframework.boot spring-boot-starter-data-redis

(2)在配置文件中加入配置,如下所示:
redis: database: 0 host: 127.0.0.1 port: 6379 password: fs9158 jedis: pool: max-active: 20 max-wait: 100 max-idle: 20 min-idle: 5 timeout: 10000

3 集成JDBC JDBC的全名是Java DataBase Connectivity,是我们最先接触到的数据库连接,通过JDBC可以直接使用Java编程来操作数据库。JDBC可以理解为一个可以执行SQL语句的Java API。
3.1 JDBC依赖 新建项目,在pom文件中加入JDBC依赖和MySQL依赖以及Web功能的依赖,如下所示:
com.microsoft.sqlserver mssql-jdbc runtime mysql mysql-connector-java >runtime org.springframework.boot spring-boot-starter-web

3.2 JDBC方法 通过下面4个方法分别列举了JdbcTemplate操作数据库的增、删、改、查的方法:
@Api(tags="用户服务接口") @RestController @RequestMapping("/baseService/user") public class SysUserController {@Autowired private SysUserService sysUserService; @Autowired private JdbcTemplate jdbcTemplate; //新增 @GetMapping(value="https://www.it610.com/add") public Boolean add (String userName, String passWord){ int result = jdbcTemplate.update(" insert into user (user_name, pass_word) values (?, ?)", userName, passWord); return result>0 ? true : false; }//删除 @GetMapping(value ="https://www.it610.com/delete") public Boolean delete (Integer id){ int result = jdbcTemplate.update(" delete from user where id=?", id); return result>0 ? true : false; }//修改 @GetMapping(value ="https://www.it610.com/update") public Boolean update (Integer id, String passWord){ int result = jdbcTemplate.update(" update user set passWord=? where id=?", passWord, id); return result>0 ? true : false; }//查询 @GetMapping(value ="https://www.it610.com/getById") public Map getById (Integer id){ String sql = "select * from user where id = ?"; Map map = jdbcTemplate.queryForMap(sql, id); return map; } }

在实际开发中对JDBC的使用不是很多,有一定基础就可以了。
4 集成JPA 4.1 JPA介绍 JPA(Java Persistence API)是Sun公司官方提出的Java持久化规范。所谓规范是指只定义标准规则,不提供实现,而JPA的主要实现有Hibernate、EclipseLink、OpenJPA等。JPA是一套规范,不是一套产品,Hibernate是一套产品,如果这些产品实现了JPA规范,那么我们可以把它们叫作JPA的实现产品。
Spring Data JPA是Spring Data的一个子项目,它通过提供基于JPA的Respository,极大地减少了JPA作为数据访问方案的代码量。通过SpringData JPA框架,开发者可以省略实现持久层业务逻辑的工作,唯一要做的,就只是声明持久层的接口,其他都交给Spring Data JPA来帮你完成
Spring Data JPA同样实现了基本的CRUD方法,如增、删、改、查等。如果有个性化的查询,则需要自定义SQL语句。Spring Data JPA提供了以下几个核心接口:
  • Repository接口;
  • CrudRepository接口,继承自Repository;
  • PagingAndSortingRepository接口,继承自CrudRepository;
  • JpaRepository接口,继承自PagingAndSortingRepository。
4.2 JPA依赖配置 在Spring Boot中集成Spring Data JPA,首先需要在pom.xml文件中引入所需的依赖,具体代码如下:
org.springframework.boot spring-boot-starter-data-jpa

接下来进行JPA的基本配置,其中主要说一下配置项spring.jpa.hibernate.ddl-auto。它提供了如下几种配置。
  • validate:在加载hibernate时,验证创建数据库表结构。
  • create:每次加载hibernate,重新创建数据库表结构,设置时要注意,如果设置错误的话,就会造成数据的丢失。
  • create-drop:在加载的时候创建表,在关闭项目时删除表结构。
  • update:加载时更新表结构。
  • none:加载时不做任何操作。
根据具体情况选择配置即可。
# JPA配置 spring.jpa.database=mysql spring.jpa.show-sql=true #validate加载hibernate时,验证创建数据库表结构 spring.jpa.hibernate.ddl-auto=none spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect #懒加载配置 spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

4.3 JPA接口 JPA最顶级的接口是Repository,而它没有定义任何方法,定义方法的是它的子接口CrudRepository,其定义实体最基本的增删改的操作,功能性还不足够强大,为此PagingAndSortingRepository则继承了它并且提供了分页和排序的功能,最后JpaRepository扩展了PagingAndSortingRepository,而且扩展了QueryByExampleExecutor接口。一般而言,我们只需要定义JPA接口扩展JpaRepository便可以获得JPA提供的方法了。如下所示:
public interface BaseSysUserRepository extends JpaRepository {//... }

JPA还有很多用法,感兴趣的读者可以参考官方文档:https://docs.spring.io/spring...。
5 集成MyBatis 5.1 MyBatis简介 MyBatis是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解来配置和映射原生信息,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。支持使用简单的XML文件或注解来配置和映射原生信息,从而将接口和Java的POJO对象映射成数据库中的记录。
5.2 MyBatis依赖配置 Spring Boot也提供了MyBatis的集成模块,即mybatis-spring-boot-starter。在pom文件中加入MyBatis依赖,如下所示:
org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.3

MyBatis常用的配置如下所示:
mybatis: type-aliases-package: com.fs.orm.entity mapper-locations: classpath*:com/fs/orm/mapper/*.xml configuration: # 开启驼峰命名转换 map-underscore-to-camel-case: true

5.3 基于XML的使用 创建Mapper对应接口类SysUserMapper,在类上加入注解@Mapper,表明这是一个Mapper。我们提前定义1个方法:
根据用户名查询用户。
SysUserMapper接口,代码如下所示:
@Mapper public interface SysUserMapper extends BaseMapper { SysUser findList(String userName); }

在src/mian/resources/mapper下创建SysUserMapper.xml,对应写好在SysUserMapper接口类的方法,代码如下:
and t.id = #{id} and t.user_name = #{userName} select count(*) from sys_user t select * from sys_user t order by t.id desc limit #{page},#{limit}

5.4 基于注解使用 MyBatis不仅可以使用XML形式操作数据库,还可以使用注解形式操作数据库,比如如下注解。
  • @Select:其中值写查询SQL。
  • @Update:其中值写修改SQL。
  • @Delete:其中值写删除SQL。
  • @Insert:其中值写插入SQL。
  • @Results:是以@Result为元素的数据。
  • @Result:映射实体类属性和字段之间的关系。
  • @ResultMap:用于解决返回结果映射问题,与上面介绍的resultMap标签功能类似。
  • @Result:可以用作表明自定义对象,方便内容重用。
  • @SelectProvider:相当于直接使用在类中写好的SQL,将SQL封装到类内,方便管理。type属性表明使用哪个类,method对应使用方法。
  • @UpdateProvider:功能类似于@SelectProvider。
  • @DeleteProvider:功能类似于@SelectProvider。
  • @InsertProvider:功能类似于@SelectProvider。
其实现效果和使用XML模式是一样的,并且两种模式可以混用。如下代码所示:
@Select("select * from sys_user ") List findAll(); @Select("select * from sys_user s where s.id=#{id} ") SysUser findById(@Param("id") String id);

6 集成Mybatis-Plus插件 Mybatis-Plus是苞米豆团队开发的一个MyBatis增强型插件,官网上介绍只做增强,不做改变,为简化开发、提高效率而生。其特性有很多,这里不一一介绍,感兴趣的读者可以在官网上查看,官网地址:https://mp.baomidou.com/。接下来我们学习Spring Boot如何使用Mybatis-Plus插件。
6.1 Mybatis-Plus依赖配置 在pom文件中加入Mybatis-Plus依赖,如下所示:
com.baomidou mybatis-plus-boot-starter 3.4.0

常用配置如下所示:
mybatis-plus: mapper-locations: classpath*:com/fs/orm/mapper/*.xml typeAliasesPackage: com.fs.orm.entity configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

还是以用户类作为讲解,实体类代码如下:
package com.fs.orm.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import java.io.Serializable; import java.util.Date; public class SysUser implements Serializable {private static final long serialVersionUID = 1L; @TableId(value="https://www.it610.com/article/id",type= IdType.ASSIGN_ID) @JsonSerialize(using= ToStringSerializer.class) private Long id; private String userName; private Integer userState; private String mobile; private String salt; private String loginAccount; private String loginPwd; private String sex; private String email; private String avatar; private String title; private String description; @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date createTime; @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date updateTime; private Integer isDeleted; public SysUser() { }//get set方法 省略 }

mapper层集成mybatis-plus提供的BaseMapper,如下所示:
package com.fs.orm.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.fs.orm.entity.SysUser; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; @Mapper public interface SysUserMapper extends BaseMapper {}

dao接口集成mybatis-plus提供的IService,代码如下:
package com.fs.orm.dao; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.IService; import com.fs.orm.entity.SysUser; import java.util.List; public interface SysUserDao extends IService {boolean addUser(SysUser sysUser); boolean logicalDeleteById(String id); boolean batchDel(String ids); SysUser editUser(SysUser sysUser); SysUser selectOne(QueryWrapper qWrapper); List getList(QueryWrapper qWrapper); }

dao接口实现集成了mybatis-plus提供的ServiceImpl并实现SysUserDao接口,代码如下:
package com.fs.orm.dao.Impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; import com.fs.orm.dao.SysUserDao; import com.fs.orm.entity.SysUser; import com.fs.orm.mapper.SysUserMapper; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; import java.util.Date; import java.util.List; @Service public class SysUserDaoImpl extends ServiceImpl implements SysUserDao {@Override public boolean addUser(SysUser sysUser) { sysUser.setCreateTime(new Date()); sysUser.setUpdateTime(new Date()); return SqlHelper.retBool(baseMapper.insert(sysUser)); }@Override public boolean logicalDeleteById(String id) { SysUser sysUser = new SysUser(); sysUser.setIsDeleted(1); UpdateWrapper userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper.eq("id", id); int update = baseMapper.update(sysUser, userUpdateWrapper); return update > 0 ? true : false; }@Override public boolean batchDel(String ids) { String [] arr = ids.split(","); UpdateWrapper userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper.in("id", arr); userUpdateWrapper.set("is_deleted", 1); int update = baseMapper.update(null, userUpdateWrapper); return update > 0 ? true : false; }@Override public SysUser editUser(SysUser sysUser) { UpdateWrapper userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper.eq("id", sysUser.getId()); userUpdateWrapper.set("user_name", sysUser.getUserName()); baseMapper.update(sysUser, userUpdateWrapper); return sysUser; }@Override public SysUser selectOne(QueryWrapper qWrapper) { return baseMapper.selectOne(qWrapper); }@Override public List getList(QueryWrapper qWrapper) { return baseMapper.selectList(qWrapper); } }

这里有两点需要说明一下:
1、这里主要使用了mybatis-plus提供的条件构造器来实现数据库的操作。
2、在mapper层和service层中间又加了一层dao,笔者的用意有两点:第一是对返回结果可能为NULL的情况进行处理,其二是对时间及其它一些固定操作在这里统一处理,使上游代码调用尽量更简便。
service业务实现层通过调用SysUserDao完成最终的业务数据逻辑处理。代码如下:
package com.fs.base.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.fs.base.service.SysUserService; import com.fs.core.exception.BizException; import com.fs.core.exception.BizExceptionEnum; import com.fs.core.util.BeanUtil; import com.fs.orm.dao.SysUserDao; import com.fs.orm.data.XmSelectData; import com.fs.orm.entity.SysUser; import com.fs.orm.vo.form.SysUserForm; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; @Service public class SysUserServiceImpl implements SysUserService {@Autowired private SysUserDao sysUserDao; @Override public SysUserForm addUser(SysUserForm sysUserForm) throws Exception { SysUser sysUser = new SysUser(); BeanUtil.copyAttribute(sysUserForm, sysUser); boolean result; try { result = sysUserDao.addUser(sysUser); }catch (Exception e){ throw new Exception("sql语法错误!"); } if(!result){ throw new BizException(BizExceptionEnum.SYS_USER_ADD_ERROR); } return sysUserForm; }@Override public SysUserForm editUser(SysUserForm sysUserForm) { SysUser sysUser = new SysUser(); BeanUtil.copyAttribute(sysUserForm, sysUser); try { sysUser = sysUserDao.editUser(sysUser); }catch (Exception e){ // throw new Exception("sql语法错误!"); } return sysUserForm; }@Override public List getAll() { QueryWrapper qWrapper = new QueryWrapper(); qWrapper.eq("is_deleted", 0); return sysUserDao.getList(qWrapper); }@Override public PageInfo getLayTable(Map params) { PageHelper.startPage(Integer.valueOf(String.valueOf(params.get("page"))),Integer.valueOf(String.valueOf(params.get("limit")))) ; QueryWrapper qWrapper = new QueryWrapper(); if(null != params.get("userName")){ qWrapper.likeLeft("user_name", String.valueOf(params.get("userName"))); } qWrapper.orderByAsc("id"); List list = sysUserDao.getList(qWrapper); PageInfo userPage =new PageInfo<>(list); return userPage; }@Override public SysUserForm initForm() { SysUserForm sysUserForm = new SysUserForm(); sysUserForm.setUserStateList(XmSelectData.getUserState(sysUserForm.getUserState())); sysUserForm.setSexList(XmSelectData.getSex(sysUserForm.getSex())); return sysUserForm; }@Override public SysUserForm editForm(Long id) { SysUser sysUser = sysUserDao.getById(id); SysUserForm sysUserForm = new SysUserForm(); BeanUtil.copyAttribute(sysUser, sysUserForm); sysUserForm.setUserStateList(XmSelectData.getUserState(sysUserForm.getUserState())); sysUserForm.setSexList(XmSelectData.getSex(sysUserForm.getSex())); return sysUserForm; }@Override public boolean logicalDeleteById(String id) { return sysUserDao.logicalDeleteById(id); }@Override public boolean batchDel(String ids) { return sysUserDao.batchDel(ids); } }

再通过controller层对外发布接口。完成整个数据交互的流程。代码如下:
package com.fs.base.controller; import com.fs.base.service.SysUserService; import com.fs.core.web.BaseResult; import com.fs.orm.entity.SysUser; import com.fs.orm.vo.form.SysUserForm; import com.github.pagehelper.PageInfo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.*; import java.sql.Savepoint; import java.util.List; import java.util.Map; @Api(tags="用户服务接口") @RestController @RequestMapping("/baseService/user") public class SysUserController {@Autowired private SysUserService sysUserService; @Autowired private JdbcTemplate jdbcTemplate; //新增 @GetMapping(value="https://www.it610.com/article/add") public Boolean add (String userName, String passWord){ int result = jdbcTemplate.update(" insert into user (user_name, pass_word) values (?, ?)", userName, passWord); return result>0 ? true : false; }//删除 @GetMapping(value ="https://www.it610.com/article/delete") public Boolean delete (Integer id){ int result = jdbcTemplate.update(" delete from user where id=?", id); return result>0 ? true : false; }//修改 @GetMapping(value ="https://www.it610.com/article/update") public Boolean update (Integer id, String passWord){ int result = jdbcTemplate.update(" update user set passWord=? where id=?", passWord, id); return result>0 ? true : false; }//查询 @GetMapping(value ="https://www.it610.com/article/delete") public Map getById (Integer id){ String sql = "select * from user where id = ?"; Map map = jdbcTemplate.queryForMap(sql, id); return map; }@ApiOperation(value = "https://www.it610.com/article/用户列表", notes = "") @PostMapping(value ="https://www.it610.com/layTable") public BaseResult getLayTable(@RequestBody Map params) { PageInfo pageInfo = sysUserService.getLayTable(params); Long count = pageInfo.getTotal(); return new BaseResult<>(count.intValue(), pageInfo.getList()); }@ApiOperation(value="https://www.it610.com/article/初始化用户表单") @PostMapping("/initForm") public BaseResult initForm() { return new BaseResult<>(sysUserService.initForm()); }@ApiOperation(value="https://www.it610.com/article/编辑用户表单") @PostMapping("/editForm/{id}") public BaseResult editForm(@PathVariable Long id) { return new BaseResult<>(sysUserService.editForm(id)); }@ApiOperation(value = "https://www.it610.com/article/添加用户", notes = "") @PostMapping(value ="https://www.it610.com/addUser") public BaseResult addUser(@RequestBody SysUserForm sysUserForm) throws Exception { return new BaseResult<>(sysUserService.addUser(sysUserForm)); }@ApiOperation(value = "https://www.it610.com/article/删除用户", notes = "逻辑删除") @PostMapping(value ="https://www.it610.com/logicalDel/{id}") public BaseResult logicalDel(@PathVariable String id){ return new BaseResult<>(sysUserService.logicalDeleteById(id)); }@ApiOperation(value = "https://www.it610.com/article/批量删除用户", notes = "逻辑删除") @PostMapping(value ="https://www.it610.com/batchDel/{ids}") public BaseResult batchDel(@PathVariable String ids){ return new BaseResult<>(sysUserService.batchDel(ids)); }@ApiOperation(value = "https://www.it610.com/article/编辑用户", notes = "") @PostMapping(value ="https://www.it610.com/editUser") public BaseResult editUser(@RequestBody SysUserForm sysUserForm) { return new BaseResult<>(sysUserService.editUser(sysUserForm)); } }

总结 本篇主要对Sring Boot使用关系数据库进行了全面的介绍,从简单的数据库配置到现在特别流行的JPA和MyBatis的使用都进行了详尽的介绍,相信你已经对操作数据库有了一定的认识,并且熟练运用,可以独立进行开发了。
由于篇幅限制,这里只是对操作进行了简单说明,有关Sring Boot数据库的底层配置和初始化加载原理及非关系型数据库的集成配置将分别单独进行介绍。
最后的最后 为初学者提供学习指南,为从业者提供参考价值。我坚信码农也具有产生洞见的能力。关注【码农洞见】,一起学习和交流吧!

    推荐阅读