# 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 定义

知识点如下:

  • 一般的实践会增加 createTimeupdateTime 这两个字段
  • 使用 @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);
}

# 定义查询

# 定义分页查询

# 自定义 SQL 查询语句

# 参考资料