MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Java编程中的Spring Boot与数据库集成

2021-03-235.0k 阅读

一、Spring Boot 概述

Spring Boot 是由 Pivotal 团队提供的全新框架,它设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过 Spring Boot,开发者能够快速创建独立的、生产级别的基于 Spring 的应用程序。

Spring Boot 的核心优势在于它的自动配置功能。它会根据项目的依赖情况自动配置 Spring 应用,极大地减少了开发人员手动配置的工作量。例如,当项目中引入了 spring-boot-starter-web 依赖时,Spring Boot 会自动配置好 Spring MVC 和 Tomcat,开发者只需要编写业务代码即可。

另外,Spring Boot 还提供了一系列的 Starter 依赖。Starter 是一种特殊的依赖,它将相关的依赖和配置整合在一起,方便开发者快速引入所需功能。比如 spring-boot-starter-data-jpa 就是用于整合 JPA(Java Persistence API)的 Starter,引入它后就可以方便地使用 JPA 进行数据库操作。

二、数据库集成基础概念

在进行 Spring Boot 与数据库集成之前,我们需要先了解一些数据库集成的基础概念。

(一)JDBC(Java Database Connectivity)

JDBC 是 Java 访问数据库的标准 API,它为数据库开发人员提供了一个标准的、通用的数据库访问方式。通过 JDBC,Java 程序可以连接各种不同类型的数据库,如 MySQL、Oracle、SQL Server 等。JDBC 提供了一系列的接口和类,包括 DriverManager 用于管理数据库驱动,Connection 用于建立与数据库的连接,StatementPreparedStatement 用于执行 SQL 语句等。

