1、@DynamicInsert和@DynamicUpdate
这两个注解在一定程度上可以增加与数据库操作相关的速度,可以节省SQL语句的执行时间,提高程序的运行效率。
来看一下@DynamicInsert为false时的sql
insert into class_room (address, name) values (?, ?)
将@DynamicInsert设为true时
insert into class_room (name) values (?)
我实际中指示保存了name,第一个中将address也插入了,第二种只是插入name,看出区别了吧,@DynamicUpdate同理
必须注意DynamicUpdate实现更新必须保证在同一个session中,否则是无效果的。
2、主键生成
@GeneratedValue(strategy = GenerationType.IDENTITY) mysql自动增长
@GeneratedValue(strategy = GenerationType.AUTO) jpa默认的
详细请看以下2篇博客
https://blog.csdn.net/u012493207/article/details/50846616
https://www.cnblogs.com/OnlyCT/p/4375268.html
3、@OneToMany @ManyToOne @OneToOne
先说一样下级联(cascade)
CascadeType.PERSIST:级联新增(又称级联保存):对order对象保存时也对items里的对象也会保存。对应EntityManager的presist方法。
CascadeType.MERGE:级联合并(级联更新):若items属性修改了那么order对象保存时同时修改items里的对象。对应EntityManager的merge方法 。
CascadeType.REMOVE:级联删除:对order对象删除也对items里的对象也会删除。对应EntityManager的remove方法。
CascadeType.REFRESH:级联刷新:获取order对象里也同时也重新获取最新的items时的对象。对应EntityManager的refresh(object)方法有效。即会重新查询数据库里的最新数据。
CascadeType.ALL:以上四种都是。
个人觉得级联是单向的,不是双向的,意思就是说,我们在设置两个类的对象之间关系的时候,总是在一方设置的很具体,在另外一方设置一个mappedBy即可,但是如果想要两边都能删除的时候,或者在生成的时候,必须在两边都设置cascade=CascadeType.All才有效果
以学生和班级实现一对多和多对一的实现
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests2 {
@Autowired
private ClassRoomRepository classRoomRepository;
@Autowired
private StudentRepository studentRepository;
/**
* 通过学生保存
*/
@Test
public void saveStudent(){
Student student = new Student();
student.setName("aaa");
student.setAge(7);
student.setBirthday(new Date());
ClassRoom classRoom = classRoomRepository.findByName("教室01");
student.setClassRoom(classRoom);
studentRepository.save(student);
}
/**
* 通过班级保存
*/
@Test
public void saveClass(){
ClassRoom classRoom = new ClassRoom();
Set set = new HashSet();
Student student = new Student();
student.setName("mmm");
student.setAge(90);
student.setBirthday(new Date());
set.add(student);
classRoom.setName("class");
classRoom.setStudentSet(set);
classRoomRepository.save(classRoom);
}
}
发现通过学生保存信息是能保存全
而通过班级保存信息不全,班级id没有保存
要实现添加班级的同时还可以添加上学生,需要在bean中添加一个方法,也就是变相的通过student添加班级
@Test
public void saveClass(){
ClassRoom classRoom = new ClassRoom();
Student student = new Student();
student.setName("hhh");
student.setAge(78);
student.setBirthday(new Date());
classRoom.addStudent(student);
classRoom.setName("vbvb");
classRoomRepository.save(classRoom);
}
之前说过级联是单项的,举例说明下,目前上面的bean中只有ClassRoom中配置了CascadeType.ALL
@Test
public void deleteClass(){
ClassRoom classRoom = classRoomRepository.findByName("jjjj");
classRoomRepository.delete(classRoom);
}
这样是可以删除班级包括学生的(这是从班级入口)
@Test
public void deleteStudent(){
Student student = studentRepository.findByName("hhh");
studentRepository.delete(student);
}
从学生人入口,发现学生和班级都不会删除,此时需要配置student设置CascadeType.ALL
这样就都能删除了,此处只是个例子,要是实际业务,肯定不能这么设计,删除一个学生这个班级及这个班级的所有学生都给删除了
如果细心会发现,当student不舍自CascadeType.ALL,并且还是关系的维护方式,调用jpa的delete方法不能删除。
此时要么是使用JPQL强制删除,要是是解除学生与班级的关系,看代码
@Service
public class ClassRoomService {
@Autowired
private ClassRoomRepository classRoomRepository;
@Autowired
private StudentRepository studentRepository;
@Transactional
public void deleteStudent(){
Student student = studentRepository.findByName("yyy");
student.getClassRoom().getStudentSet().remove(student);
studentRepository.delete(student);
}
}
@Test
public void deleteStudent(){
classRoomService.deleteStudent();
}
使用OneToOne时,当第二次执行是,执行的是update操作。比如(A对象已经存储了B对象的关系,此时再次存储A对象和C对象的关系,C对象会更新掉B对象)如果使用的OneToMany则会执行insert操作,及A对象同时关联的了B和C对象。
4、@Formula
@Formula多数情况下用于做统计用途,必须注意的是
1)得用括号括起来,
2)关联表起别名
打印的sql
select classroom0_.id as id1_0_, classroom0_.address as address2_0_, classroom0_.name as name3_0_, (SELECT count(*) FROM student s WHERE s.class_id = classroom0_.id) as formula0_ from class_room classroom0_ where classroom0_.name=?
5、@DateTimeFormat和@JsonFormat
DateTimeFormat主要是入参,及前台传递的日期为字符串类型,后台接收的为日期类型,此时使用此注解,就行字符串到日期的转化。否则会直接报错。
在bean中添加注解
JsonFormat是用来给前台返回日期使用的,通过此注解返回自己想要的格式
未使用此注解返回的数据
使用注解后
需要注解的事,配置Dto文件,如图中,我返回的studentDto而不是student。需要使用ModelMapper转化
@RestController
public class StudentController {
@Autowired
private StudentService studentService;
private final static ModelMapper modelMapper = new ModelMapper();
@GetMapping("/student")
public StudentDto setStudentService() {
Student student = studentService.testStudent3();
return modelMapper.map(student,StudentDto.class);
}
@PostMapping("/save")
public void saveStudent(Student student){
studentService.saveStudent(student);
}
}
6、联合约束uniqueConstraints
@Table(name="lib_case_Collection",uniqueConstraints = {@UniqueConstraint(columnNames = {"case_id","user_id"})})
7、复合主键@IdClass
8、@PostPersist
@PrePersist @PostPersist @PreRemove @PostRemove @PreUpdate @PostUpdate @PostLoad 。它们标注在某个方法之前,没有任何参数。这些标注下的方法在实体的状态改变前后时进 行调用,相当于拦截器,参考图 13.6 实体状态转换关系图,pre 表示在状态切换前触发, post 则表示在切换后触发。 @PostLoad 事件在下列情况触发: 1. 执行 EntityManager.find( )或 getreference( )方法载入一个实体后; 2. 执行 JPA QL 查询过后; 3. EntityManager.refresh( )方法被调用后。 @PrePersist 和 @PostPersist 事 件 在 实 体 对 象 插 入 到 数 据 库 的 过 程 中 发 生 , @PrePersist 事件在调用 EntityManager.persist( )方法后立刻发生, 级联保存也会发生此事 件,此时的数据还没有真实插入进数据库。@PostPersist 事件在数据已经插入进数据库后 发生。 @PreUpdate 和 @PostUpdate 事件的触发由更新实体引起, @PreUpdate 事件在实 体的状态同步到数据库之前触发,此时的数据还没有真实更新到数据库。@PostUpdate 事件在实体的状态同步到数据库后触发,同步在事务提交时发生。 @PreRemove 和 @PostRemove 事件的触发由删除实体引起,@ PreRemove 事件在实体从数据库删除之前触发,即调用了 EntityManager.remove()方法或者级联删除
以PostPersist为例
保存实体后,立马更新,由于我设置的更新时将排序id等于生成的主键id,所有出现2个22
9、indexes
@Table(name = "em_exam_room_distribution",indexes = {@Index(columnList = "examId,roomId")})
有喜欢的朋友可以关注下头条号《老徐聊技术》