Статьи

Укажите именованные параметры с помощью NamedParameterJdbcTemplate

В этой статье мы рассмотрим, как использовать NamedParameterJdbcTemplate в загрузочном приложении Spring, подключенном к базе данных Postgres в бэкэнде. Мы будем вставлять, обновлять и удалять сотрудников из Postgres DB, используя NamedParameterJdbcTemplate. Просто чтобы сохранить дизайн соответствующим образом, я отделил dao, сервис и контроллер. Сервис — это просто проход в этой статье.

обзор

NamedParameterJdbcTemplate — это шаблонный класс, который допускает базовый набор операций JDBC. Он имеет базовый классический JdbcTemplate, который позволяет запускать нативные SQL-запросы с ‘?’ заполнители во время выполнения подготовленных заявлений. NamedParameterJdbcTemplate реализует интерфейс NamedParameterJdbcOperations и содержит ссылку на объект JdbcTemplate в интерфейсе JdbcOperations.

Предпосылки

  1. jdk1.8 установлен
  2. Postgres 10.x установлен

Давайте настроим проект сейчас:

  • Загрузите пример проекта Spring Boot с https://start.spring.io/
  • Обновите файл pom.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 http://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.1.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.sample</groupId>
<artifactId>postgress</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>postgress</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

spring-boot-starter-jdbcАртефакт выдаст все jar-файлы, связанные с jdbc, и org.postgresql.postgresqlбудет зависеть от драйвера Postgres jdbc во время выполнения.

  • Создайте schema.sql в папке ресурсов. Таблица сотрудника будет создана при запуске сервера. Это можно игнорировать, если вы не хотите, чтобы исходная база данных была настроена во время запуска сервера. Как правило, для создания готовых приложений этот шаг можно игнорировать, так как таблицы будут создаваться с помощью сценария непосредственно в БД.
CREATE TABLE employee
(
 employeeName varchar(100) NOT NULL,
  employeeId varchar(11) NOT NULL ,
 employeeAddress varchar(100) DEFAULT NULL,
 employeeEmail varchar(100) DEFAULT NULL,
 PRIMARY KEY (employeeId)
);
  • Создайте data.sql в папке ресурсов для загрузки первого набора сотрудников во время запуска. Иначе можно пропустить:

insert into employee(employeeId, employeeName , employeeAddress,employeeEmail) values('1','Jack','USA','jack@gmail.com');

  • Изменения в application.properties для настройки источника данных с URL, именем пользователя и паролем БД Postgres. 5432 порт по умолчанию Postgres. Hibernate автоматически выберет PostgresSQLDialect.
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.show-sql=true
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=admin


spring.datasource.initialization-mode=always
spring.datasource.initialize=true
spring.datasource.schema=classpath:/schema.sql
spring.datasource.continue-on-error=true

spring.jpa.hibernate.ddl-autoотключит автоматическое создание таблиц в спящем режиме из объектов-сущностей. Обычно Hibernate запускает его, если определен объект. Но мы будем использовать собственный SQL-запрос с JdbcTemplate, поэтому мы можем отключить это, поскольку не будем создавать никаких сущностей.

spring.datasource.initialization-modeпомечен как всегда, поскольку мы хотим, чтобы инициализация базы данных происходила при каждом запуске. Это необязательно и сделано для этой цели.

spring.datasource.initialize=true отметит инициализацию как истинную.

spring.datasource.continue-on-error=true продолжит запуск приложения, несмотря на любую ошибку в инициализации данных.

spring.datasource.schema путь к схеме, который необходимо инициализировать.

spring.datasource.urlURL БД Postgres. Это может быть и удаленная БД.

spring.datasource.username имя пользователя для базы данных

spring.datasource.password пароль для базы данных

  • Создать дао интерфейс и дао реализацию
package com.sample.postgress.dao;

import java.util.List;

import com.sample.postgress.entity.Employee;

public interface EmployeeDao {

List<Employee> findAll();

void insertEmployee(Employee emp);

void updateEmployee(Employee emp);

void executeUpdateEmployee(Employee emp);

public void deleteEmployee(Employee emp);
}
package com.sample.postgress.dao;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;