以下是一个简单的 JDBC 连接 MySQL 数据库并执行查询的示例代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class JdbcExample {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            // 加载 MySQL 驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 建立连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password");
            stmt = conn.createStatement();
            // 执行查询
            rs = stmt.executeQuery("SELECT * FROM users");
            while (rs.next()) {
                System.out.println(rs.getString("username"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (rs != null) rs.close();
                if (stmt != null) stmt.close();
                if (conn != null) conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

(二)ORM(Object Relational Mapping)

ORM 是一种将对象模型与关系型数据库模型进行映射的技术。在传统的数据库开发中,开发人员需要编写大量的 SQL 语句来实现对象与数据库表之间的转换,这不仅繁琐而且容易出错。ORM 通过使用元数据来描述对象与数据库表之间的映射关系,使得开发人员可以使用面向对象的方式来操作数据库,而无需关心底层的 SQL 语句。

常见的 ORM 框架有 Hibernate、MyBatis 等。以 Hibernate 为例,开发人员只需要定义实体类和映射文件(或者使用注解来配置映射关系),Hibernate 就可以自动将对象的操作转换为相应的 SQL 语句。

三、Spring Boot 与 JDBC 集成

Spring Boot 对 JDBC 的集成非常方便,通过引入 spring-boot-starter-jdbc Starter 依赖,就可以快速实现与数据库的连接和操作。

(一)添加依赖

pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

(二)配置数据源

application.properties 文件中配置数据源相关信息:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

(三)使用 JdbcTemplate 进行数据库操作

Spring Boot 提供了 JdbcTemplate 类来简化 JDBC 操作。JdbcTemplate 封装了 JDBC 的常用操作,如查询、更新等。

以下是一个使用 JdbcTemplate 进行查询的示例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public List<Map<String, Object>> getUsers() {
        String sql = "SELECT * FROM users";
        return jdbcTemplate.queryForList(sql);
    }
}

在上述代码中,通过 @Autowired 注入了 JdbcTemplate,然后在 getUsers 方法中使用 queryForList 方法执行 SQL 查询并返回结果。

四、Spring Boot 与 Hibernate(JPA)集成

JPA 是 Java 持久化 API 的简称,它是一种规范,而 Hibernate 是 JPA 的一种实现。Spring Boot 对 JPA 的集成非常便捷,通过 spring-boot-starter-data-jpa Starter 依赖即可实现。

(一)添加依赖

pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

(二)配置数据源和 JPA

application.properties 文件中配置数据源和 JPA 相关信息:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update

spring.jpa.database-platform 配置了使用的数据库方言,spring.jpa.hibernate.ddl-auto 配置了 Hibernate 启动时对数据库表结构的操作策略,update 表示如果表结构不存在则创建,如果存在则更新。

(三)定义实体类

定义一个 User 实体类,并使用 JPA 注解来配置映射关系:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;

    // 省略 getters 和 setters
}

在上述代码中,@Entity 注解表明该类是一个实体类,@Id 注解标识了主键字段,@GeneratedValue 注解指定了主键生成策略。

(四)定义 Repository 接口

通过定义一个继承自 JpaRepository 的接口,就可以自动获得基本的数据库操作方法,如 savefindByIdfindAll 等。

import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.entity.User;

public interface UserRepository extends JpaRepository<User, Long> {
}

(五)使用 Repository 进行数据库操作

在服务层中注入 UserRepository 并使用其方法进行数据库操作:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> getUsers() {
        return userRepository.findAll();
    }

    public User saveUser(User user) {
        return userRepository.save(user);
    }
}

五、Spring Boot 与 MyBatis 集成

MyBatis 是另一个流行的持久层框架,它提供了 SQL 映射和动态 SQL 等强大功能。Spring Boot 与 MyBatis 的集成也较为简单。

(一)添加依赖

pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

(二)配置数据源

application.properties 文件中配置数据源信息,与前面 JDBC 和 JPA 集成时的配置类似:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

(三)定义实体类

与 JPA 集成时类似,定义 User 实体类:

public class User {

    private Long id;
    private String username;
    private String password;

    // 省略 getters 和 setters
}

(四)定义 Mapper 接口和 XML 映射文件

定义 UserMapper 接口:

import org.apache.ibatis.annotations.Mapper;
import com.example.demo.entity.User;

import java.util.List;

@Mapper
public interface UserMapper {

    List<User> getUsers();

    void saveUser(User user);
}

resources 目录下创建 mapper 目录,并在其中创建 UserMapper.xml 文件:

<?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.example.demo.mapper.UserMapper">
    <select id="getUsers" resultType="com.example.demo.entity.User">
        SELECT * FROM users
    </select>
    <insert id="saveUser" parameterType="com.example.demo.entity.User">
        INSERT INTO users (username, password) VALUES (#{username}, #{password})
    </insert>
</mapper>

(五)配置 MyBatis

application.properties 文件中配置 MyBatis 的 mapper 位置和实体类别名包:

mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.demo.entity

(六)使用 Mapper 进行数据库操作

在服务层中注入 UserMapper 并使用其方法进行数据库操作:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public List<User> getUsers() {
        return userMapper.getUsers();
    }

    public void saveUser(User user) {
        userMapper.saveUser(user);
    }
}

六、事务管理

在数据库集成中,事务管理是非常重要的一部分。事务可以确保一组数据库操作要么全部成功,要么全部失败,从而保证数据的一致性和完整性。

(一)Spring 声明式事务

Spring 提供了声明式事务管理,通过使用 @Transactional 注解,就可以很方便地为方法或类添加事务支持。

在使用 JPA 时,事务管理非常简单。例如,在服务层的方法上添加 @Transactional 注解:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void saveUsers(List<User> users) {
        for (User user : users) {
            userRepository.save(user);
        }
    }
}

在上述代码中,saveUsers 方法会在一个事务中执行,如果其中任何一个 userRepository.save(user) 操作失败,整个事务会回滚,之前保存的用户也会被撤销。

(二)事务传播行为

事务传播行为定义了当一个事务方法被另一个事务方法调用时,应该如何传播事务。Spring 提供了多种事务传播行为,常见的有 PROPAGATION_REQUIRED(默认)、PROPAGATION_REQUIRES_NEWPROPAGATION_NESTED 等。

  1. PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  2. PROPAGATION_REQUIRES_NEW:总是创建一个新的事务。如果当前存在事务,则将当前事务挂起。
  3. PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则创建一个新的事务。

例如,将 UserService 中的 saveUsers 方法的事务传播行为改为 PROPAGATION_REQUIRES_NEW

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void saveUsers(List<User> users) {
        for (User user : users) {
            userRepository.save(user);
        }
    }
}

