我们搭建一个maven项目,然后我们加载数据,数据我已经准备好了。
delete from jpa_test.oo_t_idcard where 1=1;
delete from jpa_test.oo_t_person where 1=1;
INSERT INTO jpa_test.oo_t_person (id, created_by, created_date, last_modified_by, last_modified_date, hair_color, height, weight) VALUES (1, 4, '2019-12-12 02:55:14.786000000', 4, '2019-12-12 02:55:14.786000000', 'green', 62.00, 75.00);
INSERT INTO jpa_test.oo_t_person (id, created_by, created_date, last_modified_by, last_modified_date, hair_color, height, weight) VALUES (2, 4, '2019-12-12 02:55:14.841000000', 4, '2019-12-12 02:55:14.841000000', 'blue', 97.00, 23.00);
INSERT INTO jpa_test.oo_t_person (id, created_by, created_date, last_modified_by, last_modified_date, hair_color, height, weight) VALUES (3, 4, '2019-12-12 02:55:14.843000000', 4, '2019-12-12 02:55:14.843000000', 'yellow', 20.00, 9.00);
INSERT INTO jpa_test.oo_t_person (id, created_by, created_date, last_modified_by, last_modified_date, hair_color, height, weight) VALUES (4, 4, '2019-12-12 02:55:14.845000000', 4, '2019-12-12 02:55:14.845000000', 'blue', 102.00, 35.00);
INSERT INTO jpa_test.oo_t_person (id, created_by, created_date, last_modified_by, last_modified_date, hair_color, height, weight) VALUES (5, 4, '2019-12-12 02:55:14.847000000', 4, '2019-12-12 02:55:14.847000000', 'blue', 120.00, 45.00);
INSERT INTO jpa_test.oo_t_person (id, created_by, created_date, last_modified_by, last_modified_date, hair_color, height, weight) VALUES (6, 4, '2019-12-12 02:55:14.848000000', 4, '2019-12-12 02:55:14.848000000', 'blue', 98.00, 42.00);
INSERT INTO jpa_test.oo_t_person (id, created_by, created_date, last_modified_by, last_modified_date, hair_color, height, weight) VALUES (7, 4, '2019-12-12 02:55:14.851000000', 4, '2019-12-12 02:55:14.851000000', 'green', 156.00, 17.00);
INSERT INTO jpa_test.oo_t_person (id, created_by, created_date, last_modified_by, last_modified_date, hair_color, height, weight) VALUES (8, 4, '2019-12-12 02:55:14.854000000', 4, '2019-12-12 02:55:14.854000000', 'black', 72.00, 8.00);
INSERT INTO jpa_test.oo_t_person (id, created_by, created_date, last_modified_by, last_modified_date, hair_color, height, weight) VALUES (9, 4, '2019-12-12 02:55:14.856000000', 4, '2019-12-12 02:55:14.856000000', 'black', 105.00, 5.00);
INSERT INTO jpa_test.oo_t_person (id, created_by, created_date, last_modified_by, last_modified_date, hair_color, height, weight) VALUES (10, 4, '2019-12-12 02:55:14.858000000', 4, '2019-12-12 02:55:14.858000000', 'red', 172.00, 16.00);
INSERT INTO jpa_test.oo_t_idcard (id, created_by, created_date, last_modified_by, last_modified_date, card_no, name, sex, person_id) VALUES (11, 4, '2019-12-12 02:55:15.716000000', 4, '2019-12-12 02:55:15.716000000', '6c398cd7-8ed9-4c6c-8080-120a1a826f89', '张三1', 0, 2);
INSERT INTO jpa_test.oo_t_idcard (id, created_by, created_date, last_modified_by, last_modified_date, card_no, name, sex, person_id) VALUES (12, 4, '2019-12-12 02:55:15.719000000', 4, '2019-12-12 02:55:15.719000000', '87b5feff-8255-4ac6-aa69-6a9990048dcd', '孙七', 0, 3);
INSERT INTO jpa_test.oo_t_idcard (id, created_by, created_date, last_modified_by, last_modified_date, card_no, name, sex, person_id) VALUES (13, 4, '2019-12-12 02:55:15.720000000', 4, '2019-12-12 02:55:15.720000000', '307dc084-a241-452b-b609-c824eb96bc44', '李四', 0, 4);
INSERT INTO jpa_test.oo_t_idcard (id, created_by, created_date, last_modified_by, last_modified_date, card_no, name, sex, person_id) VALUES (14, 4, '2019-12-12 02:55:15.722000000', 4, '2019-12-12 02:55:15.722000000', '5e704f89-2d13-4794-9494-29dfa7c446ec', '赵六', 0, 5);
INSERT INTO jpa_test.oo_t_idcard (id, created_by, created_date, last_modified_by, last_modified_date, card_no, name, sex, person_id) VALUES (15, 4, '2019-12-12 02:55:15.724000000', 4, '2019-12-12 02:55:15.724000000', 'b0ade2b0-a350-4536-90a0-4b09736493ec', '李四', 1, 6);
INSERT INTO jpa_test.oo_t_idcard (id, created_by, created_date, last_modified_by, last_modified_date, card_no, name, sex, person_id) VALUES (16, 4, '2019-12-12 02:55:15.727000000', 4, '2019-12-12 02:55:15.727000000', 'a9c1531e-8719-4912-8bc7-ba3f7a5da05f', '李四', 1, 7);
INSERT INTO jpa_test.oo_t_idcard (id, created_by, created_date, last_modified_by, last_modified_date, card_no, name, sex, person_id) VALUES (17, 4, '2019-12-12 02:55:15.729000000', 4, '2019-12-12 02:55:15.729000000', '1ad27d7b-0208-4adb-a856-d6a87dc4a227', '钱八', 0, 8);
INSERT INTO jpa_test.oo_t_idcard (id, created_by, created_date, last_modified_by, last_modified_date, card_no, name, sex, person_id) VALUES (18, 4, '2019-12-12 02:55:15.733000000', 4, '2019-12-12 02:55:15.733000000', '08fd002e-bce7-4931-acb0-b18cf134880b', '王五', 1, 9);
INSERT INTO jpa_test.oo_t_idcard (id, created_by, created_date, last_modified_by, last_modified_date, card_no, name, sex, person_id) VALUES (19, 4, '2019-12-12 02:55:15.740000000', 4, '2019-12-12 02:55:15.740000000', '34f09eef-c0f5-4418-936c-b58c2a82b256', '钱八', 1, 10);
INSERT INTO jpa_test.oo_t_idcard (id, created_by, created_date, last_modified_by, last_modified_date, card_no, name, sex, person_id) VALUES (20, 4, '2019-12-12 02:55:16.213000000', 4, '2019-12-12 02:55:16.213000000', 'a9963fd3-be45-483f-b5e1-e409de9c9c84', '赵六', 0, 1);
然后我们编写一个人和身份证两个实体类之间的一对一的关系:
@Entity
@Table(name = "oo_t_idcard")
@Data
@ToString(exclude = "person", callSuper = true)
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class IdCard extends DefaultEntity {
private static final long serialVersionUID = -4315695680043696544L;
private String name;
private String cardNo;
private Integer sex;
@OneToOne
@JoinColumn(foreignKey = @ForeignKey(name = "fk_person"))
private Person person;
}
@Entity
@Table(name = "oo_t_person")
@Setter
@Getter
@ToString(exclude = "idCard", callSuper = true)
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Person extends DefaultEntity {
private static final long serialVersionUID = 4051419685118041233L;
private BigDecimal height;
private BigDecimal weight;
private String hairColor;
@OneToOne(mappedBy = "person", cascade = {CascadeType.MERGE, CascadeType.REMOVE})
private IdCard idCard;
}
然后就是定义接口继承hibernate提供的仓库JpaRepository如下代码:
public interface IDCardRepository extends JpaRepository<IdCard, Long> {
}
public interface PersonRepository extends BaseRepository<Person, Long> {
Optional<Person> findByWeightAndHeight(BigDecimal weight, BigDecimal height);
int countByHairColor(String hairColor);
@Query("from Person p left join fetch p.idCard i where i.name = ?1")
Person findSomePersonByNameAtJPQL(String name);
@Query(value = "select * from oo_t_person p left join oo_t_idcard oti on p.id = oti.person_id where oti.name = ?1"
, nativeQuery = true)
Person findSomePersonByNameAtNative(String name);
@Transactional
long deleteByHeight(BigDecimal height);
}
最后我们边测试边理解hibernate的各种api方法,和查询方法和规则:
public class One2OneRepositoryTest extends BaseTest {
private int dataCount = 10;
private String[] nameArr = {"张三", "李四", "王五", "赵六", "孙七", "钱八"};
private Integer[] sexArr = {0, 1};
private String[] hairColorArr = {"red", "green", "black", "blue", "yellow", "pink", "gray"};
private Random random = new Random();
@Autowired
private DynamicLeftJoinQuery dynamicLeftJoinQuery;
@Autowired
private EntityManager entityManager;
@Test
@Order(1)
@Disabled
@DisplayName("批量数据保存(Person -> IdCard)")
void testSave1() {
System.out.println("=== Person表保存所有生成出来的数据 =========================================");
Collection<Person> persons = initPersonData(dataCount);
personRepository.saveAll(persons);
Person firstPerson = persons.iterator().next();
persons.remove(firstPerson);
System.out.println("=== 将第一个Person数据从persons集合移出,并将其他Person数据生成对应的idCard数据 =========================================");
Collection<IdCard> idCards = initIDCardData(persons);
System.out.println("=== 保存idCards集合的所有数据,除第一个Person =========================================");
idCardRepository.saveAll(idCards);
System.out.println("=== 用自由态的方式关联赋值给idCard,并保存 =========================================");
idCards = initIDCardData(Collections.singleton((Person) new Person().setId(firstPerson.getId())));
idCardRepository.saveAll(idCards);
assertAll(
() -> assertThat(assertThat(idCardRepository.getOne()
.getPerson()
.getId())
.isNotNull()),
() -> assertThat(assertThat(idCardRepository
.count(Example.of(new IdCard()
.setPerson((Person) new Person()
.setId(firstPerson.getId())))))
.isEqualTo(1))
);
}
@Test
@Order(2)
@Disabled
@DisplayName("批量数据保存(IdCard -> Person)")
void testSave2() {
Person person = initPersonData(1).get(0);
IdCard idCard = initIDCardData(Collections.singleton(person)).get(0);
idCard.setPerson(null);
System.out.println("=== 先分别保存无关联的idCard和person =========================================");
idCardRepository.save(idCard);
personRepository.save(person);
System.out.println("=== 检查这个idCard确无person关联 =========================================");
assertThat(idCardRepository.getOne(idCard.getId()).getPerson()).isNull();
System.out.println("=== 关联赋值person后,再次保存 =========================================");
idCard.setPerson(person);
idCardRepository.save(idCard);
System.out.println("=== 再次检查这个idCard应有person对象内容 =========================================");
assertThat(idCardRepository.getOne(idCard.getId()).getPerson().getHeight()).isNotNull();
}
@Test
@Order(3)
@Disabled
@DisplayName("单表删除(IdCard)")
void testDelete1() {
IdCard idCard = idCardRepository.getOne();
System.out.println("=== 只删除IdCard(从待久态里删除) =========================================");
idCardRepository.delete(idCard);
assertAll(
() -> assertThat(idCardRepository.findById(idCard.getId()).orElse(null)).isNull(),
() -> assertThat(personRepository.findById(idCard.getPerson().getId()).orElse(null)).isNotNull()
);
}
@Test
@Order(4)
@Disabled
@DisplayName("单表删除(Person)")
void testDelete2() {
Person person = personRepository.getOne();
personRepository.delete(person);
assertAll("单表删除(Person)结果验证",
() -> assertThat(personRepository.findById(person.getId()).orElse(null)).isNotNull(),
() -> assertThat(idCardRepository.findById(person.getIdCard().getId()).orElse(null)).isNotNull()
);
}
@Test
@Order(5)
@Disabled
@DisplayName("级联更新(Person)")
void testCascadeUpdate1() {
Person person = personRepository.getOne();
person.setHairColor(hairColorArr[0]);
person.setHeight(null);
person.getIdCard().setName("Elsa");
System.out.println("=== 更新Person和级联更新 IdCard =========================================");
personRepository.save(person);
Person result = personRepository.getOne(person.getId());
assertAll("级联更新结果验证",
() -> assertThat(result.getHairColor()).isEqualTo(hairColorArr[0]),
() -> assertThat(result.getIdCard().getName()).isEqualTo("Elsa")
);
person = personRepository.getOne(1);
person.setIdCard(null);
person.setHairColor("yellow1");
System.out.println("=== 级联更新 IdCard =========================================");
personRepository.save(person);
assertThat(idCardRepository.findOne(Example.of(new IdCard()
.setPerson((Person) new Person()
.setId(person.getId())))).orElse(null))
.isNotNull();
}
@Test
@Order(6)
@Disabled
@DisplayName("级联更新(IdCard)")
void testCascadeUpdate2() {
System.out.println("IdCard是从表,不建议(或不允许)级联更新Person!");
}
@Test
@Order(7)
@Disabled
@DisplayName("JPA默认查询接口(by单Id)")
void testQuery1() {
Long personId = personRepository.getOne().getId();
System.out.println("=== 可正常获取到person的find方法 ========================");
assertThat(personRepository.findById(personId).orElse(null)).isNotNull();
System.out.println("=== 不能正常获取到person的find方法 ========================");
assertThat(personRepository.findById(-1L).orElse(null)).isNull();
System.out.println("=== 可正常获取到person的get方法 ========================");
assertThat(personRepository.getOne(personId)).isNotNull();
System.out.println("=== 不能正常获取到person的get方法 ========================");
assertThrows(EntityNotFoundException.class, () -> personRepository.getOne(-1L));
}
@Test
@Order(8)
@Disabled
@DisplayName("JPA默认查询接口(by多Id)")
void testQuery2() {
int count = 3;
Iterable<Long> ids = personRepository.getMany(count)
.stream()
.map(Person::getId)
.collect(Collectors.toList());
System.out.println("=== 可正常获取到多个person的findAll方法 ========================");
assertThat(personRepository.findAllById(ids).size()).isEqualTo(count);
assertThat(personRepository.findAllById(Arrays.asList(-1L, -2L, -3L))).isNotNull().isEmpty();
}
@Test
@Order(9)
@Disabled
@DisplayName("JPA默认查询接口(分页查询)")
void testQuery3() {
int pageNo = 0;
int pageSize = dataCount / 2;
Page<Person> page = personRepository.page(pageNo, pageSize);
System.out.println("=== 分页结果 ===========================");
System.out.println("=== page size: ===========================");
System.out.println(pageSize);
System.out.println("=== total rows: ===========================");
System.out.println(page.getTotalElements());
System.out.println("=== total page: ===========================");
System.out.println(page.getTotalPages());
System.out.println("=== contents: ===========================");
System.out.println(page.getContent());
}
@Test
@Order(10)
@Disabled
@DisplayName("JPA默认查询接口(分页 + 排序)")
void testQuery4() {
int pageNo = 0;
int pageSize = dataCount / 2;
Sort sort = Sort.by("height").ascending();
Page<Person> page = personRepository.findAll(PageRequest.of(pageNo, pageSize));
Page<Person> pageAndSort = personRepository.findAll(PageRequest.of(pageNo, pageSize, sort));
System.out.println("=== 分页 + 排序结果 ===========================");
System.out.println("=== 未排序数据: ===========================");
System.out.println(page.stream().map(Person::getHeight).collect(Collectors.toList()));
System.out.println("=== 已排序数据: ===========================");
System.out.println(pageAndSort.stream().map(Person::getHeight).collect(Collectors.toList()));
}
@Test
@Order(11)
@Disabled
@DisplayName("JPA默认查询接口(Example)")
void testQuery5() {
Person person = personRepository.getOne();
System.out.println("=== byId查询的另一种写法 ===========================");
assertThat(personRepository.findOne(Example.of((Person) new Person().setId(person.getId()))).orElse(null)).isNotNull();
System.out.println("=== byHeight查询 ===========================");
assertThat(personRepository.findAll(Example.of(new Person().setHeight(person.getHeight())))).isNotEmpty();
}
@Test
@Order(12)
@Disabled
@DisplayName("JPA默认查询接口(Others)")
void testQuery6() {
System.out.println("=== count查询 ===========================");
long count = personRepository.count(Example.of(new Person().setHairColor(hairColorArr[0])));
assertThat(count).isGreaterThan(0);
System.out.println("=== existsByExample查询 ===========================");
boolean exists = personRepository.exists(Example.of(new Person().setHairColor(hairColorArr[0])));
assertThat(exists).isTrue();
System.out.println("=== existsById查询 ===========================");
Person person = personRepository.getOne();
assertThat(personRepository.existsById(person.getId())).isTrue();
}
@Test
@Order(13)
@DisplayName("用方法命名规则查询")
void testQuery7() {
Person person = personRepository.getOne();
System.out.println("=== Query Methods命名规则find查询(可正常返回) ===========================");
assertThat(personRepository.findByWeightAndHeight(person.getWeight(), person.getHeight())
.orElse(null)).isNotNull();
System.out.println("=== Query Methods命名规则find查询(不可正常返回) ===========================");
assertThat(personRepository.findByWeightAndHeight(new BigDecimal(-1), new BigDecimal(-1))
.orElse(null)).isNull();
System.out.println("=== Query Methods命名规则count查询 ===========================");
assertThat(personRepository.countByHairColor(hairColorArr[0])).isNotNull();
}
@Test
@Order(14)
@Disabled
@DisplayName("方法级自定义JPQL")
void testQuery8() {
System.out.println("=== 方法级自定义JPQL ===========================");
assertThat(personRepository.findSomePersonByNameAtJPQL(nameArr[0])).isNotNull();
System.out.println("=== 方法级自定义native sql ===========================");
assertThat(personRepository.findSomePersonByNameAtNative(nameArr[0])).isNotNull();
}
@Test
@Order(15)
@Disabled
@DisplayName("Wrapper式查询")
void testQuery9() {
System.out.println("=== countAllPerson查询 ===========================");
CriteriaBuilder builder1 = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery1 = builder1.createQuery(Long.class);
Root<Person> root1 = criteriaQuery1.from(Person.class);
criteriaQuery1.select(builder1.count(root1));
Long count = entityManager.createQuery(criteriaQuery1).getSingleResult();
assertThat(count).isEqualTo(dataCount);
System.out.println("===================================================");
Person person = personRepository.getOne();
System.out.println("=== countAllPerson查询 ===========================");
CriteriaBuilder builder2 = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> criteriaQuery2 = builder2.createQuery(Person.class);
Root<Person> root2 = criteriaQuery2.from(Person.class);
criteriaQuery2.where(builder2.equal(root2.get("weight"), person.getWeight()));
assertThat(entityManager.createQuery(criteriaQuery2).getResultList()).isNotEmpty();
}
@Test
@Order(16)
@Disabled
@DisplayName("EntityManager手写JPQL")
void testQuery10() {
TypedQuery<Person> query = entityManager.createQuery("from Person p where p.hairColor = ?1", Person.class);
query.setParameter(1, hairColorArr[0]);
assertThat(query.getResultList()).isNotEmpty();
}
@Test
@Order(17)
@Disabled
@DisplayName("动态JPQL")
public void testDynamicQuery() {
}
private List<Person> initPersonData(int count) {
return Stream.iterate(0, i -> i + 1).limit(count)
.map(i -> new Person()
.setHeight(new BigDecimal(random.nextInt(200)))
.setWeight(new BigDecimal(random.nextInt(100)))
.setHairColor(hairColorArr[random.nextInt(hairColorArr.length)]))
.collect(Collectors.toList());
}
private List<IdCard> initIDCardData(Collection<Person> persons) {
return persons.stream()
.map(person -> {
IdCard idCard = new IdCard();
idCard.setName(nameArr[random.nextInt(nameArr.length)]);
idCard.setSex(sexArr[random.nextInt(sexArr.length)]);
idCard.setCardNo(StrUtil.uuid());
idCard.setPerson(person);
return idCard;
})
.collect(Collectors.toList());
}
@Autowired
private PersonRepository personRepository;
@Autowired
private IDCardRepository idCardRepository;
}