Spring Boot教程之四十七:Spring Boot ——JDBC
Spring Boot – JDBC
Spring Boot JDBC用于通过提供库和启动器依赖项将Spring Boot 应用程序与JDBC连接起来。Spring Boot JDBC 对正在编写的 SQL 查询具有一定程度的控制。Spring Boot JDBC 通过使用自动配置的概念自动化工作和步骤,简化了 Spring JDBC 的工作。JdbcTemplate 、DataSource、NamedParameterJdbcTemplate等所有必需的对象都是自动配置的,对象创建由 Spring Boot 完成。
要从头开始构建应用程序,您只需使用 JdbcTemplate。作为程序员,您需要自动连接JdbcTemplate并执行数据库操作,如创建、检索、更新和删除。输入需要通过application.properties或application.yml 文件传递。在 application.properties 文件中,我们配置数据源和连接池。
JDBC 由两部分组成,如下所示:
- JDBC 接口:java.sql / javax.sql包有 JDBC API 的类/接口。
- JDBC 驱动程序:JDBC 驱动程序 允许 Java 程序与数据库交互。
Spring Boot 提供了多种使用数据库的方法(例如 – JdbcTemplate),而无需 JDBC 所需的繁琐工作。您可以使用原始 JDBC 手动配置工作。
JDBC 连接池
JDBC 连接池是一种使数据库连接可供多个客户端重复使用的机制,因此可以减轻数据库服务器的负担。连接池包含一组池化连接或可重复使用的连接。
当我们使用 DriverManager 或 DataSource 时,使用 DataSource 打开的连接是不可重用的。对于每个客户端,如果打开一个新连接,数据库服务器的负担就会增加。因此,为了减轻数据库服务器的负担,我们使用连接池。
连接池的工作原理
- 服务器管理员准备一个具有 setoff 连接的连接池以及一个中介对象作为 DataSource API 来访问该池。
- 管理员将DataSource对象存储到JNDI(Java命名目录接口)中。
- 应用程序从 JNDI 注册表读取数据源并从池中请求连接。
- DataSource 对象从池中获取连接并创建到该连接的代理或逻辑连接,然后将代理连接感知到 Java。
- 当 Java 程序关闭代理连接时,DataSource 将会将真正的连接返回到池中。
要使用 Spring Boot 操作数据库,我们需要添加以下依赖项:
A. JDBC API
数据库连接 API 指定客户端如何连接和查询数据库。
pom.xml Maven依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
B.MySQL 驱动程序
MySQL JDBC 和 R2DBC 驱动程序与数据库协同工作。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
此后,我们将在application.properties文件中添加数据源属性:
对于 MySQL 数据库:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:8080/test spring.datasource.username=root spring.datasource.password=root
项目结构
应用程序的实现
A.pom.xml(配置文件)
- XML
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>sia</groupId> <artifactId>GFG</artifactId> <version>0.0.1-SNAPSHOT</version> <name>GFG</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build>
</project> |
B.Spring应用程序的启动(GfgApplication.java)
- Java
// Java Program to Illustrate Boot of Spring Application
package gfg;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
// Annotation @SpringBootApplication
// Application(Main) Class public class GfgApplication {
// Main driver method public static void main(String[] args) {
SpringApplication.run(GfgApplication.class, args); } } |
C.DataSource的配置(ConfigDataSource.java)
DataSourceBuilder<T> 是一个用于构建数据源的有用类。
- org.springframework.boot.jdbc.DataSourceBuilder<T> - public final class DataSourceBuilder<T extends DataSource> extends Object
DataSourceBuilder<T> 类的方法
方法 | 描述 |
create() | 创建DataSourceBuilder 的新实例。 |
driverClassName(String driverClassName) | 指定用于构建数据源的驱动程序类名。 |
url(String url) | 指定用于构建数据源的URL 。 |
username(String username) | 指定用于构建数据源的用户名。 |
password(String password) | 指定用于构建数据源的密码。 |
build() | 返回一个新创建的DataSource实例。 |
该构建器支持以下池数据源实现。
数据源 | 描述 |
Hikari | com.zaxxer.hikari.HikariDataSource |
Tomcat JDBC Pool | org.apache.tomcat.jdbc.pool.数据源 |
Apache DBCP2 | org.apache.commons.dbcp2.BasicDataSource |
Oracle UCP | oracle.ucp.jdbc.PoolDataSourceImpl |
注意:当没有明确设置类型时,将使用第一个可用的池实现。
例子:
- Java
// Java Program Illustrating Configuration of // DataSourceConfiguration of DataSource
package gfg;
import javax.sql.DataSource; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
// Annotation @Configuration
// Class public class ConfigDataSource {
@Bean public static DataSource source() {
DataSourceBuilder<?> dSB = DataSourceBuilder.create(); dSB.driverClassName("com.mysql.jdbc.Driver");
// MySQL specific url with database name dSB.url("jdbc:mysql://localhost:3306/userdetails");
// MySQL username credential dSB.username("user");
// MySQL password credential dSB.password("password");
return dSB.build(); } } |
注意:驱动程序类名 – 'com.mysql.jdbc.Driver' 已被弃用。它不会出错,因为驱动程序是自动加载的,不需要手动加载。新的驱动程序类名为 ' com.mysql.cj.jdbc.Driver '。
D.要存储在数据库中的用户凭证(UserDetails.java)
可以添加“Lombok”库来跳过 Getter/Setter 方法、构造无参数构造函数、最终字段的构造函数等。
Maven-pom.xml 依赖
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
例子:
- Java
// Java Program Illustrating User Credentials to // be Stored in the Database
package geek.details;
import lombok.Data;
// Annotation for Getter/Setter methods @Data public class UserDetails {
String user; String userName; String password; } |
E.连接和查询数据库的实用程序类(JDBC.java)
出于许多安全原因,密码编码是必须的。要使用 Spring Security,请添加以下依赖项:
Maven – pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency>
先决条件如下:
- 添加上述依赖项后,登录页面将默认激活。
- 默认用户名是“用户”。
- 密码由 Spring Security 自动生成,并在启动应用程序后显示在控制台上。
注意:生成的密码在下一次迭代/运行应用程序时无效,因为会生成新密码,但用户名保持不变。
- 对于编码,Spring 提供了许多方法,例如“BCryptPasswordEncoder”。
- 它是使用 BCrypt 强散列算法的 PasswordEncoder 的实现。
- 可以修改 Version、Strength 和 SecureRandom 实例。
- org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder - public class BCryptPasswordEncoder extends java.lang.Object implements PasswordEncoder
BCryptPasswordEncoder 类的构造函数:
构造函数 | 描述 |
BCryptPasswordEncoder() | 默认构造函数。 |
BCryptPasswordEncoder(int strength) | 强度是 4 到 31 之间使用的对数回合。默认值为 10。 |
BCryptPasswordEncoder( int strength, SecureRandom random ) | 要使用的安全随机实例。 |
BCryptPasswordEncoder( BCryptVersion version ) | BCrypt 版本 — 2a、2b、2y。 |
BCryptPasswordEncoder( BCryptVersion version, int strength ) | Bcrypt 版本/对数轮次。 |
BCryptPasswordEncoder( BCryptVersion version, int strength, SecureRandom random ) | Bcrypt 版本/对数轮次/安全随机实例。 |
BCryptPasswordEncoder( BCryptVersion version, SecureRandom random ) | Bcrypt 版本/安全随机实例。 |
BCryptPasswordEncoder 类的方法:
方法 | 描述 |
encode(CharSequence rawPassword) | 对使用 SHA-1 或更高哈希值以及 8 字节或更大的随机生成的盐值提供的原始密码进行编码。 |
matches(CharSequence rawPassword, String encodedPassword) | 验证存储的编码密码是否与提交的编码原始密码匹配。如果匹配则返回 true,否则返回 false。 |
upgradeEncoding(String encodedPassword) | 如果为了提高安全性需要对已编码的密码再次进行编码,则返回 true,否则返回 false。默认实现始终返回 false。 |
例子:
- Java
// Java Program Illustrating Utility class for Connecting // and Querying the Database
package gfg;
import geek.details.UserDetails; import java.security.SecureRandom; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import javax.sql.DataSource; import lombok.extern.slf4j.Slf4j; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
// Annotation to provide logging feature @Slf4j
// Class public class JDBC {
public int insert(UserDetails user) { DataSource dataSource = null; Connection connection = null; PreparedStatement prepStatement = null;
int result = 0; try {
// Get the configured datasourse dataSource = ConfigDataSource.source(); // Attempt for connection to MySQL connection = dataSource.getConnection(); prepStatement = connection.prepareStatement( "insert into user (user,username,password) values (?,?,?)"); prepStatement.setString(1, user.getUser()); prepStatement.setString(2, user.getUserName());
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder( 10, new SecureRandom()); String encodedPassword = bCryptPasswordEncoder.encode( user.getPassword());
prepStatement.setString(3, encodedPassword); result = prepStatement.executeUpdate(); } catch (SQLException e) { log.getName(); }
return result; } } |
F.Spring应用的控制器(JdbcController.java)
- Java
// Java Program to Illustrate Controller of Spring Application
package gfg;
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping;
import geek.details.UserDetails;
@Controller @RequestMapping("/jdbc") public class JdbcController {
@GetMapping public String get(Model model) {
// Add object to be bound by user provided details model.addAttribute("obj", new UserDetails()); return "template"; }
@PostMapping public String post(@ModelAttribute("obj") UserDetails user, Model model) {
JDBC SQL = new JDBC(); int result = SQL.insert(user); if(result == 1) model.addAttribute("message", "Successful JDBC connection and execution of SQL statement"); else model.addAttribute("message", "Query not submitted!"); return "Status"; } } |
模板(Thymeleaf)
A. template.html:获取用户数据并将其绑定到 UserDetails 对象。
- HTML
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <title>GFG</title> </head> <body> <h1>Register Geek</h1>
<form method="POST" th:action="@{/jdbc}" th:object="${obj}">
<label for="user">User: </label><br/> <input type="text" th:field="*{user}"/><br/>
<label for="username">Username: </label><br/> <input type="text" th:field="*{userName}"/><br/>
<label for="password">Password: </label><br/> <input type="password" th:field="*{password}"/>
<input type="submit" value="Register"/>
</form> </body> </html> |
输出:
填写用户详细信息
B. 状态.html
显示JDBC操作的消息。
- HTML
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <title>GFG</title> </head> <body> <h1>STATUS</h1> <h2 th:text="${message}"> <span>message will print here</span> </h2> </body> </html> |
浏览器中的输出:
C.MySQL 数据库
输出:
注意: Spring Boot 提供了许多方便的数据处理方式,例如 Spring Data JPA – 它具有 Hibernate 的默认实现。我们可以利用它们来利用 Java 持久性 API (JPA) 进行对象/关系映射,并避免繁琐的工作。