Hable sobre cómo usar JdbcTemplate para leer y escribir datos en Spring Boot

Primero introduzca las dependencias en pom.xml.

<!--jdbc-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!--h2-->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

El programa de muestra intenta utilizar la base de datos de caché h2, por lo que también se cita aquí.

1 base de datos de caché h2

h2 es un motor de base de datos de código abierto integrado (dispositivo no integrado), desarrollado en base a Java, que puede integrarse directamente en la aplicación, empaquetarse y publicarse junto con la aplicación y no está restringido por la plataforma.

Después de iniciar la aplicación, ingrese http://127.0.0.1:8080/h2-console en la barra de direcciones del navegador para abrir la consola h2.

Primero seleccione el formato de codificación de la consola como chino, luego ingrese la URL JDBC y luego haga clic en "Probar conexión". Si la conexión es exitosa, aparecerá "Prueba exitosa".

Finalmente, haga clic en el botón "Conectar" para abrir el cliente de la consola de la base de datos y conectarse a la base de datos h2:

2 Inicializar la estructura y los datos de la tabla

En src / main / resources /, cree un nuevo archivo schema.sql para escribir la estructura de la tabla SQL. En el mismo directorio, cree un nuevo archivo data.sql y escriba SQL de datos iniciales. Entonces, cuando se inicia la aplicación, Spring Boot ejecutará estos scripts.

schema.sql:

create table if not exists Book
( id varchar( 4) not null, name varchar( 25) not null, type varchar( 10) not null );

data.sql:

insert into Book
  (id, name, type)
values
  ('1', '两京十五日', '小说');
insert into Book
  (id, name, type)
values
  ('2', '把自己作为方法', '历史');
insert into Book
  (id, name, type)
values
  ('3', '正常人', '小说');

Después de un inicio exitoso, verá las tablas y los datos recién creados en el cliente de la consola de la base de datos h2.

Haga clic en Reservar a la izquierda, la declaración SQL para consultar la tabla se generará automáticamente en el cuadro de entrada SQL a la derecha, y luego haga clic en "Ejecutar" para ejecutarlo. Veremos los datos de la tabla inicializados en la esquina inferior derecha.

3 codificación

3.1 Nueva clase de entidad

@Data
@RequiredArgsConstructor
public class Book {

    private final String id;
    private final String name;
    private final String type;
}

Aquí se utiliza el complemento de Lombok. Lombok es una utilidad de Java que puede utilizarse para ayudarnos a eliminar el código repetitivo detallado de Java.

Las clases de Java anotadas con @Data agregarán automáticamente estos métodos después de la compilación:

  1. Obtener y establecer métodos para todos los atributos;
  2. método toString;
  3. método hashCode;
  4. es igual al método.

La anotación @RequiredArgsConstructor tomará todos los campos no inicializados anotados con @NonNull y final en la clase como parámetros de entrada del constructor.

3.2 Nueva clase de repositorio

Primero defina una interfaz de repositorio, luego cree una nueva clase de implementación para esta interfaz.

interfaz:

public interface BookRepository {

    Iterable<Book> findAll();

    Book findOne(String id);

    Book save(Book Book);
}

Clase de implementación:

@Repository
public class JdbcBookRepository implements BookRepository {

    private JdbcTemplate jdbc;

    @Autowired
    public JdbcBookRepository(JdbcTemplate jdbc) {
        this.jdbc = jdbc;
    }

    @Override
    public Iterable<Book> findAll() {
        return null;
    }

    @Override
    public Book findOne(String id) {
        return null;
    }

    @Override
    public Book save(Book Book) {
        return null;
    }
}

@Repository es similar a @Controller, @Service y @Component. El propósito es entregar objetos a Spring para su administración. @Repository se usa generalmente en la clase de implementación de la capa de persistencia.

La anotación @Autowired puede inyectar los recursos externos necesarios en campos o métodos especificados en forma de byType.

Autowire tiene los siguientes cuatro modos:

modo Descripción
por nombre Montaje automático basado en el nombre del atributo
por tipo Montaje automático según el tipo de atributo
constructor Similar a byType, la diferencia es que se aplica al parámetro del constructor, y se lanzará una excepción si no se encuentra
detección automática Elegirá inteligentemente entre byType y constructor

JdbcTemplate se inyecta aquí a través del constructor anotado por @Autowired. Este constructor asigna JdbcTemplate a una variable de instancia, que será utilizada por otros métodos para realizar consultas de base de datos o operaciones de actualización.

3.3 Operación de consulta

Supongamos que necesitamos consultar todos los libros, luego puede llamar al List<T> query(String sql, RowMapper<T> rowMapper)método JdbcTemplate .

@Override
public Iterable<Book> findAll() {
    return jdbc.query("select id, name, type from Book",
            this::mapRowToBook);
}

private Book mapRowToBook(ResultSet rs, int rowNum) throws SQLException {
    return new Book(rs.getString("id"), rs.getString("name"),
            rs.getString("type"));
}

Aquí usamos referencias a métodos Java para escribir parámetros de entrada de RowMapper. La ventaja de esto es: en comparación con la clase interna anónima original, la referencia del método es más concisa.

3.4 actualizar ()

El método update () de JdbcTemplate se puede utilizar para agregar o actualizar datos.