import com.sample.postgress.entity.Employee;
import com.sample.postgress.mapper.EmployeeRowMapper;
@Repository
public class EmployeeDaoImpl implements EmployeeDao{

public EmployeeDaoImpl(NamedParameterJdbcTemplate template) {  
        this.template = template;  
}  
NamedParameterJdbcTemplate template;  

@Override
public List<Employee> findAll() {
return template.query("select * from employee", new EmployeeRowMapper());
}
@Override
public void insertEmployee(Employee emp) {
 final String sql = "insert into employee(employeeId, employeeName , employeeAddress,employeeEmail) values(:employeeId,:employeeName,:employeeEmail,:employeeAddress)";

        KeyHolder holder = new GeneratedKeyHolder();
        SqlParameterSource param = new MapSqlParameterSource()
.addValue("employeeId", emp.getEmployeeId())
.addValue("employeeName", emp.getEmployeeName())
.addValue("employeeEmail", emp.getEmployeeEmail())
.addValue("employeeAddress", emp.getEmployeeAddress());
        template.update(sql,param, holder);

}

@Override
public void updateEmployee(Employee emp) {
 final String sql = "update employee set employeeName=:employeeName, employeeAddress=:employeeAddress, employeeEmail=:employeeEmail where employeeId=:employeeId";

        KeyHolder holder = new GeneratedKeyHolder();
        SqlParameterSource param = new MapSqlParameterSource()
.addValue("employeeId", emp.getEmployeeId())
.addValue("employeeName", emp.getEmployeeName())
.addValue("employeeEmail", emp.getEmployeeEmail())
.addValue("employeeAddress", emp.getEmployeeAddress());
        template.update(sql,param, holder);

}

@Override
public void executeUpdateEmployee(Employee emp) {
 final String sql = "update employee set employeeName=:employeeName, employeeAddress=:employeeAddress, employeeEmail=:employeeEmail where employeeId=:employeeId";


 Map<String,Object> map=new HashMap<String,Object>();  
 map.put("employeeId", emp.getEmployeeId());
 map.put("employeeName", emp.getEmployeeName());
 map.put("employeeEmail", emp.getEmployeeEmail());
 map.put("employeeAddress", emp.getEmployeeAddress());

 template.execute(sql,map,new PreparedStatementCallback<Object>() {  
    @Override  
    public Object doInPreparedStatement(PreparedStatement ps)  
            throws SQLException, DataAccessException {  
        return ps.executeUpdate();  
    }  
});  


}

@Override
public void deleteEmployee(Employee emp) {
 final String sql = "delete from employee where employeeId=:employeeId";


 Map<String,Object> map=new HashMap<String,Object>();  
 map.put("employeeId", emp.getEmployeeId());

 template.execute(sql,map,new PreparedStatementCallback<Object>() {  
    @Override  
    public Object doInPreparedStatement(PreparedStatement ps)  
            throws SQLException, DataAccessException {  
        return ps.executeUpdate();  
    }  
});  


}

}
  • findAll () извлекает всех сотрудников, а затем сопоставляет набор результатов с объектом Employee, используя RowMapper, описанный ниже.

  • insertEmployee () вставит сотрудника, используя, template.update(sql,param, holder) где param — SqlParameterSource, который будет динамически отображать значения в запросе, отмеченном двоеточием. GeneratedKeyHolder вернет автоматически сгенерированное значение при вставке данных.

  • executeUpdateEmployee () обновит сотрудника, используя template.execute

 template.execute(sql,map,new PreparedStatementCallback<Object>() {  
    @Override  
    public Object doInPreparedStatement(PreparedStatement ps)  
            throws SQLException, DataAccessException {  
        return ps.executeUpdate();  
    }  
}); 
  • EmployeeRowMapper для сопоставления результирующего набора, полученного из запроса выбора, с POJO.
package com.sample.postgress.mapper;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

import com.sample.postgress.entity.Employee;

public class EmployeeRowMapper implements RowMapper<Employee> {

@Override
public Employee mapRow(ResultSet rs, int arg1) throws SQLException {
Employee emp = new Employee();
emp.setEmployeeId(rs.getString("employeeId"));
emp.setEmployeeName(rs.getString("employeeName"));
emp.setEmployeeEmail(rs.getString("employeeEmail"));

        return emp;
}


}
  • Вы можете создать контроллер и класс обслуживания следующим образом:
package com.sample.postgress.service;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.sample.postgress.dao.EmployeeDao;
import com.sample.postgress.entity.Employee;
@Component
public class EmployeeServiceImpl implements EmployeeService{
@Resource 
EmployeeDao employeeDao;
@Override
public List<Employee> findAll() {
return employeeDao.findAll();
}
@Override
public void insertEmployee(Employee emp) {
employeeDao.insertEmployee(emp);

}
@Override
public void updateEmployee(Employee emp) {
employeeDao.updateEmployee(emp);

}
@Override
public void executeUpdateEmployee(Employee emp) {
employeeDao.executeUpdateEmployee(emp);

}

@Override
public void deleteEmployee(Employee emp) {
employeeDao.deleteEmployee(emp);

}
}
package com.sample.postgress.controller;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.sample.postgress.entity.Employee;
import com.sample.postgress.service.EmployeeService;

@RestController
@RequestMapping("/postgressApp")
public class ApplicationController {

@Resource 
EmployeeService employeeService;

@GetMapping(value = "/employeeList")
public List<Employee> getEmployees() {
return employeeService.findAll();

}

@PostMapping(value = "/createEmp")
public void createEmployee(@RequestBody Employee emp) {
 employeeService.insertEmployee(emp);

}
@PutMapping(value = "/updateEmp")
public void updateEmployee(@RequestBody Employee emp) {
 employeeService.updateEmployee(emp);

}
@PutMapping(value = "/executeUpdateEmp")
public void executeUpdateEmployee(@RequestBody Employee emp) {
 employeeService.executeUpdateEmployee(emp);

}

@DeleteMapping(value = "/deleteEmpById")
public void deleteEmployee(@RequestBody Employee emp) {
 employeeService.deleteEmployee(emp);

}


}

Теперь давайте используем POSTMAN для проверки изменений:

Тест 1: Получить список сотрудников

HTTP: // локальный: 8080 / PostgresApp / employeeList

Тест 2: Создать сотрудника

HTTP: // локальный: 8080 / PostgresApp / createEmp

Мы видим запись, вставленную с Джонсом.

Тест 3: Обновление сотрудника

HTTP: // локальный: 8080 / PostgresApp / executeUpdateEmp

Тест 4: Удалить сотрудника

HTTP: // локальный: 8080 / PostgresApp / deleteEmpById

Заключение

Мы узнали, как настроить Spring Boot с Postgres и использовать NamedParameterJdbcTemplate для выполнения операции CRUD. Вы найдете полный код здесь.

Удачного кодирования!