本指南将带你构建一个应用程序,使用 Spring Data JPA 在关系型数据库中存储和读取数据。
你将构建什么
你将构建一个把 Customer 对象存储在内存数据库中的应用程序。
你需要什么
- 约 15 分钟。
- 你喜欢的文本编辑器或 IDE。
- Java 17 或更高版本。
- Gradle 7.5+ 或 Maven 3.5+。
- 也可将代码直接导入 IDE:Spring Tool Suite(STS)、IntelliJ IDEA 或 VSCode。
如何完成本指南
与大多数 Spring 入门指南一样,你可以从零开始,逐步完成,也可以跳过已经熟悉的基本配置步骤。两种方式最终都会得到可工作的代码。
要从零开始,请继续阅读“使用 Spring Initializr 开始”。要跳过基础步骤,请:
- 下载并解压本指南的源码仓库,或者用 Git 克隆:
git clone https://github.com/spring-guides/gs-accessing-data-jpa.git
- 切换到
gs-accessing-data-jpa/initial目录。 - 直接阅读“定义一个简单实体”。
完成之后,可以将结果与 gs-accessing-data-jpa/complete 中的代码进行比较。
使用 Spring Initializr 开始
可以打开这个预先初始化的项目,点击 Generate 下载 ZIP 文件。它已按本教程示例所需的配置设置好。
要手动初始化项目:
- 访问 https://start.spring.io。这个服务会引入应用程序所需的全部依赖,并代你完成大部分配置。
- 选择 Gradle 或 Maven,以及希望使用的语言。
- 在 Artifact 字段中输入
accessing-data-jpa。 - 点击 Dependencies,选择 Spring Data JPA,然后选择 H2 Database。
- 点击 Generate。
- 下载生成的 ZIP 文件,其中是按照你的选择配置好的应用程序归档。
定义一个简单实体
在这个示例中,你会存储 Customer 对象,每个对象对应的类都被标注为 JPA 实体。下面是 Customer 类:
Java
package com.example.accessingdatajpa;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
protected Customer() {}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return String.format(
"Customer[id=%d, firstName='%s', lastName='%s']",
id, firstName, lastName);
}
public Long getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
Kotlin
package com.example.accessingdatajpa
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
@Entity
class Customer(
var firstName: String = "",
var lastName: String = ""
) {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
var id: Long? = null
override fun toString(): String =
"Customer[id=$id, firstName='$firstName', lastName='$lastName']"
}
Customer 类有三个属性:id、firstName 和 lastName。Java 版本还提供两个构造方法。默认构造方法仅供 JPA 使用;你不会直接使用它,所以它被设为 protected。另一个构造方法供你创建要保存到数据库中的 Customer 实例。
Customer 类上的 @Entity 注解表明它是一个 JPA 实体。由于没有 @Table 注解,假定这个实体映射到名为 Customer 的表。
Customer 对象的 id 属性带有 @Id 注解,让 JPA 将它识别为对象的 ID。该属性还带有 @GeneratedValue,表示 ID 应自动生成。
另外两个属性 firstName 和 lastName 没有注解,假定它们映射到与属性同名的列。
便捷的 toString() 方法会输出客户对象的属性。
创建简单查询
Spring Data JPA 专注于使用 JPA 在关系型数据库中存储数据。它最有吸引力的特性,是能够在运行时根据 repository 接口自动创建实现。
要了解它的工作方式,可以创建一个处理 Customer 实体的 repository 接口:
Java
package com.example.accessingdatajpa;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
Customer findById(long id);
}
Kotlin
package com.example.accessingdatajpa
import org.springframework.data.repository.CrudRepository
interface CustomerRepository : CrudRepository<Customer, Long> {
fun findByLastName(lastName: String): List<Customer>
}
CustomerRepository 扩展 CrudRepository 接口。在 CrudRepository 的泛型参数中,指定了实体类型 Customer 和 ID 类型 Long。通过扩展它,CustomerRepository 继承了多种持久化方法,包括保存、删除与查找 Customer 实体的方法。
Spring Data JPA 还允许你通过声明方法签名来定义其他查询。例如,CustomerRepository 中包含 findByLastName() 方法。
在典型的 Java 应用程序中,你可能需要编写一个实现 CustomerRepository 的类。但这正是 Spring Data JPA 的强大之处:无需编写 repository 接口的实现,Spring Data JPA 会在应用程序运行时创建它。
现在,可以把这个示例组装起来,看看它的运行效果。
创建应用程序类
Spring Initializr 会为应用程序创建一个简单的类。下面是它为此示例创建的类:
Java
package com.example.accessingdatajpa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AccessingDataJpaApplication {
public static void main(String[] args) {
SpringApplication.run(AccessingDataJpaApplication.class, args);
}
}
Kotlin
package com.example.accessingdatajpa
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class AccessingDataJpaApplication
fun main(args: Array<String>) {
runApplication<AccessingDataJpaApplication>(*args)
}
@SpringBootApplication 是一个便捷注解,它包含以下功能:
@Configuration:把这个类标记为应用程序上下文的 bean 定义来源。@EnableAutoConfiguration:告诉 Spring Boot 根据类路径设置、其他 bean 和各种属性设置添加 bean。例如,当类路径中存在spring-webmvc时,这个注解会将应用程序识别为 Web 应用程序,并启用关键行为,例如设置DispatcherServlet。@ComponentScan:让 Spring 在com/example包中寻找其他组件、配置和服务,从而找到控制器。
main() 方法通过 Spring Boot 的 SpringApplication.run() 启动应用程序。你注意到了吗?其中没有一行 XML,也没有 web.xml 文件。这个应用程序完全用 Java 编写,你无需处理底层装配或基础设施配置。
现在需要修改 Initializr 创建的简单类。要生成输出——本例中输出到控制台——需要设置 logger,然后准备一些数据,并用这些数据生成输出。完整的 AccessingDataJpaApplication 类如下:
Java
package com.example.accessingdatajpa;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class AccessingDataJpaApplication {
private static final Logger logger = LoggerFactory.getLogger(AccessingDataJpaApplication.class);
public static void main(String[] args) {
SpringApplication.run(AccessingDataJpaApplication.class, args);
}
@Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args) -> {
// save a few customers
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "O'Brian"));
repository.save(new Customer("Kim", "Bauer"));
repository.save(new Customer("David", "Palmer"));
repository.save(new Customer("Michelle", "Dessler"));
// fetch all customers
logger.info("Customers found with findAll():");
logger.info("-------------------------------");
repository.findAll().forEach(customer -> {
logger.info(customer.toString());
});
logger.info("");
// fetch an individual customer by ID
Customer customer = repository.findById(1L);
logger.info("Customer found with findById(1L):");
logger.info("--------------------------------");
logger.info(customer.toString());
logger.info("");
// fetch customers by last name
logger.info("Customer found with findByLastName('Bauer'):");
logger.info("--------------------------------------------");
repository.findByLastName("Bauer").forEach(bauer -> {
logger.info(bauer.toString());
});
logger.info("");
};
}
}
Kotlin
package com.example.accessingdatajpa
import org.slf4j.LoggerFactory
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
private val logger = LoggerFactory.getLogger(AccessingDataJpaApplication::class.java)
@SpringBootApplication
class AccessingDataJpaApplication {
@Bean
fun demo(repository: CustomerRepository) = CommandLineRunner {
// save a few customers
repository.saveAll(
listOf(
Customer("Jack", "Bauer"),
Customer("Chloe", "O'Brian"),
Customer("Kim", "Bauer"),
Customer("David", "Palmer"),
Customer("Michelle", "Dessler")
)
)
// fetch all customers
logger.info("Customers found with findAll():")
logger.info("-------------------------------")
repository.findAll().forEach { customer ->
logger.info(customer.toString())
}
logger.info("")
// fetch an individual customer by ID
val customer = repository.findById(1L).orElseThrow()
logger.info("Customer found with findById(1L):")
logger.info("--------------------------------")
logger.info(customer.toString())
logger.info("")
// fetch customers by last name
logger.info("Customer found with findByLastName('Bauer'):")
logger.info("--------------------------------------------")
repository.findByLastName("Bauer").forEach { bauer ->
logger.info(bauer.toString())
}
logger.info("")
}
}
fun main(args: Array<String>) {
runApplication<AccessingDataJpaApplication>(*args)
}
AccessingDataJpaApplication 类包含一个 demo() 方法,用来演示 CustomerRepository 的几种操作。它首先从 Spring 应用程序上下文中取得 CustomerRepository,然后保存几个 Customer 对象,展示 save() 方法,并准备后续操作所需的数据。接着调用 findAll() 从数据库取得全部 Customer 对象,再调用 findById() 按 ID 查找单个客户。
最后,它调用 findByLastName(),找出姓氏为 Bauer 的全部客户。demo() 返回一个 CommandLineRunner bean,应用程序启动时会自动运行其中的代码。
构建可执行 JAR
可以用 Gradle 或 Maven 从命令行运行应用程序,也可以构建单个可执行 JAR 文件,其中包含所有必要的依赖、类与资源,再运行它。构建可执行 JAR 后,更容易在整个开发生命周期中,跨不同环境将服务作为应用程序交付、进行版本管理与部署。
如果使用 Gradle,可以通过 ./gradlew bootRun 运行应用程序;也可以使用 ./gradlew build 构建 JAR,然后运行:
java -jar build/libs/gs-accessing-data-jpa-0.0.1-SNAPSHOT.jar
如果使用 Maven,可以通过 ./mvnw spring-boot:run 运行应用程序;也可以使用 ./mvnw clean package 构建 JAR,然后运行:
java -jar target/gs-accessing-data-jpa-0.0.1-SNAPSHOT.jar
按指南运行应用程序后,应看到与下列内容相似的输出:
Customers found with findAll():
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=2, firstName='Chloe', lastName='O'Brian']
Customer[id=3, firstName='Kim', lastName='Bauer']
Customer[id=4, firstName='David', lastName='Palmer']
Customer[id=5, firstName='Michelle', lastName='Dessler']
Customer found with findById(1L):
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer found with findByLastName('Bauer'):
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=3, firstName='Kim', lastName='Bauer']
小结
你已经编写了一个简单应用程序,使用 Spring Data JPA 将对象保存到数据库并取回它们,整个过程无需编写具体的 repository 实现。
另请参阅
以下指南也可能有帮助:
希望编写新的指南,或为现有指南作贡献?请参阅贡献指南。











暂无评论内容