【译】Когда использовать Spring 6 JdbcClient

原文地址:JdbcClient Spring 6: когда и как его использовать?

Введение

Начиная сSpring 6.1, JdbcClient является JDBC Операции запроса и обновления предоставляют унифицированный клиентский API, обеспечивая тем самым более плавную и упрощенную модель взаимодействия. В этом руководстве показано, как использовать JdbcClient в различных сценариях.

2. Методы доступа к базе данных в Spring

Spring Framework предоставляет несколько различных методов доступа к базе данных. Два популярных метода:

  • Унифицированный API для прямого выполнения операторов SQL, таких как JdbcTemplate.
  • Поддержка инфраструктуры ORM, такой как Hibernate, JPA.

Унифицированный API обеспечивает простой и эффективный подход, позволяющий разработчикам более простым образом обрабатывать запросы SQL. Ключевые компоненты этого подхода включают: JdbcTemplate, NamedParameterJdbcTemplate и JdbcClient.

Среды объектно-реляционного сопоставления (ORM), такие как Hibernate, предоставляют уровень абстракции для реляционных баз данных, позволяя разработчикам взаимодействовать с базой данных, используя объектно-ориентированную парадигму. Это позволяет разработчикам сопоставлять объекты Java с таблицами базы данных, инкапсулируя и изолируя детали запросов SQL.

Выбор между прямым выполнением SQL и поддержкой платформы ORM зависит от множества факторов, включая сложность приложения, предпочтения разработчика и конкретные требования проекта. Прямое выполнение SQL предпочтительнее из-за его простоты и управляемости, в то время как платформы ORM превосходны там, где приоритет отдается объектно-ориентированному проектированию и абстракции.

3. Разница между JdbcClient и JdbcTemplate

JdbcTemplate — это базовый класс Spring Data, который упрощает использование JDBC и устраняет большой объем кода шаблонов, связанный с традиционным использованием JDBC. Он предоставляет методы для выполнения SQL-запросов, обновлений и хранимых процедур.

Он имеет следующие особенности:

  • Выполнение SQL-запросов, обновлений и хранимых процедур.
  • Передайте параметры запроса, используя заполнитель ?
  • Сопоставление строк результатов запроса с помощью RowMapper или ResultSetExtractor

Возьмите следующий код в качестве примера

public int getCountOfUsers(String name) {
    
    

  String sql = "SELECT COUNT(*) FROM users WHERE name = ?";
  return jdbcTemplate.queryForObject(sql, Integer.class, name);
}```


JdbcClientSpring 6.1 中引入的增强型统一 JDBC 客户端 API,为命名和位置参数语句提供了流畅的交互模型。它旨在进一步简化 JDBC 操作。

它具有以下功能:

 - 统一支持命名参数和位置参数
 - 旨在进一步简化 JDBC 操作
 - 作为不断发展的 Spring 框架的一部分引入

以下面的代码为例

```java
public int getCountOfUsers(String name) {
    
    

  return jdbcClient.sql("SELECT COUNT(*) FROM users WHERE name = ?")
    .param(name)
    .query(Integer.class)
    .single();
}

Выбор между JdbcTemplate и JdbcClient зависит от контекста проекта, версии Spring и предпочтений разработчика. Оба инструмента упрощают взаимодействие с базой данных, и каждый из них имеет свои преимущества и варианты использования.

4. Начните использовать JdbcClient

4.1. Мавен

Чтобы использовать JdbcClient в приложении Spring, мы должны убедиться, что в проекте используется минимальная версия Spring 6.1 или Spring Boot 3.2.

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.2.0-M2</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <!-- other dependencies -->
</dependencies>

4.2. Конфигурация и инициализация

Чтобы настроить JdbcClient, убедитесь, что класс Repository содержит компонент DataSource.

После настройки экземпляры класса JdbcClient становятся потокобезопасными. Распространенным подходом является внедрение зависимости DataSource Bean в класс Repository/Dao. JdbcClient создается в конструкторе репозитория с помощью оператора JdbcClient.create(). Платформа Spring автоматически внедрит bean-компоненты DataSource с помощью внедрения конструктора.