@Override
public Book save(Book book) {
    jdbc.update("insert into Book (id,name,type) values (?,?,?)",
            book.getId(),
            book.getName(),
            book.getType()
    );
    return book;
}

El método update () se define de la siguiente manera:

int update(String sql, @Nullable Object... args)

Acepta una declaración SQL que contiene marcadores de posición y múltiples parámetros de entrada. Devuelve el número de registros realmente afectados.

Cree una clase de prueba unitaria de Spring para verificar el método save () recién creado:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class JdbcBookRepositoryTest {

    @Autowired
    private JdbcBookRepository jdbcBookRepository;

    @Test
    public void save() {

        Book book = new Book("4", "比利时的哀愁", "小说");
        jdbcBookRepository.save(book);
        Book find=jdbcBookRepository.findOne("4");
        assertEquals("比利时的哀愁",find.getName());
    }
}

3.5 Clase contenedora SimpleJdbcInsert

SimpleJdbcInsert se usa generalmente en escenarios de inserción de múltiples tablas. SimpleJdbcInsert tiene dos métodos para realizar operaciones de inserción de datos: execute () y executeAndReturnKey (). Se aceptan Map<String ,Object>como parámetros, donde la clave correspondiente al nombre de la columna en la tabla de datos, el valor correspondiente a los valores reales que se insertarán en la columna.

Tomemos un ejemplo de libro. Un libro puede contener varias etiquetas y una etiqueta también puede pertenecer a varios libros. Existe una relación de muchos a muchos entre ellos, por lo que se establece una tabla de mapeo entre libros y etiquetas para almacenar estas relaciones específicamente. Los detalles se muestran en la siguiente figura:

Primero, agregue estas declaraciones de creación de estructura de tabla en schema.sql:

create table if not exists Book
( id identity, name varchar( 25) not null, type varchar( 10) not null );


create table if not exists Tag
( id identity, name varchar( 25) not null);


create table if not exists Book_Tags ( book bigint not null, tag bigint not null );

alter table Book_Tags add foreign key (book) references Book( id);
alter table Book_Tags add foreign key (tag) references Tag( id);

A continuación, cree estas clases de entidad:

@Data
@RequiredArgsConstructor
public class Tag {

    private final Long id;
    private final String name;
}

@Data
@RequiredArgsConstructor
public class Book {

    private final String id;
    private final String name;
    private final String type;

    private List<Tag> tags = new ArrayList<>();
}

Luego, en el constructor de la clase de implementación Repository, inicialice la instancia SimpleJdbcInsert de cada tabla:

@Repository
public class JdbcBookRepository implements BookRepository {

    private static final Logger log = LogManager.getFormatterLogger();

    private final SimpleJdbcInsert bookInserter;
    private final SimpleJdbcInsert tagInserter;
    private final SimpleJdbcInsert bookTagsInserter;
    private final ObjectMapper objectMapper;
    private JdbcTemplate jdbc;

    @Autowired
    public JdbcBookRepository(JdbcTemplate jdbc) {
        this.jdbc = jdbc;
        this.bookInserter = new SimpleJdbcInsert(jdbc)
                .withTableName("Book")
                .usingGeneratedKeyColumns("id");

        this.tagInserter = new SimpleJdbcInsert(jdbc)
                .withTableName("Tag")
                .usingGeneratedKeyColumns("id");

        this.bookTagsInserter = new SimpleJdbcInsert(jdbc)
                .withTableName("Book_Tags");

        this.objectMapper = new ObjectMapper();
    }
    ...
}

El método withTableName () de SimpleJdbcInsert se usa para especificar el nombre de la tabla; y el método usingGeneratedKeyColumns () se usa para especificar la clave primaria.

El código de operación de guardado específico es:

public Book saveIncludeTags(Book book) {
    //保存图书
    Map<String, Object> values = objectMapper.convertValue(book, Map.class);
    long bookId = bookInserter.executeAndReturnKey(values).longValue();

    //保存标签
    List<Long> tagIds = new ArrayList<>();
    for (Tag tag : book.getTags()) {
        values = objectMapper.convertValue(tag, Map.class);
        long tagId = tagInserter.executeAndReturnKey(values).longValue();
        tagIds.add(tagId);
    }

    //关联图书与标签
    for (Long tagId : tagIds) {
        values.clear();
        values.put("book", bookId);
        values.put("tag", tagId);
        log.info("values -> %s", values);
        bookTagsInserter.execute(values);
    }

    return book;
}
  • El método executeAndReturnKey () y execute () SimpleJdbcInsert admite Map<String, ?>la forma de la referencia. La diferencia entre ellos es que executeAndReturnKey () devolverá el valor de la clave principal en forma de Número.
  • Jackson se puede utilizar en ObjectMapper.convertValue(Object fromValue, Class<T> toValueType)un método para convertir un valor correspondiente a un objeto Mapa POJO.
  • El tipo de número se puede convertir según la escena.

Este código primero guarda el libro y obtiene la clave principal del libro; luego guarda la etiqueta para obtener la clave principal de la etiqueta; finalmente, guarda la clave principal del libro y la clave principal de la etiqueta obtenida anteriormente en la tabla de relaciones entre ellos.

Supongo que te gusta

Origin blog.csdn.net/deniro_li/article/details/108807674
Recomendado
Clasificación