Skip to main content

07.springBootJpa

1 连接数据库配置示例

1.1 数据库配置文件

spring:
datasource:
url: jdbc:mysql://localhost:3306/zhuche?characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: 12345678
jpa:
hibernate:
ddl-auto: create-drop # <-- 这里是每次启动时都重建数据表,适用于开发阶段,如果是生产环境的话,则写none才合适。

1.2 需要用到的maven依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

1.2 创建模型

package com.zhuche.server.model;

import javax.persistence.*;
import java.util.List;

@Entity // <-- 加入持久化实例注解
@Table(name = "banner") // <-- 指定表名
public class BannerModel {
@Id
private long id; // <-- 字段 id

private String name; // <-- 字段 name

private String description; // <-- 字段 description

private String img; // <-- 字段 img

private String title; // <-- 字段 title
}

然后重启下应用,这在zhuche数据库中就已生成了一张名为banner的数据表了。

2 "1对多"示例

现有一个banner表,而banner下关联着banner_item表中的多条记录。这就是典型的1对多了。以下就是通过模型类的方式把这种关系描述 出来:

package com.zhuche.server.model;

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "banner")
public class BannerModel {
@Id
private long id;

private String name;

private String description;

private short type;

private String img;

private String title;

@OneToMany
@JoinColumn(name = "bannerId") // 本模型1对多子模型,且本模型的在子模型的外键名为: bannerId
private List<BannerItemModel> Items;
}
package com.zhuche.server.model;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "banner_item") // 这是子模型
public class BannerItemModel {
@Id
private long id;

private String img;

private String keyword;

private short type;

private String name;

private Long bannerId; // 这是banner模型的外键
}

添加repository层的文件;

package com.zhuche.server.repository;

import com.zhuche.server.model.BannerModel;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BannerRepository extends JpaRepository<BannerModel, Long> {
BannerModel findOneById(Long id);

BannerModel findOneByName(String name);
}

最后调用它:

package com.zhuche.server.api.v1;

import com.zhuche.server.model.BannerModel;
import com.zhuche.server.service.BannerService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotBlank;

@RestController
@RequestMapping("/banner")
@Validated
public class BannerController {
protected BannerService _bannerService;

public BannerController(BannerService bannerService) {
this._bannerService = bannerService;
}

@GetMapping("/name/{name}")
public BannerModel getByName(@PathVariable @NotBlank String name) {
BannerModel banner = this._bannerService.getByName(name);

return banner; // <-- 这就是了调用后返回的查询结果了
}
}

然后重启下应用,就会生成bannerbanner_item这2个表了。其整个调用层次为controller -> service -> repository -> model

3 开启sql控制台输出

model在对数据库操作的过程,本质上是通过sql来实现的,在开发中,及时查看sql能快速定位问题所在.

server:
port: 8081
spring:
datasource:
url: jdbc:mysql://localhost:3306/zhuche?characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: 12345678
jpa:
properties:
hibernate:
show_sql: true # <-- 启用sql输出
format_sql: true # <-- 并格式化

重启下应用,就可以了。

4 "一对多"和"多对一"的双向绑定

一对多那么反过来也可以多对一, 用数据表来说,就是banner是父表,而banner_item是子表,一个banner的数据可能对应多条baner_item 的记录,反过来banner_item也可以对应banner表的记录,这就是双向。而维持这种关系的外键是存放在baner_item表中的baner_id键 示例如下:

4.1 模型层文件示例

package com.zhuche.server.model;

import javax.persistence.*;
import java.util.List;


@Entity
@Table(name = "banner")
public class BannerModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

private String name;

private String description;

private short type;

private String img;

private String title;

@OneToMany(mappedBy = "banner")
private List<BannerItemModel> Items;
}
package com.zhuche.server.model;

import javax.persistence.*;

@Entity
@Table(name = "banner_item")
public class BannerItemModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

private String img;

private String keyword;

private short type;

private String name;

protected Long bannerId;

@ManyToOne
@JoinColumn(insertable = false, updatable = false, name = "bannerId")
private BannerModel banner;
}

4.2 repository层文件示例

package com.zhuche.server.repository;

import com.zhuche.server.model.BannerModel;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BannerRepository extends JpaRepository<BannerModel, Long> {
BannerModel findOneById(Long id);

BannerModel findOneByName(String name);
}

4.3 service服务层示例

package com.zhuche.server.service;

import com.zhuche.server.model.BannerModel;

public interface BannerService {
BannerModel getByName(String name);
}
package com.zhuche.server.service;

import com.zhuche.server.model.BannerModel;
import com.zhuche.server.repository.BannerRepository;
import org.springframework.stereotype.Service;

@Service
public class BannerServiceImpl implements BannerService{
private final BannerRepository _bannerRepository;

public BannerServiceImpl(BannerRepository bannerRepository) {
this._bannerRepository = bannerRepository;
}

@Override
public BannerModel getByName(String name) {
return this._bannerRepository.findOneByName(name);
}
}

4.5 controller控制层调用示例

package com.zhuche.server.api.v1;

import com.zhuche.server.model.BannerModel;
import com.zhuche.server.service.BannerService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotBlank;

@RestController
@RequestMapping("/banner")
@Validated
public class BannerController {
protected BannerService _bannerService;

public BannerController(BannerService bannerService) {
this._bannerService = bannerService;
}

@GetMapping("/name/{name}")
public BannerModel getByName(@PathVariable @NotBlank String name) {
BannerModel banner = this._bannerService.getByName(name);

return banner;
}
}

5 双向多对多

package com.zhuche.server.model;

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "theme")
public class ThemeModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String title;

private String name;

@ManyToMany
@JoinTable(
name = "theme_spu",
joinColumns = @JoinColumn(name = "theme_id"),
inverseJoinColumns = @JoinColumn(name = "spu_id")
)
private List<SpuModel> spuList;
}
package com.zhuche.server.model;

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "spu")
public class SpuModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String title;

private String subtitle;

@ManyToMany(mappedBy = "spuList")
private List<ThemeModel> themeList;
}

6 禁用物理外键

JPA默认有物理外键的,不需要来自数据库的物理外键约束的话。可以禁用掉。

6.1 指定单个j实例不加物理外键的注解方式

package com.zhuche.server.model;

import javax.persistence.
@Entity
@Table(name = "banner_item")
public class BannerItemModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

private String img;

private String keyword;

private short type;

private String name;

protected Long bannerId;

@ManyToOne
@JoinColumn(
foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT), // <-- 加入这行注解
insertable = false, updatable = false, name = "bannerId"
)
private BannerModel banner;
}

7 操作时间相关的字段声明

package com.zhuche.server.model;


import lombok.Getter;
import lombok.Setter;

import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;

@Getter
@Setter
@MappedSuperclass // <-- 用于,让继承本抽像类后,本类的字段声明生效
public abstract class BaseEntity {
@Column(columnDefinition = "DATETIME DEFAULT CURRENT_TIMESTAMP")
private LocalDateTime createTime;

@Column( columnDefinition = "datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
private LocalDateTime updateTime;

private LocalDateTime deleteTime;
}