@Repository
public class PersonRepository {
    
    

  private final JdbcClient jdbcClient;

  public PersonRepository(DataSource dataSource) {
    
    
    this.jdbcClient = JdbcClient.create(dataSource);
  }

  //...
}

4.3 Простой пример использования JdbClient

После создания экземпляра JdbcClient мы можем использовать его удобные методы для выполнения SQL-запросов.

public Optional<Person> findById(Long id) {
    
    

  String sql = "select id, first_name, last_name, created_at from person where id = :id";

  return jdbcClient.sql(sql)
    .param("id", id)
    .query((rs, rowNum) -> new Person(
        rs.getInt("id"), 
        rs.getString("first_name"), 
        rs.getString("last_name"), 
        rs.getTimestamp("created_at").toInstant()))
    .optional();
}

5. Передача параметров для операторов SQL

API JdbcClient очень гибок в приеме параметров SQL. Давайте рассмотрим несколько методов.

5.1.Позиционные параметры

Позиционные параметры — это заполнители в операторе запроса, определяемые порядком их позиции в операторе. Используются ли эти параметры в качестве заполнителей в операторах SQL?

В следующем примере параметры запроса first_name, Last_name и Create_at неявно регистрируются в том порядке, в котором они назначены методу StatementSpec.param().

String sql = "insert into person(first_name, last_name, created_at) values (?, ?, ?)";

jdbcClient.sql(sql)
  .param("Alex")
  .param("Dave")
  .param(Timestamp.from(Instant.now()))
  .update();

Мы также можем передать параметры как var-args, используя метод StatementSpec.params() следующим образом:

jdbcClient.sql(sql)
  .params("Alex", "Dave", Timestamp.from(Instant.now()))
  .update(keyHolder);

Кроме того, параметры можно передавать в виде списка.

jdbcClient.sql(sql)
  .params(List.of("Alex", "Dave", Timestamp.from(Instant.now())))
  .update(keyHolder);

Если мы хотим дополнительно гарантировать, что параметры связаны в правильном порядке, мы можем даже передать индекс параметра, просто на всякий случай.

jdbcClient.sql(sql)
  .param(1, "Alex")
  .param(2, "Dave")
  .param(3, Timestamp.from(Instant.now()))
  .update()

5.2.Именованные параметры

Подобно NamedParameterJdbcTemplate, JdbcClient также поддерживает именование параметров операторов SQL с использованием формата заполнителя «:paramName».

String sql = "insert into person(first_name, last_name, created_at) values (:firstName, :lastName, :createdAt)";

jdbcClient.sql(sql)
  .param("firstName, "Alex")
  .param("lastName", "Dave")
  .param("createdAt", Timestamp.from(Instant.now()))
  .update();

Именованные параметры также можно передавать в виде карты, где ключи представляют именованные параметры, а значения передаются в запрос во время выполнения.

Map<String, ?> paramMap = Map.of(
  "firstName", "Alex",
  "lastName", "Dave",
  "createdAt", Timestamp.from(Instant.now())
);

jdbcClient.sql(sql)
  .params(paramMap)
  .update();

5.3 Параметры экземпляра объекта (Источник параметров)

Чтобы упростить задачу, вы также можете передать объект (класс записи, класс со свойствами компонента или обычный держатель поля), имена полей которого соответствуют именованным параметрам.

В следующем примере мы выполняем операцию INSERT в базе данных, используя значения из объекта Person.

Person person = new Person(null, "Clark", "Kent", Instant.now());

jdbcClient.sql(sql)
  .paramSource(person)
  .update();

Класс Person — это тип записи, имена полей которого соответствуют именованным параметрам.

public record Person(Long id, String firstName, String lastName, Instant createdAt) {
    
    
}

Аналогично мы также можем использовать стратегии SimplePropertySqlParameterSource и BeanPropertySqlParameterSource.

SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(person);

jdbcClient.sql(sql)
  .paramSource(namedParameters)
  .update();

6. Сопоставление наборов результатов с объектами

6.1 Использование пользовательского RowMapper

При запросе строк из базы данных мы можем использовать набор результатов для получения значения столбца, как показано в разделе 3.3. Но если мы хотим повысить гибкость и простоту кода, мы можем рассмотреть возможность использования RowMapper.

Следующий класс PersonRowMapper реализует интерфейс RowMapper и переопределяет метод mapRow(), который содержит логику сопоставления строк базы данных с экземплярами Person.

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
import com.howtodoinjava.model.Person;
import org.springframework.jdbc.core.RowMapper;

public class PersonRowMapper implements RowMapper<Person> {
    
    

  private PersonRowMapper() {
    
    }

  private static final PersonRowMapper INSTANCE = new PersonRowMapper();

  public static PersonRowMapper getInstance() {
    
    
    return INSTANCE;
  }

  @Override
  public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
    
    
    return new Person(
      rs.getLong("id"),
      rs.getString("first_name"),
      rs.getString("last_name"),
      getInstantFromTimestamp(rs.getTimestamp("created_at"))
    );
  }

  private Instant getInstantFromTimestamp(Timestamp timestamp) {
    
    
    return (timestamp != null) ? timestamp.toInstant() : null;
  }
}

