【官方教程翻译】SpringBoot 通过 Spring Data JPA 使用 MySQL
在项目初始化的部分有删减
本文带你了解如何创建一个连接到 MySQL 数据库的 Spring 应用。本文会使用 Spring Data JPA 来连接数据库。用户也可以根据需要选择其他的库(比如直接用 Spring JDBC )
最终目标
本文会带你创建一个 MySQL 数据库和一个 Spring 应用,并在 Spring 应用中连接到新创建的数据库。
示例代码见 github.com/spring-guid…
使用 Spring Initializr 创建项目
访问 start.spring.io ,在依赖列表选中 Spring Web 、 Spring Data JPA 和 MySQL Driver ,然后将初始化好的包下载下来,使用 IDE 打开即可
创建数据库
在终端中打开 MySQL
$ sudo mysql --password
在 mysql 命令行界面中,使用下面的命令创建一个新数据库
mysql> create database db_example; -- 创建新数据库
mysql> create user 'springuser'@'%' identified by 'ThePassword'; -- 创建用户
mysql> grant all on db_example.* to 'springuser'@'%'; -- 为新用户赋予所有权限
创建 application.properties
文件
Spring Boot 本身做了一大堆的默认设置。例如默认的数据库为 H2
。因此,当我们要换一个数据库的时候,就需要在 application.properties
文件中显式进行配置。
创建资源文件: src/main/resources/application.properties
,添加如下内容:
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword
spring,datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.jpa.show-sql: true
上面的 spring.jpa.hibernate.ddl-auto
值可以为 none
, update
, create
或 create-drop
。详情请阅读 hibernate 文档 。
none
:MySQL
的默认值。不会改变数据库结构;update
:Hibernate 将根据给定的实体结构来修改数据库(如果启动时格式不一致,会更新表,并保留原数据);create
:每次都创建数据库,如果没有表会新建表,如果表内已经有数据则会更新结构,而且不会在关闭时删库;create-drop
:创建数据库并在SessionFactory
关闭时删库(也就是每次程序关闭时清空表)。
译注:这里的“修改”指的是修改数据库结构
最开始,该值必须设置为 create
或 update
——因为此时还没有任何数据库结构。在首次运行后,即可根据应用需要,将该值改为 update
或 none
——例如当需要改变数据库结构时,可将该值设置为 update
Spring Boot 为 H2
等嵌入式数据库准备的默认值是 create-drop
。对于 MySQL 等其他数据库,默认值是 none
。
为增强安全性,建议在连接生产环境的数据库时将值改为
none
,并收回 Spring Boot 所使用的数据库用户的所有权限,只保留最基本的增删改查权限。更多关于安全的内容可见本文文末。
创建 @Entity
模型
接下来需要创建数据实体的模型(src/main/java/com/example/accessingdatamysql/User.data):
package com.example.accessingdatamysql;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity // 该注解告诉 Hibernate 从该类中创建一个表
public class User {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private String email;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Hibernate 会自动将实体翻译为表。
创建仓库
然后需要创建一个存储用户记录的仓库,代码如下:
(代码位于 src/main/java/com/example/accessingdatamysql/UserRepository.java )
package com.example.accessingdatamysql;
import org.springframework.data.repository.CrudRepository;
import com.example.accessingdatamysql.User;
public interface UserRepository extends CrudRepository<User, Integer> {
}
创建控制器
我们需要创建一个控制器来处理 HTTP 请求,代码如下:
(代码位于 src/main/java/com/example/accessingdatamysql/MainController.java )
package com.example.accessingdatamysql;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ReponseBody;
@Controller // 表明该类是一个控制器
@RequestMapping(path="/demo")
public class MainController {
/**
* 该注解意味着要获取名为 userRepository 的 bean,
* 该 bean 是由 Spring 自动生成的,我们会用它来处理数据
*/
@Autowired
private UserRepository userRepository;
@PostMapping(path="/add")
public @ResponseBody String addNewUser(@RequestParam String name, @RequestParam String email) {
/**@ResponseBody 说明该函数返回的字符串是一个 response ,而不是 view 名称
* @RequestParam 说明该参数是来自 GET 或 POST 的
*/
User n = new User();
n.setName(name);
n.setEmail(email);
userRepository.save(n);
return "Saved";
}
@GetMapping(path="/all")
public @ResponseBody Iterable<User> getAllUsers() {
// 该函数返回一个 JSON 或 XML 形式的 user 列表
return userRepository.findAll();
}
}
上面的例子中为两个请求地址显式指明了
POST
和GET
方法。默认情况下,@RequestMapping
能够映射所有类型的 HTTP 操作
创建应用类( Application Class )
Spring Initializr 会为应用创建一个简单的类。如下:
package com.example.accessingdatamysql;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AccessingDataMysqlApplication {
public static void main(String[] args) {
SpringApplication.run(AccessingDataMysqlApplication.class, args);
}
}
在这个例子中,我们不需要修改该类
@SpringBootApplication
是下面三个注解的简写:
@Configuration
: 将类标记为应用上下文( application context )bean 的定义;@EnableAutoConfiguration
:让 Spring Boot 根据 classpath 设置、其他的属性设置( various property settings )等来添加 bean 。例如:如果 classpath 中有一个spring-webmvc
,那么该标记就会将应用程序标记为一个 web 应用,并启用相关的行为——比如启动一个DispatcherServlet
;@ComponentScan
:让 Spring 寻找在com/example
包下面的其他组件、配置、服务等,并找到所有的控制器。
main()
方法使用 Spring Boot 的 SpringApplication.run()
函数来启动应用。
创建可运行的 JAR 文件
测试应用
启动应用后,我们可以用 curl
这类工具来进行测试:
GET localhost:8080/demo/all
获取所有数据。POST localhost:8080/demo/add
向数据中添加一个新用户。
例如,下面的命令将添加一个新用户:
$ curl localhost:8080/demo/add -d name=First -d email=someemail@someemailprovider.com
服务器将返回:
Saved
下面的命令将展示所有已有的用户:
$ curl 'localhost:8080/demo/all'
服务器将返回:
[{"id":1,"name":"First","email":"someemail@someemailprovider.com"}]
增强安全性
在实际的生产环境中,我们需要针对 SQL 注入攻击进行防御——黑客可能会注入如 DROP TABLE
或其他毁灭性的 SQL 指令。因此,我们需要在对外提供应用前对数据库进行一些修改。
下面的命令能够收回所有 Spring 应用使用的数据库用户所拥有的特权:
mysql> revoke all on db_example.* from 'springuser'@'%';
这样一来,Spring 应用就无法对数据库本身进行任何修改了。
然而,应用必须有一些最小的权限,下面的命令能够确保应用拥有这些权限:
mysql> grant select, insert, delete, update on db_example.* to 'springuser'@'%';
这样将只保留 Spring 应用修改数据内容的权限,而不能对数据库结构( schema )进行修改
当需要修改数据库时,可以:
- 重新分配权限;
- 修改
spring.jpa.hibernate.ddl-auto
值为update
; - 重新运行程序
然后再重复执行上面的两条命令,恢复安全性。如果条件允许,最好使用独立的迁移工具如 Flyway 或 Liquibase
转载自:https://juejin.cn/post/7076670262317416455