2.5 JPA支持
Springboot对JPA(Java Persistence API,java数据持久化,也就是数据库层)的支持很简洁。JPA是指数据库表持久化的一种技术,显著特点是表映射成类。
这是一个完整的eclipse项目,点击下载后导入,可直接运行。
首先看看pom.xml,添加了这些:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
其中com.h2database是一个嵌入式数据库h2,spring-boot-starter-data-jpa提供jpa的方法支持。
有三个java文件
1.Customer.java
这是一个数据库映射类,类的所有属性都和表一一对应。表在哪里呢?这个例子使用了一个内嵌的数据库h2,只需要配置pom文件就可以使用了。后面我们会看到。如果熟悉hibernate或者mybatis的就会发现,SpringBoot省去了xml配置文件,而使用了标签。这里@Entity就表示这是一个实体类,对应一个表。@Id表示这个属性是主键:
package com.example.accessingdatajpa;
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);
}
public Long getId(){
return id;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
}
2.CustomerRepository.java
package com.example.accessingdatajpa;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface CustomerRepository extends CrudRepository{
ListfindByLastName(String lastName);
Customer findById(long id);
}
这是一个接口,它需要继承一个接口CrudRepository,这个接口需要将指定泛型,第一个参数是要处理的映射类,第二个参数是这个映射类的主键的类型。
这里定义了两个方法,findByLastName通过lastName查找Customer,结果是一个集合;findById通过主键id查找,结果唯一。
这个接口是用来定义处理Customer表的所有方法的。
3.JPAApplication.java
这是启动类,里面有一个方法:
@Bean
public CommandLineRunner demo(CustomerRepository repository){
return(args)->{
// 保存一些Customer对象
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"));
// 从数据库取得所有Customer对象
log.info("Customers found with findAll():");
log.info("-------------------------------");
for(Customer customer:repository.findAll()){
log.info(customer.toString());
}
log.info("");
// 通过id取得一个Customer对象
Customer customer=repository.findById(1L);
log.info("Customer found with findById(1L):");
log.info("--------------------------------");
log.info(customer.toString());
log.info("");
// 通过lastName取得Customer对象
log.info("Customer found with findByLastName('Bauer'):");
log.info("--------------------------------------------");
repository.findByLastName("Bauer").forEach(bauer->{
log.info(bauer.toString());
})
;
log.info("");
};
含有@bean标签的方法,都会在启动的时候初始化,这个方法展示了Customer的两个获取方法。运行的结果直接显示在控制台:
看到这里,可能已经有人发现:CustomerRepository只是一个接口,并没有实现,实现类在哪里?具体要执行的SQL语句在哪里?
不需要实现类
SpringBoot为我们写了实现!
实现由Spring Data JPA提供,你只需要定义接口,具体SQL语句是自动生成的。在程序运行时,Spring框架会自动为CustomerRepository创建一个实现类,并且此实现类会作为一个Spring Bean被注入到你的服务(Service)层或其他需要依赖注入的组件,供应用程序使用。
只需要命名的时候按照规范。findById和findByLastNamee并不是随便写的,必须在Customer类里存在id和lastName这两个属性,只有通过主键查找才可以返回唯一值,其他的查找必须返回集合,通常就是List
findBy也是规范之一。
关于GRUD操作方法的规范命名,Spring Boot的JPA提供了很完备的命名规范,关于repository的更多细节将在7.8节介绍。
3.修改启动类
在启动类添加方法CommandLineRunner,此方法来演示如何操作数据库。Spring Boot应用在启动时会运行这个方法提供的代码,它合理地使用了JPA仓库来保存和检索Customer实例。现在的启动类DemoApplication 的代码如下所示:
package com;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;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import com.example.accessingdatajpa.Customer;import com.example.accessingdatajpa.CustomerRepository;@SpringBootApplication@RestControllerpublic class DemoApplication{ private static final Logger log=LoggerFactory.getLogger(DemoApplication.class); public static void main(String[]args){ SpringApplication.run(DemoApplication.class,args); } @GetMapping("/hello") public String hello(@RequestParam(value="name",defaultValue="World")String name){ return String.format("Hello %s!",name); } @Beanpublic CommandLineRunner demo(CustomerRepository repository){ return(args)-> { // 保存一些Customer对象 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")); // 从数据库取得所有Customer对象 log.info("Customers found with findAll():"); log.info("-------------------------------"); for(Customer customer:repository.findAll()){ log.info(customer.toString()); } log.info(""); // 通过id取得一个Customer对象 Customer customer=repository.findById(1L).get(); log.info("Customer found with findById(1L):"); log.info("--------------------------------"); log.info(customer.toString()); log.info(""); // 通过lastName取得Customer对象 log.info("Customer found with findByLastName('Bauer'):"); log.info("---------------------------------"); repository.findByLastName("Bauer").forEach(bauer -> { log.info(bauer.toString()); }); log.info(""); }; }}
代码7-13在启动类添加测试方法
含有@bean标签的方法,都会在启动的时候初始化,这个方法展示了Customer的两个获取方法。重新启动Spring Boot,运行的结果直接显示在控制台,如图所示: