前言

在现代应用程序开发中,数据访问是至关重要的一环。如何有效地与数据库进行交互直接影响到应用程序的性能和维护性。Spring 框架提供了多种工具来简化和优化数据访问,其中包括 JDBCTemplate、Spring Data JDBC 和 Spring Data JPA。本篇博客将详细介绍这三种工具的区别和适用场景,帮助开发者选择合适的解决方案。

我们用一个栗子来说明这三者的区别:从数据库中通过id查询用户名,这里使用mysql数据库演示,

下面给出了sql代码

1
2
3
4
5
6
7
8
9
10
11
12
create table if not exists user (
id int primary key,
name varchar(255) not null,
email varchar(255) not null,
password varchar(255) not null
);

insert into user (id,name, email, password)values (1,'admin1', 'abd@gmail.com', 'abc');
insert into user (id,name, email, password)values (2,'admin2', 'abAasdfd@gmail.com', 'admin');
insert into user (id,name, email, password)values (3,'admin3', 'a123bd@gmail.com', 'admi123n');
insert into user (id,name, email, password)values (5,'admin4', 'abd6245@gmail.com', 'ad1m1in');
insert into user (id,name, email, password)values (8,'admin78', 'a1345bd@gmail.com', 'ad24min');

User类,其中使用了lombok库的@Data标签,可以自动生成set,get以及构造方法。

1
2
3
4
5
6
7
8
9
import lombok.Data;

@Data
public class User {
private int id;
private String name;
private String email;
private String password;
}

JDBCTemplate

JDBCTemplate 是 Spring 框架提供的一个简化 JDBC 操作的工具类。它封装了复杂的 JDBC 操作,简化了数据库访问。

功能和特点

  • 简化了 JDBC 连接、语句创建、执行和结果集处理
  • 需要手动编写 SQL 查询语句
  • 更细粒度的控制,适用于需要精确控制 SQL 语句和数据库交互的场景
  • 无 ORM 功能,需要手动将结果集转换为对象

使用场景和示例代码(Repo层)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import org.jdbctemplatedemo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserRepoByTP {
private JdbcTemplate jdbcTemplate;

@Autowired
public UserRepoByTP(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}

public User findById(int id){
return jdbcTemplate.queryForObject("select * from user where id = ?",
new Object[]{id}, (rs, rowNum) -> {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setEmail(rs.getString("email"));
user.setPassword(rs.getString("password"));
return user;
}
);
}
}

配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import org.springframework.beans.factory.annotation.Autowired;
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 DataSourceConfig {

@Autowired
private DataSource dataSource;

@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource);
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.jdbctemplatedemo.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
public class UserRepoByTPTests {
@Autowired
private UserRepoByTP userRepoByTP;
@Test
public void testFindById() {

User user = userRepoByTP.findById(1);
assertNotNull(user);
assertEquals("admin1", user.getName());
}
}

Spring Data JDBC

Spring Data JDBC 是 Spring Data 的一部分,旨在简化基于 JDBC 的数据库访问,提供了比 JDBCTemplate 更高层次的抽象。

功能和特点

  • 通过 Repository 接口进行数据操作
  • 自动处理数据库表和实体类之间的映射
  • 较轻量级,没有 JPA 的复杂性和开销
  • 适合性能要求高但不需要复杂功能的场景

使用场景和示例代码(Repo层)

1
2
3
4
5
6
import org.jdbctemplatedemo.entity.User;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository
extends CrudRepository<User, Integer> {
}

与 JDBCTemplate 需要手动编写 SQL 不同,Spring Data JDBC 能自动生成数据访问层的实现类。

修改领域类

1
2
3
4
5
6
7
8
9
10
11
12
13
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;

@Data
@Table
public class User {
@Id
private int id;
private String name;
private String email;
private String password;
}

使用@Id标签标记唯一标识,使用@Table 注解用于指定实体类与数据库表的映射关系。它通常用于在实体类上标记,指定实体类所对应的数据库表的名称和其他属性。

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.jdbctemplatedemo.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;


@SpringBootTest
public class UserRepositoryJDBCTests {
@Autowired
private UserRepository userRepository;

@Test
public void testFindById() {
Optional<User> user = userRepository.findById(1);
assertNotNull(user);
assertEquals("admin1", user.get().getName());
}

}

Spring Data JPA

Spring Data JPA 基于 JPA 规范,提供了强大的 ORM 功能,是 Spring Data 的重要组成部分。

功能和特点

  • 完全支持 JPA 规范,提供了丰富的 ORM 功能
  • 通过 Repository 接口进行 CRUD 操作
  • 支持 JPQL、方法名解析查询等复杂查询机制
  • 提供缓存、懒加载、事务管理等高级功能
  • 适用于需要复杂关系映射和高级功能的应用

使用场景和示例代码(Repo层)

1
2
3
4
5
6
import org.jdbctemplatedemo.entity.User;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository
extends CrudRepository<User, Integer> {
}

与JDBC的Repo写法一致

修改领域类

1
2
3
4
5
6
7
8
9
10
11
12
13
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.Data;

@Data
@Entity
public class User {
@Id
private int id;
private String name;
private String email;
private String password;
}

这里使用的是@Entity标签,该注解是 JPA(Java Persistence API)中的一种注解,用于标识一个类是一个 JPA 实体类。实体类是映射到数据库表的对象,它的每个实例对应数据库表中的一行数据。使用 @Entity 注解将一个普通的 Java 类标记为 JPA 实体类,使得 JPA 提供的持久化操作能够管理该类的实例。

这里的@Id是jakarta.persistence库中的和Spring Data JDBC中不同,需要注意

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
public class UserRepoByJPA {

@Autowired
private UserRepository userRepository;

@Test
public void testFindById() {
Optional<User> user = userRepository.findById(1);
assertNotNull(user);
assertEquals("admin1", user.get().getName());
}
}

比较与选择

  • JDBCTemplate: 适用于需要精细控制 SQL 语句和数据库交互的场景,如简单查询和更新操作。
  • Spring Data JDBC: 适用于需要高性能但不需要复杂 ORM 功能的场景,提供了简单易用的 Repository 接口。
  • Spring Data JPA: 适用于需要复杂关系映射和高级功能的应用,如需要缓存、懒加载和复杂查询的场景。
特性 JDBCTemplate Spring Data JDBC Spring Data JPA
SQL 控制 需要手动编写 需要少量 SQL 不需要手动编写
ORM 支持 有,但较简单 完整支持
缓存与懒加载
性能 较高 相对较低,但提供更多功能
适用场景 精细控制、简单查询 轻量级、高性能需求 复杂关系映射、需要高级功能