前言
我一直认为 Spring Data JPA 是一个好东西,有着自己独特的黑魔法。但是由于目前接触甚少,不知道该如何开启。所以想通过从无到有的过程,逐渐的去认识它,搞清楚它与Mybatis的关系,如果站在架构的角度看会怎么怎么样的情况。在这个过程中,会使用文字的方式将过程记录下来,也算是一点经历。
Spring Data JPA 介绍
From spring.io:Spring Data JPA是Spring Data系列的一个组成部分,可以轻松快捷的实现数据访问层的增强支持,这使得基于Spring且使用了数据库访问技术的应用程序更加容易构建。Spring Data JPA 内置了简单数据库读写操作,包括分页查询,并提供接口以待增强。
Spring Data JPA 是基于Hibernate(在3.2版本中便对JPA提供了完全的支持)、JPA规范的基础上封装的一套ORM框架,可以说就是JPA规范的一个实践落地的产品。Spring Data JPA的内置实现中提供了包括增删改查、分页、自定义SQL的常用功能,且提供接口以待拓展增强。基于Spring Data JPA可以简洁的代码,快速的实现对数据库的访问。
使用示例
环境说明:
- windows 10 专业版
- IntelliJ IDEA 2019.3.1
- JDK 1.8
- maven 3.6.1
- Spring Boot 2.2.5.RELEASE
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 我这里使用mysql作为数据存储 -->
<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>
定义一个简单实体
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* @author zhoujian
*/
@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;
}
public Long getId() { return id; }
public void setId(Long id) { his.id = id; }
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
@Override
public String toString() {
return String.format("Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName);
}
}
创建查询接口
import org.springframework.data.repository.CrudRepository;
import java.util.List;
/**
* {@link Customer}实体的仓库接口
* @author zhoujian
*/
public interface CustomerRepository extends CrudRepository<Customer, Long> {
/**
* 根据{@link Customer#lastName}查询数据
* @param lastName {@link Customer}的属性
* @return customer list
*/
List<Customer> findByLastName(String lastName);}
简单测试
这里只是方便测试,所以直接使用了 CommandLineRunner 进行业务测试,在这里也直接与 Repository 层耦合,也不是通过单元测试,并不推荐这样的做法。
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;
/**
* @author zhoujian
*/
@SpringBootApplication
public class ForTestOrmApplication {
public static void main(String[] args) {
SpringApplication.run(ForTestOrmApplication.class, args);
}
private static final Logger LOG = LoggerFactory.getLogger(ForTestOrmApplication.class);
@Bean
public CommandLineRunner jpaTestRunner(CustomerRepository customerRepository){
return (args) -> {
// 插入五条 customer 数据
customerRepository.save(new Customer("Jack", "Liu"));
customerRepository.save(new Customer("Mary", "Liu"));
customerRepository.save(new Customer("Bob", "Huang"));
customerRepository.save(new Customer("Jim", "Chen"));
customerRepository.save(new Customer("David", "Gao"));
// 获取所有的 customer 数据
LOG.info("pull all customers with findAll():");
LOG.info("---------------------------------");
customerRepository.findAll().forEach(
customer -> LOG.info("Customer is : {}", customer.toString())
);
// 获取所有的 customer 数据
LOG.info("pull all customers with findByLastName():");
LOG.info("---------------------------------");
customerRepository.findByLastName("Liu").forEach(
customer -> LOG.info("Customer is : {}", customer.toString())
);
};
}
}
测试期望如下:
2020-04-20 08:50:01.195 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : pull all customers with findAll():
2020-04-20 08:50:01.195 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : ---------------------------------
Hibernate: select customer0_.id as id1_0_, customer0_.first_name as first_na2_0_, customer0_.last_name as last_nam3_0_ from customer customer0_
2020-04-20 08:50:01.293 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : Customer is : Customer[id=1, firstName='Jack', lastName='Liu']
2020-04-20 08:50:01.293 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : Customer is : Customer[id=2, firstName='Mary', lastName='Liu']
2020-04-20 08:50:01.293 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : Customer is : Customer[id=3, firstName='Bob', lastName='Huang']
2020-04-20 08:50:01.293 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : Customer is : Customer[id=4, firstName='Jim', lastName='Chen']
2020-04-20 08:50:01.293 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : Customer is : Customer[id=5, firstName='David', lastName='Gao']
2020-04-20 08:50:01.293 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : pull all customers with findByLastName():
2020-04-20 08:50:01.293 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : ---------------------------------
Hibernate: select customer0_.id as id1_0_, customer0_.first_name as first_na2_0_, customer0_.last_name as last_nam3_0_ from customer customer0_ where customer0_.last_name=?
2020-04-20 08:50:01.311 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : Customer is : Customer[id=1, firstName='Jack', lastName='Liu']
2020-04-20 08:50:01.312 INFO 12016 --- [ main] c.j.for_test_orm.ForTestOrmApplication : Customer is : Customer[id=2, firstName='Mary', lastName='Liu']