74、SpringBoot 整合 Spring Data JDBC

总结:用起来跟 Spring Data JPA 差不多

★ Spring Data JDBC

既不需要JPA、Hibernate这种ORM框架,但Spring Data还是提供了面向对象的封装。

——它相当于是一种轻量化的持久化技术,用起来比Spring JDBC更方便,
   但又不像Spring Data JPA那么需要大量注解、复杂

它相当于是一个折中。

★ Spring Data JDBC的功能

大致包括如下几方面功能:
- DAO接口只需继承CrudRepository或PagingAndSortingRepository,
  Spring Data JDBC能为DAO组件生成实现类、类似于Spring Data JPA。
- Spring Data JDBC支持方法名关键字查询、类似于Spring Data JPA
- Spring Data JDBC支持用@Query定义查询语句。
- Spring Data JDBC同样支持DAO组件添加自定义的查询方法
                  ——————通过添加额外的父接口,并为额外的该接口提供实现类,
                        Spring Data JDBC就能该实现类中的方法“移植”到DAO组件中。
- 一般不支持样本查询;也不支持Specification查询。

★ Spring Data JDBC VS Spring Data JPA

Spring Data JDBC相当于“轻量化”的Spring Data JPA。
Spring Data JDBC的功能不如Spring Data JPA强大(毕竟它底层没有ORM框架的加持)。
Spring Data JDBC也不需要处理复杂的ORM映射、实体对象的生命周期管理等,
因此Spring Data JDBC用起来更简单。 
——Spring Data JDBC有点类似MyBatis

★ Spring Data JDBC映射规则

Spring Data JDBC默认的处理方式是“约定优于配置”的同名映射:

- 程序操作User对象,Spring Data JDBC对应于操作user表。
- 对于id数据列,自动被映射到对象的id属性。

▲Spring Data JDBC的注解:

- @Table:映射自定义的表名。非JPA注解
- @Column:映射自定义的列名,非JPA注解
- @Id:修饰标识属性,非JPA注解
- @PersistenceConstructor:修饰主构造器。当你的映射类中有多个构造器时,
                           你希望Spring Data JDBC用哪个构造器来创建对象,
                           就用该注解来修饰该构造器。

★ Spring Data JDBC操作数据库方法:

A. 全自动:方法名关键字查询。

B. 半自动:@Query指定查询语句。

C. 全手动:自己定义查询方法,即可用DataSource,也用JdbcTemplate。

★ Spring Data JDBC的编程步骤:

(1)定义映射类,为Java类添加@Table、@Column、@Id和 @PersistenceConstructor

(2)让DAO接口继承CrudRepository或PagingAndSortingRepository。

(3)在DAO接口中定义方法名关键字查询、@Query查询、完全自定义查询(需要额外的接口和实现类)

代码演示

其实跟 JPA 差不多

User 类

74、SpringBoot 整合 Spring Data JDBC_第1张图片

UserDao接口,

根据方法名关键字查询---------全自动,不用自己写sql的
也有通过注解 @Query 进行查询的 —>自己定义查询语句-----半自动,可以自己写sql语句
74、SpringBoot 整合 Spring Data JDBC_第2张图片

也可以自定义Dao接口,用来自己写sql和封装数据
74、SpringBoot 整合 Spring Data JDBC_第3张图片

自定义接口和实现类,来实现数据的查询,
一个基于 DataSource , 一个基于 jdbcTemplate
74、SpringBoot 整合 Spring Data JDBC_第4张图片
74、SpringBoot 整合 Spring Data JDBC_第5张图片

74、SpringBoot 整合 Spring Data JDBC_第6张图片

UserDaoTest 测试

测试类
74、SpringBoot 整合 Spring Data JDBC_第7张图片
74、SpringBoot 整合 Spring Data JDBC_第8张图片
74、SpringBoot 整合 Spring Data JDBC_第9张图片
74、SpringBoot 整合 Spring Data JDBC_第10张图片
74、SpringBoot 整合 Spring Data JDBC_第11张图片
74、SpringBoot 整合 Spring Data JDBC_第12张图片

application.properties

74、SpringBoot 整合 Spring Data JDBC_第13张图片

pom.xml

一个是 spring data jdbc 的依赖 , 一个是 mysql 的依赖,
创建项目的时候这个 mysql 的依赖老是不完整,所以要记录下
74、SpringBoot 整合 Spring Data JDBC_第14张图片

完整代码

