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; // <-- 这就是了调用后返回的查询结果了
    }
}
然后重启下应用,就会生成banner和banner_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;
}