七、性能优化与注意事项

在 Spring Boot 与数据库集成过程中,性能优化是非常关键的。以下是一些性能优化的建议和注意事项。

(一)合理使用缓存

在频繁读取数据库的场景下,可以考虑使用缓存。Spring Boot 支持多种缓存框架,如 Ehcache、Redis 等。通过在服务层方法上添加 @Cacheable 注解,可以将方法的返回结果缓存起来,下次调用时如果缓存中存在相应数据,则直接从缓存中获取,避免了重复查询数据库。

例如,在 UserService 中添加缓存:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Cacheable("users")
    public List<User> getUsers() {
        return userRepository.findAll();
    }
}

(二)批量操作

在进行数据库插入、更新等操作时,如果数据量较大,应该使用批量操作。例如,在使用 JdbcTemplate 进行插入操作时,可以使用 batchUpdate 方法;在使用 JPA 时,可以通过 saveAll 方法进行批量保存。

使用 JdbcTemplate 进行批量插入:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import com.example.demo.entity.User;

import java.util.List;

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void batchSaveUsers(List<User> users) {
        String sql = "INSERT INTO users (username, password) VALUES (?,?)";
        jdbcTemplate.batchUpdate(sql, users, users.size(), (ps, user) -> {
            ps.setString(1, user.getUsername());
            ps.setString(2, user.getPassword());
        });
    }
}

(三)优化 SQL 语句

编写高效的 SQL 语句是提升数据库性能的关键。要避免使用全表扫描,合理使用索引,对复杂的查询进行优化。例如,在查询语句中使用 EXPLAIN 关键字来分析查询计划,找出性能瓶颈并进行优化。

(四)连接池管理

合理配置数据库连接池的参数也非常重要。连接池的大小、最大连接数、最小连接数等参数都会影响数据库的性能。一般来说,需要根据应用的实际负载情况来调整这些参数,避免连接过多或过少导致的性能问题。

在 Spring Boot 中,如果使用 HikariCP 连接池(默认),可以在 application.properties 文件中配置相关参数:

spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5

八、多数据源集成

在一些复杂的应用场景中,可能需要连接多个数据库,即多数据源集成。Spring Boot 对多数据源集成也提供了一定的支持。

(一)配置多数据源

首先,在 application.properties 文件中配置多个数据源的相关信息:

spring.datasource.first.url=jdbc:mysql://localhost:3306/first_db
spring.datasource.first.username=root
spring.datasource.first.password=password
spring.datasource.first.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.second.url=jdbc:mysql://localhost:3306/second_db
spring.datasource.second.username=root
spring.datasource.second.password=password
spring.datasource.second.driver-class-name=com.mysql.cj.jdbc.Driver

(二)创建数据源配置类

分别为两个数据源创建配置类,例如:

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class FirstDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.first")
    public DataSource firstDataSource() {
        return new BasicDataSource();
    }

    @Bean
    public JdbcTemplate firstJdbcTemplate(@Qualifier("firstDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class SecondDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.second")
    public DataSource secondDataSource() {
        return new BasicDataSource();
    }

    @Bean
    public JdbcTemplate secondJdbcTemplate(@Qualifier("secondDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

(三)使用多数据源

在需要使用不同数据源的地方,通过注入相应的 JdbcTemplate 来进行数据库操作。例如:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class MultiDataSourceService {

    @Autowired
    private JdbcTemplate firstJdbcTemplate;

    @Autowired
    private JdbcTemplate secondJdbcTemplate;

    public void operateOnFirstDataSource() {
        firstJdbcTemplate.update("INSERT INTO first_table (column1) VALUES ('value1')");
    }

    public void operateOnSecondDataSource() {
        secondJdbcTemplate.update("INSERT INTO second_table (column1) VALUES ('value1')");
    }
}

通过以上步骤,就可以实现 Spring Boot 与多数据源的集成,满足复杂业务场景下对不同数据库的操作需求。

通过对 Spring Boot 与数据库集成的各个方面进行深入探讨,包括基础概念、各种集成方式、事务管理、性能优化以及多数据源集成等,开发者可以根据实际项目需求,选择合适的集成方案,构建高效、稳定的数据库访问层。