User

package cn.ljh.app.domain;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;

/**
 * author JH
 */


@Data
//此处不能添加JPA注解,因为此项目没有用到 JPA
@Table("user_inf")
public class User
{

    @Column(value = "user_id")
    @Id
    private Integer id;
    private String name;
    private String password;
    private int age;

    /**
     * @PersistenceConstructor
     *  修饰主构造器。当你的映射类中有多个构造器时,
     *  你希望Spring Data JDBC用哪个构造器来创建对象,就用该注解来修饰该构造器
     */
    @PersistenceConstructor
    public User()
    {
    }

    public User(Integer id, String name, String password, int age)
    {
        this.id = id;
        this.name = name;
        this.password = password;
        this.age = age;
    }

    @Override
    public String toString()
    {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

UserDao

package cn.ljh.app.dao;


import cn.ljh.app.domain.User;
import org.springframework.data.jdbc.repository.query.Modifying;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;

import java.util.List;


public interface UserDao extends CrudRepository<User,Integer>,CustomUserDao
{
    // 继承 CrudRepository 接口后,就已经有通用的 CRUD 操作,无需自己来书写这些方法
    //方法名关键字查询---------全自动

    //根据名字模糊查询
    List<User> findByNameLike(String namePattern);
    //根据年龄大小进行范围查询
    List<User> findByAgeGreaterThan(int startAge);

    List<User> findByAgeLessThan(int age);

    //根据年龄区间进行范围查询
    List<User> findByAgeBetween(int startAge , int endAge);

    //@Query 查询 --->自己定义查询语句-----半自动
    //rowMapperClass 或 rowMapperRef 是用来做自定义映射,查询出来的User对象的数据,映射到Student对象的属性上面去都可以,因为是自定义的。

    //根据密码模糊查询
    @Query("select * from user_inf where password like :passwordPattern")
    List<User> findBySql(String passwordPattern);

    //根据年龄范围修改名字
    @Query("update user_inf set name = :name where age between :startAge and :endAge")
    @Modifying //更改数据库数据需要用到这个注解
    int updateNameByAge(String name , int startAge , int endAge);

}

CustomUserDao

package cn.ljh.app.dao;

import cn.ljh.app.domain.User;

import java.util.List;

/**
 * author JH
 */
//自己定义的接口,用来实现全手动的查询
public interface CustomUserDao
{
    //通过名字进行模糊查询,使用 dataSource
    List<User> customQueryUsingConnection(String namePattern);

    //通过名字进行模糊查询,使用 jdbcTemplate
    List<User> customQueryUsingTemplate(String namePattern);
}

CustomUserDaoImpl

package cn.ljh.app.dao.impl;

import cn.ljh.app.dao.CustomUserDao;
import cn.ljh.app.domain.User;
import lombok.SneakyThrows;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.sql.Array;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * author JH
 */
public class CustomUserDaoImpl implements CustomUserDao
{
    private DataSource dataSource;
    private JdbcTemplate jdbcTemplate;

    //通过有参构造器进行依赖注入
    public CustomUserDaoImpl(DataSource dataSource, JdbcTemplate jdbcTemplate)
    {
        this.dataSource = dataSource;
        this.jdbcTemplate = jdbcTemplate;
    }

    @SneakyThrows
    @Override
    public List<User> customQueryUsingConnection(String namePattern)
    {
        //创建数据库连接
        Connection connection = this.dataSource.getConnection();
        //创建 PreparedStatement 预处理语句
        PreparedStatement pstmt = connection.prepareStatement("select * from user_inf where name like ?");
        pstmt.setString(1, namePattern);
        //执行查询
        ResultSet rs = pstmt.executeQuery();
        List<User> userList = new ArrayList<>();
        //遍历结果集,封装对象
        while (rs.next())
        {
            userList.add(new User(
                    rs.getInt("user_id"),
                    rs.getString("name"),
                    rs.getString("password"),
                    rs.getInt("age")
            ));
        }
        return userList;
    }

    @Override
    public List<User> customQueryUsingTemplate(String namePattern)
    {
        //直接执行查询
        List<User> userList = this.jdbcTemplate.query(
                "select user_id as id,name ,password,age from user_inf where name like ?",
                //把查询的结果封装起来
                new BeanPropertyRowMapper<>(User.class),
                namePattern
        );
        return userList;
    }
}

UserDaoTest

package cn.ljh.app;

import cn.ljh.app.dao.UserDao;
import cn.ljh.app.domain.User;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.jdbc.repository.query.Modifying;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * author JH
 */
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class UserDaoTest
{
    @Autowired
    private UserDao userDao;

    // 继承 CrudRepository 接口后,就已经有通用的 CRUD 操作,无需自己来书写这些方法==============
    //添加user对象
    @ParameterizedTest
    @CsvSource({"aa,xxx,2", "bb,xxx,3"})
    public void testSave(String name, String password, int age)
    {
        //没有id,save就是添加
        User user = userDao.save(new User(null, name, password, age));
        System.err.println(user);
    }

    //根据id修改对象
    @ParameterizedTest
    @CsvSource({"13,aaa,xxxx,22"})
    public void testUpdate(Integer id, String name, String password, int age)
    {
        //有id,save就是修改
        User user = userDao.save(new User(id, name, password, age));
        System.err.println(user);
    }

    //根据id删除用户对象
    @ParameterizedTest
    @ValueSource(ints = {14})
    public void testDelete(Integer id)
    {
        userDao.deleteById(id);
    }

    //根据id查询对象
    @ParameterizedTest
    @ValueSource(ints = {1})
    public void testFindById(Integer id)
    {
        Optional<User> user = userDao.findById(id);
    }


    //方法名关键字查询---------全自动=====================================================
    //根据名字模糊查询
    @ParameterizedTest
    @ValueSource(strings = {"孙%", "%精"})
    public void testFindByNameLike(String namePattern)
    {
        List<User> users = userDao.findByNameLike(namePattern);
        users.forEach(System.err::println);
    }

    //根据年龄大小进行范围查询
    @ParameterizedTest
    @ValueSource(ints = {500, 10})
    public void testFindByAgeGreaterThan(int startAge)
    {
        List<User> users = userDao.findByAgeGreaterThan(startAge);
        users.forEach(System.err::println);
    }

    //根据年龄大小进行范围查询
    @ParameterizedTest
    @ValueSource(ints = {20})
    public void testFindByAgeLessThan(int age)
    {
        List<User> users = userDao.findByAgeLessThan(age);
        users.forEach(System.err::println);
    }

    //根据年龄区间进行范围查询
    @ParameterizedTest
    @CsvSource({"15,20", "500,1000"})
    public void testFindByAgeBetween(int startAge, int endAge)
    {
        List<User> users = userDao.findByAgeBetween(startAge, endAge);
        users.forEach(System.err::println);
    }


    //@Query 查询 --->自己定义查询语句-----半自动=====================================================================
    //rowMapperClass 或 rowMapperRef 是用来做自定义映射,查询出来的User对象的数据,映射到Student对象的属性上面去都可以,因为是自定义的。

    //根据密码模糊查询
    @ParameterizedTest
    @ValueSource(strings = {"niu%", "%3"})
    public void testFindBySql(String passwordPattern)
    {
        List<User> users = userDao.findBySql(passwordPattern);
        users.forEach(System.err::println);
    }

    //根据年龄范围修改名字
    @ParameterizedTest
    @CsvSource({"牛魔王aa,800,1000"})
    @Transactional
    @Rollback(false)
    public void testUpdateNameByAge(String name, int startAge, int endAge)
    {
        int i = userDao.updateNameByAge(name, startAge, endAge);
    }

    //自己定义的接口,用来实现全手动的查询===================================================================================

    //通过名字进行模糊查询,使用 dataSource
    @ParameterizedTest
    @ValueSource(strings = {"孙%"})
    public void testCustomQueryUsingConnection(String namePattern)
    {
        List<User> users = userDao.customQueryUsingConnection(namePattern);
        users.forEach(System.err::println);
    }

    //通过名字进行模糊查询,使用 jdbcTemplate
    @ParameterizedTest
    @ValueSource(strings = {"孙%"})
    public void testCustomQueryUsingTemplate(String namePattern)
    {
        List<User> users = userDao.customQueryUsingTemplate(namePattern);
        users.forEach(System.err::println);
    }
}

application.properties

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

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 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.4.5</version>
    </parent>
    <groupId>cn.ljh</groupId>
    <artifactId>Spring_Data_JDBC</artifactId>
    <version>1.0.0</version>
    <name>Spring_Data_JDBC</name>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <!-- 导入 spring data jdbc -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </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>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

你可能感兴趣的:(springboot,spring,boot,spring,java,Spring,Data,JPA)