数据存储

快速导航

概览

在介绍以下几种数据库之前少不了先说下Spring家族的spring-data,适用于关系型和非关系型数据库,简化了配置和数据库访问。例如,Spring Data JPASpring Data MongoDBSpring Data Redis

Spring Data 官网,推荐去官网看看。

mysql

Mysql数据库这里要用到Spring-Data-Jpa,它是JPA规范下提供的Repository层的实现,可以使用Hibernate、OpenJpa等框架进行开发。关于JPA规范,它的全称Java Persistence API(Java持久化API)一个ORM规范,具体实现还是Hibernate等,JPA为我们提供了CRUD的接口。

常用方法

更多详细方法及使用参考官方文档 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

  • save(): 保存、更新
  • delete: 删除,或者deleteByProperty Property为字段属性名
  • findOne(): 通过id查询
  • findByProperty(type Property): 通过属性查询,例如表中的name字段查询,实现方式 findByName(String name)
  • findAll(): 查询所有数据
  • findAll(new PageRequest(1, 20)): 分页

添加依赖

项目根目录 pom.xml 添加依赖 spring-boot-starter-data-jpa mysql-connector-java

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-jpa</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>mysql</groupId>
  7. <artifactId>mysql-connector-java</artifactId>
  8. </dependency>

修改配置文件

application.yml

  • mysql相关配置
  • datasource 数据源

    • driver-class-name 驱动名称
    • `url 数据库地址(hots:port/database)
    • username 数据库用户名
    • password 数据库密码
  1. spring:
  2. datasource:
  3. driver-class-name: com.mysql.jdbc.Driver
  4. url: jdbc:mysql://127.0.0.1:3306/dbUser?useUnicode=true&characterEncoding=utf-8&useSSL=true
  5. username: root
  6. password: 123456
  • jpa相关配置
  • hibernate: 相关配置信息有以下几种类型

    • ddl-auto:create: 每次运行加载不管之前是否有数据都会自动创建一个表,会造成数据丢失。
    • ddl-auto:update: 第一次加载会创建新的数据接口,之后只会在原有表基础之上进行迭代。
    • ddl-auto:validate: 验证类里面的属性与表结构是否一致。
    • ddl-auto:create-drop: 每次退出时删除。
    • ddl-auto:node: 默认什么都不做。
  • show-sql: 是否打印SQL,在开发时可以开启方便调试。
  • database: 数据库类型。
  1. spring:
  2. jpa:
  3. hibernate:
  4. ddl-auto: update
  5. show-sql: true
  6. database: mysql

实例

Spring-Data-Jpa实现CRUD操作

实现以下需求:

  • GET: 查询所有用户信息
  • GET: 根据年龄获取用户信息
  • POST: 增加用户(姓名、年龄)
  • PUT: 修改用户
  • DELETE: 删除用户
创建表

就是创建存储的User实体(User类)

是不需要手动去数据库创建表的,以下创建的User类和定义的属性会对应到数据库中的表和字段,这就需要应用jpa的特性了,看下以下注解。

  • @Entity: 代表此类映射为数据库的表结构
  • @Id: 指定一个主键
  • @GeneratedValue: 配置主键相关信息
    • Table: 使用一个特定的数据库表来保存主键
    • IDENTITY: 数据库自动生成
    • AUTO: 主键由程序控制,默认值
    • SEQUENCE: 通过数据库的序列产生主键, MYSQL不支持,部分数据库(Oracle,PostgreSQL,DB2)支持序列对象
  1. ```java
  2. @Entity
  3. public class User {
  4. @Id
  5. @GeneratedValue
  6. private Integer id;
  7. private String name;
  8. private Integer age;
  9. public User() {
  10. }
  11. // getter、setter方法此处省略,代码可参考本节源码
  12. }
创建数据访问接口

创建接口User的数据访问UserRepository继承于JpaRepository,可以在这个接口里实现UserRepository的扩展

UserRepository.java

  1. public interface UserRepository extends JpaRepository<User, Integer> {
  2. /**
  3. * 扩展,通过名字查询
  4. * @param name
  5. * @return
  6. */
  7. public List<User> findByName(String name);
  8. }
