本片文章我们主要介绍 spring-boot 如何进行 JPA 的配置以及如何进行实体间的一对多配置.
依赖准备
要在 spring-boot 使用 jpa 需要在项目中有进入相关的依赖, pom 文件里加入下面内容
- <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>
- <scope>runtime</scope>
- </dependency>
项目的配置文件中需要对数据库链接以及 jpa 进行配置:
- spring:
- datasource:
- url: jdbc:MySQL://localhost:3306/missyou?characterEncoding=utf-8&serverTimezone=GMT+8
- username: root
- password: 12345678
- jpa:
- hibernate:
- ddl-auto: update # 只针对新增的 entity 创建表
- properties:
- hibernate:
- show_sql: true # 在对数据库进行操作的时候打印出 sql, 方便在生产环境排查问题
- format_sql: true # 打印 sql 的时候进行格式化, 看起来方便
jpa 实战
一对多关系
先定义两个实体类 Banner 和 BannerItem, 一个 Banner 可以对应多个 BannerItem, 属于典型的一对多的关系
- @Entity
- public class Banner {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private long id;
- @Column(length = 16)
- private String name;
- @Transient // 表明这个字段不会映射到表中的字段
- private String description;
- private String img;
- private String title;
- @OneToMany
- private List<BannerItem> items; // 关联属性, 导航属性
- }
- @Entity
- public class BannerItem {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private Long id;
- private String img;
- private String keyword;
- private Short type;
- private String name;
- }
先对上面代码中的一些注解进行说明:
@Entity 标记当前类为一个实体, 对应数据库中的一张表, 用来表示这张表信息, 类名默认就是表名, jpa 会根据命名规则自动小写并加下划线, 比如 BannerItem 实体, 生成的表名就是 banner_item
@Id 表名标记的字段将作为主键
@GeneratedValue(strategy = GenerationType.IDENTITY) 设置 id 为自增长
@Column(length = 16) 设置字段的属性, 比如长度, 是否为空, 是否唯一等
@OneToMany 可以使用两个实体建立一对多的关系, 也就是一个 Banner 可以包含多个 BannerItem
@Transient 注解表示被标记的当前字段不会映射到数据库表的字段, 也就是说生成的表中不会包含这个字段
此时运行程序, 就会在数据库中创建对应的表:
这里生成了三张表, banner 表和 banner_item 表我们知道是对应的 Banner 实体和 BannerItem 实体, 那 banner_items 这张表是怎么回事呢?
在解释这张表之前, 我们先来看一下这个表的结构:
表里只有两个字段, banner_id 和 items_id, 分别是 banner 的 id 和 banner_item 的 id, 这就是说这张表相当于一张关系表, 在多对多的时候我们才需要一张关系表, 而现在只是一对多, 为什么会产生这张表呢?
这是因为在上面的实体定义的时候, 我们只是给这两个实体建立了关系, 并没有任何一个字段来表明哪一个 BannerItem 属于哪一个 Banner, 那 JPA 看到你没有做, 那就我来做, 他会自动帮你创建这样一张关系表来维护这种归属关系. 那有没有办法去掉这张表呢, 当然有.
这个时候就需要新增一个外键字段了, 来表明一个 banner_item 到底是归属于哪一个 banner, 我们来修改一下上面的实体定义:
Banner 实体里做如下修改:
- @OneToMany
- @JoinColumn(name = "bannerId")
- private List<BannerItem> items;
@JoinColumn 注解指定外键
BannerItem 实体增加一个字段: bannerId
private Long bannerId;
删除之前的表, 重新运行程序
这个时候生成的表就只有两个了, 在 banner_item 表里会新增一个外键字段.
下面我们通过一个程序实例来验证上面的内容:
1, 构造数据
表结构已经构造好了, 现在我们填充一些数据, 来使用 JPA 进行数据查询
- INSERT INTO missyou.banner (id, img, name, title) VALUES (1, 'http://sss.jpg', '顶部 banner', '顶部 banner');
- INSERT INTO missyou.banner (id, img, name, title) VALUES (2, 'http://aaa.jpg', '顶部 banner2', '顶部 banner2');
- INSERT INTO missyou.banner_item (id, banner_id, img, keyword, name, type) VALUES (1, 1, 'http://www.jpj', '衣服', '阿迪促销', 1);
- INSERT INTO missyou.banner_item (id, banner_id, img, keyword, name, type) VALUES (2, 1, 'http://www.jpj', '鞋', '阿迪促销', 1);
2, 新建 Controller\service\repository
BannerRepository 仓储层, 主要负责读取数据库
- @Repository
- public interface BannerRepository extends JpaRepository<Banner, Long> {
- Banner findOneById(Long id);
- Banner findOneByName(String name);
- }
sevice 层, 具体的业务逻辑
- @Service
- public class BannerServiceImpl implements BannerService{
- @Autowired
- private BannerRepository bannerRepository;
- @Override
- public Banner getByName(String name) {
- return bannerRepository.findOneByName(name);
- }
- }
controller 层, 负责接收客户端请求返回数据
- @GetMapping("/banner/name/{name}")
- public Banner getBannerByName(@PathVariable String name){
- return bannerService.getByName(name);
- }
请求接口:
可以看到数据已经查询出来了.
双向一对多
上面的示例是根据 banner_id 去查关联的一组 banner_item, 但是有些场景我们可能需要通过某个 item_id 去查是属于哪个 banner, 那这就是一种的反向的一对多, 接下来我们看一下这总反向的一对多如何配置.
我们之前配置了一个 items 属性
- @OneToMany
- @JoinColumn(name = "bannerId")
- private List<BannerItem> items;
这个属性就可以帮我们定位到某个 banenr 关联的一组 bannerItem, 可以叫做导航属性, 那么反过来, 如何从一个 item 定位到一个 Banner, 怎么设置导航属性?
首先需要在 BannerItem 实体类里面增加一个 banner 属性, 并使用如下注解进行标记
- @ManyToOne
- @JoinColumn(name = "bannerId")
- private Banner banner;
修改 Banner 实体
- @OneToMany(mappedBy = "banner")
- private List<BannerItem> items;
这里其实就是把 @JoinColumn(name = "bannerId") 移动到 BannerItem 里面. 并且在 BanenrItem 里要删除掉之前定义的外键字段 bannerId.
这是因为在设置双向一对多的关系时, 会默认在 banner_item 表里生成一个外键, 如果自己再写一个就会造成重复, 程序就会报错.
那如果自己很想指定, 也可以, 进行如下配置
- @ManyToOne
- @JoinColumn(insertable = false, updatable = false, name = "bannerId")
- private Banner banner;
总结
以上就是我们介绍的关于在 spring-boot 中如何进行实体间的单向一对多和双向一对多的配置, 关于要在实际项目如何使用哪一种方式, 还是要结合自己的业务, 一般不需要进行双向的配置, 而且一般都不会去设置物理外键, 后面我们再讨论如何进行多对多的配置以及如何去除物理外键.
欢迎大家去 我的博客 https://www.immortalp.com/ 瞅瞅, 里面有更多关于测试实战的内容哦!!
来源: https://www.cnblogs.com/zyjimmortalp/p/12951363.html