# Spring Data JPA 入门教程
# 环境搭建
# JPA + H2 环境
略,请看 Spring 官网的 Guides。
# JPA + MySQL 环境
在学习阶段使用 H2 数据库是很方便的,但最终到了生产肯定要切换到 MySQL。
首先要启动 MySQL 服务器,这里推荐使用 Docker,参考Docker 官网 (opens new window)
- 启动服务:
$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
- 测试服务是否启动成功:
$ docker run -it --rm mysql:tag mysql -h192.168.x.x -uroot -p
然后在 Spring 项目中连接 MySQL,参考Spring 官方教程 (opens new window),关键步骤:
- 启动 MySQL
- 在 MySQL 中创建一个数据库
- 在 MySQL 中创建一个用户
- 在 application.properties 中配置刚创建的 MySQL 数据库、用户名、密码
- 进行后续的开发
# 定义 Entity、Repository
# 定义 Entity
在 JPA 中,实体 (Entity) 相当于数据模型。下面我们创建一个咖啡实体。
首先定义咖啡的 POJO,为了方便业务使用,我们还定义了一个构造函数:
public class Coffee {
private Long id;
private String name;
private double price;
public Coffee(String name, double price) {
this.name = name;
this.price = price;
}
}
为了让 POJO 被识别为 JPA Entity,必须有 @Entity
,光这样还不够,IDE 会提示说还需要 @Id
和无参构造函数。
@Entity
public class Coffee {
@Id
private Long id;
private String name;
private double price;
public Coffee() {}
public Coffee(String name, double price) {
this.name = name;
this.price = price;
}
// 省略大量的 getter/setter 方法
}
构造函数、getter/setter 写起来简单枯燥,我们使用 lombok 提供的注解来减少样板代码。
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Coffee {
@Id
private Long id;
private String name;
private double price;
}
# 定义 Repository
Repository 是 Spring 对数据访问层的抽象,使用时需要定义一个继承自 org.springframework.data.repository.Repository
的接口。
下面为我们的咖啡实体定义一个 Repository:
public interface CoffeeRepository extends CrudRepository<Coffee, Long> {
}
# 使用 Repository 访问数据库
我们先来看一下入口类,这里用到的 SpringBoot 有点超纲,但没关系,我们没必要一开始就搞明白所有知识点。现在我们只需要知道 run()
是入口函数。
@SpringBootApplication
@Slf4j
public class SpringbucksApplication implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(SpringbucksApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
}
}
下面我们使用前面定义好的 CoffeeRepository 读写数据库:
@SpringBootApplication
@Slf4j
public class SpringbucksApplication implements ApplicationRunner {
@Autowired
private CoffeeRepository coffeeRepository;
public static void main(String[] args) {
SpringApplication.run(SpringbucksApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
initOrders();
}
private void initOrders() {
Coffee latte = Coffee.builder().id(1L).name("latte").price(11.9).build();
Coffee espresso = new Coffee(2L, "espresso", 13.9);
coffeeRepository.save(latte);
coffeeRepository.save(espresso);
log.info("共{}个咖啡", coffeeRepository.count());
coffeeRepository.findAll().forEach(c -> log.info("咖啡名:{},价格:{}", c.getName(), c.getPrice()));
}
}
# Entity
# 完善 Entity 定义
知识点如下:
- 一般的实践会增加
createTime
和updateTime
这两个字段 - 使用
@Table
指定表名,如果省略则表名默认为类名 - 主键用
@Id
,一般会配合@GeneratedValue
实现主键自动填充
@Entity
@Table(name = "T_COFFEE")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Coffee {
@Id
@GeneratedValue
private Long id;
private String name;
private double price;
@CreationTimestamp
private Date createTime;
@UpdateTimestamp
private Date updateTime;
}
# 如何定义多表连接
# 如何处理金额
涉及到金额的系统,一定要注意,不要用浮点数存储金额。
# Repository
Repository 是一个继承自 Repository
的接口。
public interface CoffeeRepository extends CrudRepository<Coffee, Long> {
List<Coffee> findByNameIgnoreCase(String name);
List<Coffee> findByPriceBetween(double start, double end);
}