创建UserController
  1. ```java
  2. package com.angelo;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.web.bind.annotation.*;
  5. import java.util.List;
  6. import java.util.Optional;
  7. @RestController
  8. public class UserController {
  9. @Autowired
  10. private UserRepository userRepository;
  11. }
  • 保存一个用户
  1. @RestController
  2. public class UserController {
  3. // ... 以上内容忽略
  4. /**
  5. * 保存一个用户
  6. * @param name
  7. * @param age
  8. * @return
  9. */
  10. @PostMapping(value = "/user")
  11. public User userAdd(@RequestBody User userParams) {
  12. User user = new User();
  13. user.setName(userParams.getName());
  14. user.setAge(userParams.getAge());
  15. return userRepository.save(user);
  16. }
  17. }

postman测试

  1. curl -X POST \
  2. http://127.0.0.1:8080/user \
  3. -H 'cache-control: no-cache' \
  4. -H 'content-type: application/json' \
  5. -H 'postman-token: e0832f99-8a03-e260-4388-b3f60dc2d0c4' \
  6. -d '{
  7. "name": "张三",
  8. "age": 18
  9. }'

返回

  1. {
  2. "id": 3,
  3. "name": "张三",
  4. "age": 18
  5. }
  • 查询用户列表
    1. @RestController
    2. public class UserController {
    3. // ... 以上内容忽略
    4. /**
    5. * 查询用户列表
    6. * @return
    7. */
    8. @RequestMapping(value = "/user/list")
    9. public List<User> userList() {
    10. return userRepository.findAll();
    11. }
    12. }

postman测试

  1. curl -X GET \
  2. http://127.0.0.1:8080/user/list \
  3. -H 'cache-control: no-cache' \
  4. -H 'postman-token: 1fca1e6c-820e-b5bd-952f-2ab658b084a5'

返回数据

  1. [
  2. {
  3. "id": 1,
  4. "name": "张三",
  5. "age": 18
  6. }
  7. ]
  • 根据id查找一个用户

注意, spring-data-jpa 2.0.5.RELEASE 版本之后获取单个对象的数据源需要用findById(),SpringBoot1.x版本可以使用findOne()

  1. @RestController
  2. public class UserController {
  3. // ... 以上内容忽略
  4. /**
  5. * 根据id查找一个用户
  6. * @param id
  7. * @return
  8. */
  9. @RequestMapping(value = "/user/{id}")
  10. public Optional<User> userFindOne(@PathVariable("id") Integer id) {
  11. return userRepository.findById(id);
  12. }
  13. }

postman测试

  1. curl -X GET \
  2. http://127.0.0.1:8080/user/1 \
  3. -H 'cache-control: no-cache' \
  4. -H 'postman-token: 801e22f4-73a1-6f1d-4207-0079d5a31004'

返回数据

  1. {
  2. "id": 1,
  3. "name": "张三",
  4. "age": 18
  5. }
  • 根据name查找用户
  1. @RestController
  2. public class UserController {
  3. // ... 以上内容忽略
  4. /**
  5. * 根据name获取用户信息
  6. * @param name
  7. * @return
  8. */
  9. @RequestMapping(value = "/user/name", method = RequestMethod.GET)
  10. public List<User> findUserListByName(@RequestParam(name="name",defaultValue="") String name) {
  11. return userRepository.findByName(name);
  12. }
  13. }

postman测试

  1. curl -X GET \
  2. 'http://127.0.0.1:8080/user/name?name=%E5%BC%A0%E4%B8%89' \
  3. -H 'cache-control: no-cache' \
  4. -H 'postman-token: 4b4a0850-50f5-3fb2-7137-a44f555e9b49'

返回数据

  1. [
  2. {
  3. "id": 1,
  4. "name": "张三",
  5. "age": 18
  6. }
  7. ]
  • 更新用户信息
  1. @RestController
  2. public class UserController {
  3. // ... 以上内容忽略
  4. /**
  5. * 更新用户信息
  6. * @param id
  7. * @param name
  8. * @param age
  9. * @return
  10. */
  11. @PutMapping(value = "/user/{id}")
  12. public User userUpdate(
  13. @PathVariable("id") Integer id,
  14. @RequestParam("name") String name,
  15. @RequestParam("age") Integer age
  16. ) {
  17. User user = new User();
  18. user.setId(id);
  19. user.setName(name);
  20. user.setAge(age);
  21. return userRepository.save(user);
  22. }
  23. }

postman测试

  1. curl -X PUT \
  2. http://127.0.0.1:8080/user/1 \
  3. -H 'cache-control: no-cache' \
  4. -H 'content-type: application/x-www-form-urlencoded' \
  5. -H 'postman-token: 2b717e08-8c07-2dc7-c592-81358617625b' \
  6. -d 'name=%E6%9D%8E%E5%9B%9B&age=20'

返回数据

  1. {
  2. "id": 1,
  3. "name": "李四",
  4. "age": 20
  5. }
  • 删除一个用户信息
  1. @RestController
  2. public class UserController {
  3. // ... 以上内容忽略
  4. /**
  5. * 删除一个用户信息
  6. * @param id
  7. */
  8. @DeleteMapping(value = "/user/{id}")
  9. public void deleteUser(@PathVariable("id") Integer id) {
  10. userRepository.deleteById(id);
  11. }
  12. }

postman测试,删除数据返回为空

  1. curl -X DELETE \
  2. http://127.0.0.1:8080/user/1 \
  3. -H 'cache-control: no-cache' \
  4. -H 'postman-token: 47e13a68-b69a-bf7b-b14c-94ce82865496'

问题排错

  • 问题1:配置datasource可能报以下错误,这是因为添加了数据库依赖,autoconfig会读取数据源配置,因为新建的项目没有配置数据源(问题重点所在)因此抛此异常。
  1. Description:
  2. Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
  3. Reason: Failed to determine a suitable driver class
  4. Action:
  5. Consider the following:
  6. If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
  7. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
  8. Process finished with exit code 1

在启动类的@SpringBootApplication注解上加上exclude= {DataSourceAutoConfiguration.class},将会解除自动加载DataSourceAutoConfiguration。同样还会引发另外一个问题,例如本实例中配置文件里的数据库就不会自动去创建链接。

  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  4. @SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
  5. public class UserApplication { // 启动类
  6. public static void main(String[] args) {
  7. SpringApplication.run(UserApplication.class, args);
  8. }
  9. }
  • 问题2:

链接mysql,启动时候警告以下内容,原因是MySql高版本需要指明是否进行SSL链接

WARN: Establishing SSL connection without server’s identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn’t set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to ‘false’. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.

改正之前代码

  1. spring:
  2. datasource:
  3. driver-class-name: com.mysql.jdbc.Driver
  4. url: jdbc:mysql://127.0.0.1:3306/dbUser
  5. username: root
  6. password: 123456

改正之后代码,useSSL设置为true都可以

  1. spring:
  2. datasource:
  3. driver-class-name: com.mysql.jdbc.Driver
  4. url: jdbc:mysql://127.0.0.1:3306/dbUser?useUnicode=true&characterEncoding=utf-8&useSSL=false
  5. username: root
  6. password: 123456

源码地址 https://github.com/Q-Angelo/SpringBoot-Course/tree/master/chapter2/chapter2-1

mongodb

简介

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案,官方解释。在NoSql数据库中还是比较优秀的一款数据库,且官方网站现在已经逐步开始支持中文版了。 MongoDB 中文版

之前MySql介绍了Spring Data Jpa,对于MongoDB,Spring也提供了强大的支持Spring Data MongoDB,这个项目提供了与MongoDB文档数据库的集成。

注意 在开始之前先开启你的mongod,对于mongodb安装启动有疑问的可以参考这里 Mac系统下安装MongoDB

添加mongodb依赖

项目根目录 pom.xml 添加依赖 spring-boot-starter-data-mongodb

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-mongodb</artifactId>
  4. </dependency>

修改配置文件mongodb相关配置

  • mongo2.4以上版本:

    • uri: 数据库链接地址 mongodb://username:password@ip:host
  • mongo2.4以下版本:

    • host: 127.0.0.1
    • port: 27017
    • username: root
    • password: root
    • database: test

application.yml

  1. spring:
  2. data:
  3. mongodb:
  4. uri: mongodb://127.0.0.1:27017
  5. database: test

定义集合模型

关于Spring Data MongoDB更多注解及使用参考官方文档

在项目启动时候,以下定义的字段会对应到数据库中的数据结构,注意要添加@Document注解。

  • @Document: 标注于实体类上表明由mongo来维护该集合,默认集合名为类名还可手动指定集合名@Document(collection=user)
  • @Id: 主键,自带索引由mongo生成对应mongo中的_id字段(ObjectId)
  • @Indexed: 设置该字段索引,提高查询效率,设置参数(unique=true)为唯一索引,默认为false
  1. package com.angelo;
  2. import org.springframework.data.annotation.Id;
  3. import org.springframework.data.mongodb.core.index.Indexed;
  4. import org.springframework.data.mongodb.core.mapping.Document;
  5. @Document
  6. public class User {
  7. @Id
  8. private String id;
  9. @Indexed
  10. private String name;
  11. private Integer age;
  12. @Indexed(unique = true)
  13. private String idCard;
  14. public User() {
  15. }
  16. // 以下getter、setter方法,代码可以参考本节源码
  17. }

创建继承于mongorepository的数据访问对象

创建UserRepository继承于MongoRepository,当然你也可以使用JpaRepository或MongoRepository,这些接口扩展了mongodb的CRUD操作的通用接口,此外还公开了底层持久化技术的功能,供我们扩展。

例如以下findById,MongoRepository提供的接口为Long类型,显然我这里使用mongodb自动生成的ObjectId,自然是不行了,因此扩展了该方法。

UserRepository.java

  1. package com.angelo;
  2. import org.springframework.data.mongodb.repository.MongoRepository;
  3. import java.util.List;
  4. public interface UserRepository extends MongoRepository<User, Long> {
  5. User findById(String id);
  6. List <User> deleteById(String id);
  7. }

创建控制层实现对数据的增删改查

此处操作Mongodb的增删改查和之前讨论的MySql一样,以下给出代码示例

  1. package com.angelo;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.web.bind.annotation.*;
  4. import java.util.List;
  5. @RestController
  6. public class UserController {
  7. @Autowired
  8. private UserRepository userRepository;
  9. /**
  10. * 查询用户列表
  11. * @return
  12. */
  13. @GetMapping(value = "/user/list")
  14. public List<User> userList() {
  15. return userRepository.findAll();
  16. }
  17. @GetMapping(value = "/user/info")
  18. public User findUserById(@RequestParam("id") String id) {
  19. return userRepository.findById(id);
  20. }
  21. /**
  22. * 创建用户信息
  23. */
  24. @PostMapping(value = "/user")
  25. public User createUser(@RequestBody User params) {
  26. User user = new User();
  27. user.setName(params.getName());
  28. user.setAge(params.getAge());
  29. user.setIdCard(params.getIdCard());
  30. return userRepository.save(user);
  31. }
  32. /**
  33. * 更新用户信息
  34. */
  35. @PutMapping(value = "/user/{id}")
  36. public User updateUser(@PathVariable("id") String id, @RequestParam("name") String name, @RequestParam("age") Integer age,
  37. @RequestParam("idCard") String idCard) {
  38. User user = new User();
  39. user.setId(id);
  40. user.setName(name);
  41. user.setAge(age);
  42. user.setIdCard(idCard);
  43. return userRepository.save(user);
  44. }
  45. /**
  46. * 删除用户信息
  47. * MongoRepository提供的原生方法会报deleteById(java.lang.long) in CurdRepository cannot be applied to (java.lang.string),此处定义的id为String类型显然不符,在UserRepository接口中进行了重写,
  48. */
  49. @DeleteMapping(value = "/user/{id}")
  50. public void deleteUserById(@PathVariable("id") String id) {
  51. userRepository.deleteById(id);
  52. }
  53. }

源码地址 https://github.com/Q-Angelo/SpringBoot-Course/tree/master/chapter2/chapter2-2