当你看到了我这篇博文,那么我想你应该已经知道 Spring Data JPA 在如今的互联网开发中使用非常频繁。
所以今天这篇博文主要探讨学习Spring Boot 2.x 中如何集成Spring Data JPA.
在写代码之前,请让我们带着这三个问题去学习。
JPA全称Java Persistence API,即Java持久化API
Spring Data JPA 是Spring Data 家族的一员。
Spring 为了简化数据持久化而开发的模块。
它简化了对关系型数据库和非关系型数据库的访问。
Spring Data 家族包括以下模块:
通过上图,我们可以看到我们熟悉的JDBC,Redis,MongoDB,JPA。
Spring 针对我们程序员经常使用的JDBC,JPA,MongoDB,Redis 做了简化开发。
接下来的日子我会针对以上这几个常用的模块抽时间一一讲解。
好了,扯了那么多废话,现在让我们回归今天的主角 ————Spring Data JPA。
那么Spring Data JPA 是个什么鬼?它到底解决了什么问题?
Spring Data JPA 本质是定义了一套通用数据访问层接口,具体的实现由Hibernate来完成。
https://github.com/spring-guides/gs-accessing-data-jpa/archive/master.zip
git clone https://github.com/spring-guides/gs-accessing-data-jpa.git
1 打开IDE, 右键--------> New -------->Import Spring Getting Started Content
2.选中Accessing Data JPA,默认配置如下:
推荐这种学习方式
initial 勾选会创建一个空的项目,complete 会创建一个已完成的项目
3.点击Finish 完成后,将会看到这个
4.展开gs-accessing-data-jpa-initial 项目,可以看到项目结构如下
5.我们打开pom.xml 可以看到如下内容:
4.0.0
org.springframework
gs-accessing-data-jpa
0.1.0
org.springframework.boot
spring-boot-starter-parent
2.0.5.RELEASE
1.8
org.springframework.boot
spring-boot-starter-data-jpa
com.h2database
h2
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
Customer.java
package hello;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.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);
}
}
@Entity 表明这是一个JPA持久化类对象 由于缺少@Table注解,因此假定此实体将映射到名为Customer的表。
@Id 和@GeneratedValue(strategy=GenerationType.AUTO) 标识这是一个自增长ID
现在我们这个Customer对象有了这些属性,id,firstName,lastName.
我们也有了两个构造方法,默认构造函数仅为JPA而存在。 我们不会直接使用它,因此它被指定为受保护的用protected 关键字标识。
另一个构造函数是我们将用于创建要保存到数据库的Customer实例的构造函数。 为了让代码看起来简洁,这里省略了getter 和setter 方法,但是不影响使用。
7.创建一个简单的查询
我们创建一个接口类CustomerRepository.java
package hello;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface CustomerRepository extends CrudRepository{
List findByLastName(String lastName);
}
CustomerRepository扩展了CrudRepository接口。
它使用的实体和ID类型Customer和Long在CrudRepository的通用参数中指定。
通过扩展CrudRepository,CustomerRepository继承了几种使用Customer持久性的方法,包括用于保存,删除和查找Customer实体的方法。
Spring Data JPA还允许我们通过简单地声明其方法签名来定义其他查询方法。
对于CustomerRepository,它使用findByLastName()方法显示。
在典型的Java应用程序中,您希望编写一个实现CustomerRepository的类。 但这就是使Spring Data JPA如此强大的原因:我们不必编写存储库接口的实现。 Spring Data JPA在您运行应用程序时动态创建实现
Spring Data JPA如此强大的原因:我们不必编写存储库接口的实现。 Spring Data JPA在您运行应用程序时动态创建实现
8.创建应用程序启动类Application.java
package hello;
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 Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
@Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args) -> {
// save a couple of 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
log.info("Customers found with findAll():");
log.info("-------------------------------");
for (Customer customer : repository.findAll()) {
log.info(customer.toString());
}
log.info("");
// fetch an individual customer by ID
repository.findById(1L)
.ifPresent(customer -> {
log.info("Customer found with findById(1L):");
log.info("--------------------------------");
log.info(customer.toString());
log.info("");
});
// fetch customers by last name
log.info("Customer found with findByLastName('Bauer'):");
log.info("--------------------------------------------");
repository.findByLastName("Bauer").forEach(bauer -> {
log.info(bauer.toString());
});
// for (Customer bauer : repository.findByLastName("Bauer")) {
// log.info(bauer.toString());
// }
log.info("");
};
}
}
@SpringBootApplication是一个方便的注解,添加了以下所有内容:
main()方法使用Spring Boot的SpringApplication.run()方法来启动应用程序。 您是否注意到没有一行XML?也没有web.xml文件。 此Web应用程序是100%纯Java,我们无需处理配置任何管道或基础结构。
Application包含一个main()方法,它通过一些测试放置CustomerRepository。 首先,它从Spring应用程序上下文中获取CustomerRepository。 然后它保存了一些Customer对象,演示了save()方法并设置了一些要处理的数据。 接下来,它调用findAll()从数据库中获取所有Customer对象。 然后它调用findOne()以通过其ID获取单个Customer。 最后,它调用findByLastName()来查找姓氏为“Bauer”的所有客户。
默认情况下,Spring Boot将启用JPA存储库支持并查看@SpringBootApplication所在的包(及其子包)。
如果您的配置包含位于包中的JPA存储库接口定义,则可以使用@EnableJpaRepositories及其类型安全的basePackageClasses
= MyRepository.class参数指出备用包。
运行主方法后可以看到
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.5.RELEASE)
2018-12-15 11:49:45.689 INFO 8704 --- [ main] hello.Application : Starting Application on DESKTOP-P6BK6E2 with PID 8704 (C:\Users\fairy\Documents\SpringBootWorkSpace\gs-accessing-data-jpa-initial\target\classes started by fairy in C:\Users\fairy\Documents\SpringBootWorkSpace\gs-accessing-data-jpa-initial)
2018-12-15 11:49:45.693 INFO 8704 --- [ main] hello.Application : No active profile set, falling back to default profiles: default
2018-12-15 11:49:45.729 INFO 8704 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4c40b76e: startup date [Sat Dec 15 11:49:45 CST 2018]; root of context hierarchy
2018-12-15 11:49:47.602 INFO 8704 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2018-12-15 11:49:47.943 INFO 8704 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2018-12-15 11:49:48.211 INFO 8704 --- [ main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2018-12-15 11:49:48.288 INFO 8704 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2018-12-15 11:49:48.615 INFO 8704 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.2.17.Final}
2018-12-15 11:49:48.617 INFO 8704 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2018-12-15 11:49:48.720 INFO 8704 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2018-12-15 11:49:48.964 INFO 8704 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2018-12-15 11:49:49.630 INFO 8704 --- [ main] o.h.t.schema.internal.SchemaCreatorImpl : HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@70f31322'
2018-12-15 11:49:49.635 INFO 8704 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2018-12-15 11:49:50.386 INFO 8704 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-12-15 11:49:50.388 INFO 8704 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'dataSource' has been autodetected for JMX exposure
2018-12-15 11:49:50.394 INFO 8704 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]
2018-12-15 11:49:50.408 INFO 8704 --- [ main] hello.Application : Started Application in 5.004 seconds (JVM running for 6.221)
2018-12-15 11:49:50.585 INFO 8704 --- [ main] hello.Application : Customers found with findAll():
2018-12-15 11:49:50.585 INFO 8704 --- [ main] hello.Application : -------------------------------
2018-12-15 11:49:50.748 INFO 8704 --- [ main] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
2018-12-15 11:49:50.891 INFO 8704 --- [ main] hello.Application : Customer[id=1, firstName='Jack', lastName='Bauer']
2018-12-15 11:49:50.891 INFO 8704 --- [ main] hello.Application : Customer[id=2, firstName='Chloe', lastName='O'Brian']
2018-12-15 11:49:50.891 INFO 8704 --- [ main] hello.Application : Customer[id=3, firstName='Kim', lastName='Bauer']
2018-12-15 11:49:50.891 INFO 8704 --- [ main] hello.Application : Customer[id=4, firstName='David', lastName='Palmer']
2018-12-15 11:49:50.891 INFO 8704 --- [ main] hello.Application : Customer[id=5, firstName='Michelle', lastName='Dessler']
2018-12-15 11:49:50.891 INFO 8704 --- [ main] hello.Application :
2018-12-15 11:49:50.904 INFO 8704 --- [ main] hello.Application : Customer found with findById(1L):
2018-12-15 11:49:50.904 INFO 8704 --- [ main] hello.Application : --------------------------------
2018-12-15 11:49:50.904 INFO 8704 --- [ main] hello.Application : Customer[id=1, firstName='Jack', lastName='Bauer']
2018-12-15 11:49:50.904 INFO 8704 --- [ main] hello.Application :
2018-12-15 11:49:50.904 INFO 8704 --- [ main] hello.Application : Customer found with findByLastName('Bauer'):
2018-12-15 11:49:50.904 INFO 8704 --- [ main] hello.Application : --------------------------------------------
2018-12-15 11:49:50.943 INFO 8704 --- [ main] hello.Application : Customer[id=1, firstName='Jack', lastName='Bauer']
2018-12-15 11:49:50.943 INFO 8704 --- [ main] hello.Application : Customer[id=3, firstName='Kim', lastName='Bauer']
2018-12-15 11:49:50.943 INFO 8704 --- [ main] hello.Application :
2018-12-15 11:49:50.945 INFO 8704 --- [ Thread-3] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@4c40b76e: startup date [Sat Dec 15 11:49:45 CST 2018]; root of context hierarchy
2018-12-15 11:49:50.950 INFO 8704 --- [ Thread-3] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2018-12-15 11:49:50.951 INFO 8704 --- [ Thread-3] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans
2018-12-15 11:49:50.953 INFO 8704 --- [ Thread-3] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2018-12-15 11:49:50.954 INFO 8704 --- [ Thread-3] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed drop of schema as part of SessionFactory shut-down'
2018-12-15 11:49:50.960 INFO 8704 --- [ Thread-3] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2018-12-15 11:49:50.963 INFO 8704 --- [ Thread-3] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
参考官方指南英文版:https://spring.io/guides/gs/accessing-data-jpa/
更多Spring官方学习指南 https://spring.io/guides