Теперь мы можем использовать PersonRowMapper в методе query(), а Spring будет использовать сопоставитель внутри себя и напрямую получать экземпляр Person.

String querySql = "select id, first_name, last_name, created_at from person where id = :id";

Optional<Person> personOptional = jdbcClient.sql(querySql)
  .param("id", 1)
  .query(PersonRowMapper.getInstance())
  .optional();

6.2 Использование сопоставления классов

Если создание PersonRowMapper слишком трудоемко, поскольку между полем класса и столбцом базы данных существует прямое сопоставление полей, можно передать тип класса непосредственно в метод query().

String querySql = "select id, first_name, last_name, created_at from person where id = :id";

Optional<Person> personOptional = jdbcClient.sql(querySql)
  .param("id", 1)
  .query(Person.class)
  .optional();

Примечание переводчика: давайте еще раз посмотрим на то, как определяется класс записи Person.Похоже, что преобразование между именами, разделенными подчеркиванием, и именованием в верблюжьем регистре будет завершено автоматически.

public record Person(Long id, String firstName, String lastName, Instant createdAt) {
    
    
}

7. SQL-запросы и операции обновления.

JdbcClient поддерживает все типы операций с базой данных, такие как выбор, создание, обновление и удаление записей.

  • Метод query() выполняет заданный запрос SQL. Возвращенные результаты запроса предоставляют несколько методов инкапсуляции, таких как класс сопоставления (Class Mapping) и преобразователь строк (RowMapper). , обработчик обратного вызова строк (RowCallbackHandler) и экстрактор набора результатов (ResultSetExtractor)
  • Метод update() выполняет предоставленный оператор SQL как обновление. Он всегда возвращает целое число затронутых строк.

Примеры этих методов были представлены в предыдущих главах и не будут описываться снова.

8. Рекомендации по пакетной вставке и хранимым процедурам

JdbcClient — это гибкий, но очень упрощенный интерфейс только для операторов запроса/обновления JDBC. Если вам нужно сделать что-то более сложное, например выполнить пакетную операцию или вызвать хранимую процедуру i=4>, JdbcClient может не предоставить все необходимые вам функции.

В этом случае вы можете использовать другие инструменты Spring, например SimpleJdbcInsert или SimpleJdbcCall.

Альтернативно вы можете напрямую использовать более простой JdbcTemplate для выполнения задач, которые JdbcClient не может полностью решить. Это похоже на то, что в наборе инструментов есть разные инструменты, и вы можете выбрать наиболее подходящий инструмент в соответствии с потребностями работы.

9. Заключение

В этом руководстве мы рассмотрели первоначальную конфигурацию и основы использования Spring 6 JdbcClient для операций запроса и обновления. Как упоминалось ранее, JdbcClient предоставляет упрощенный и унифицированный API для взаимодействия с JDBC, что делает код более кратким и читабельным.

Получайте удовольствие от учебы

Адрес исходного кода на Github

Guess you like

Origin blog.csdn.net/xieshaohu/article/details/134544734