1. 简介
JPA(Java Persistence API):java 持久化 API
2. 常用注解
2.1 @Entity
标注当前类为实体类,将映射到指定的数据库表中
@Entity public class Users { }
登录后复制
2.2 @Table
一般与 @Entity 注解一起使用,如果数据库表名和类名一致时不使用 @Table 注解也是可以的,
否则需要使用 @Table 注解来指定表名
@Entity @Table(name="t_users") public class Users { }
登录后复制
2.3 @Id 、@GeneratedValue、@SequenceGenerator、@Column
2.3.1 @Id
用于将实体类的属性映射为主键
2.3.2 @GeneratedValue
指定主键生成策略
package javax.persistence; /** * 策略类型 */ public enum GenerationType { /** * 通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植 */ TABLE, /** * 通过序列产生主键,通过 @SequenceGenerator 注解指定序列名 * MySql 不支持这种方式 * Oracle 支持 */ SEQUENCE, /** * 采用数据库 ID自增长的方式来自增主键字段 * Oracle 不支持这种方式; */ IDENTITY, /** * 缺省值,JPA 根据数据库自动选择 */ AUTO; private GenerationType() { } }
登录后复制
2.3.3 @SequenceGenerator
2.3.4 @Column
当实体类属性名和数据库列名不一致时必须要使用此注解
@Entity @Table(name="t_users") public class Users { @Id @Column(name = "user_id") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq") @SequenceGenerator(name = "user_seq", sequenceName = "user_seq") private Long userId; }
登录后复制
2.4 @Transient
表示当前属性无需映射到数据库中
2.5 @Temproal
主要针对 Date 类型的属性使用,可以通过该注解指定时间的精度
@Entity @Table(name="t_users") public class Users { @Temporal(TemporalType.DATE) private Date time1; @Temporal(TemporalType.TIME) private Date time2; @Temporal(TemporalType.TIMESTAMP) private Date time3; }
登录后复制
3. EntityManagerFactory
4. EntityManager 实体的四种状态
新建状态: 新创建还未拥有持久性主键持久化状态: 已经拥有持久性主键并和持久化建立了上下文关系游离状态: 拥有持久性主键,但没有和持久化建立上下文关系删除状态: 拥有持久性主键,并且和持久化建立了上下文关系,但是从数据库中删除了
4.1 find(Class entityClass, Object primaryKey)
find 如果没有查询到会返回 null
4.2 getReference(Class entityClass, Object primaryKey)
getReference 如果没有查询到不会返回 null , 会抛出 EntityNotFoundException
注意:使用此方法可能出现懒加载异常的情况,也就是我们还没有去获取实体类中的属性值,结果 EntityManager 就已经被关闭了
4.3 persist
注意:执行方法时传入的对象不能为主键设置值会抛出异常
4.4 remove
注意:该方法只能删除持久化对象,而不能删除游离状态的对象(hibernate 可以)
/** * 删除游离态(失败) */ public void testRemove(){ Users user = new Users(); Users.setUserId(1); entityManager.remove(customer); } /** * 删除持久化状态(成功) */ public void testRemove(){ Users user = entityManager.find(Users.class, 1); entityManager.remove(user); }
登录后复制
4.5 merge(T entity)
// 新建状态 public void testMerge (){ Users user= new Users(); // 省略一系列的set // user.set..... Users newUser = entityManager.merge(user); // user.getUserId() == null ==> true // newUser.getUserId() == null ==> false }
登录后复制
4.6 flush()
将上下文中所有未保存的实体保存到数据库中
4.6 refresh()
刷新所有实体的属性值
5. EntityTransaction
5.1 begin
5.2 commit
5.3 rollback
6. 映射关系
6.1 单向一对多
/** * 订单和用户是多对一的关系 */ @Entity @Table(name="t_order") public class Order { // lazy为懒加载,默认为eager立即查询 @ManyToOne(fetch=FetchType.Lazy) // @JoinColumn标注字段是一个类,userId为该类的主键 @JoinColumn(name="user_id") private Users user; }
登录后复制
登录后复制
6.2 单向多对一
/** * 订单和用户是多对一的关系 */ @Entity @Table(name="t_order") public class Order { // lazy为懒加载,默认为eager立即查询 @ManyToOne(fetch=FetchType.Lazy) // @JoinColumn标注字段是一个类,userId为该类的主键 @JoinColumn(name="user_id") private Users user; }
登录后复制
登录后复制
6.3 双向多对一
/** * 用户和订单是一对多的关系 */ @Entity @Table(name="t_users") public class User { // 如果两侧都要描述关联关系的话,维护关联关系的任务要交给多的一方 // 使用 @OneToMany 了 mappedBy 的代表不维护关联关系,也就是不会产生额外的update语句 // @OneToMany 和 @JoinColumn 不能同时使用会报错 @OneToMany(mappedBy="user") private Set<Orders> orders; } /** * 订单和用户是多对一的关系 */ @Entity @Table(name="t_orders") public class Order { // lazy为懒加载,默认为eager立即查询 @ManyToOne(fetch=FetchType.Lazy) // @JoinColumn标注字段是一个类,userId为该类的主键 @JoinColumn(name="user_id") private Users user; }
登录后复制
6.4 双向一对一
/** * 学校 */ @Entity @Table(name="t_school") public class School { // 默认为eager立即查询 @OneToOne // 添加唯一约束 @JoinColumn(name="school_master_id", unique = true) private SchoolMaster schoolMaster; } /** * 校长 */ @Entity @Table(name="t_school_master") public class SchoolMaster { // 不维护关联关系要使用 mappedBy @OneToOne(mappedBy="schoolMaster") private School school; }
登录后复制
6.5 双向多对多
/** * 学生 */ @Entity @Table(name="t_student") public class Student { @GeneratedValue @Id private Long student_id; // 要使用 set 集合接收 // 默认为lazy懒加载 @ManyToMany // name 为中间表的表名 @JoinTable(name="t_student_choose_course", // name 为与中间表与当前表所关联的字段的名称,referencedColumnName 为当前表中与中间表关联的字段的名称 joinColumns={@JoinColumn(name="student_id", referencedColumnName="student_id")}, // name 为与中间表与多对多另一方表所关联的字段的名称,referencedColumnName 为多对多另一方与中间表关联的字段的名称 inverseJoinColumns={@JoinColumn(name="course_id", referencedColumnName="course_id")}) private Set<Course> courses; } /** * 课程 */ @Entity @Table(name="t_course") public class Course { @GeneratedValue @Id private Long course_id; // 要使用 set 集合接收 // 默认为lazy懒加载 @ManyToMany(mappedBy="courses") private Set<Student> students; }
登录后复制
7. 二级缓存
8. JPQL
8.1 查询接口
8.1.1 createQuery
public void testCreateQuery(){ // 这里我们使用了一个 new Student,因为我们是查询 Student 中的部分属性,如果不适用 new Student 查询返回的结果就不是 Student 类型而是一个 Object[] 类型的 List // 也可以在实体类中创建对应的构造器,然后使用如下这种 new Student 的方式,来把返回结果封装为Student 对象 String jpql = "SELECT new Student(s.name, s.age) FROM t_student s WHERE s.student_id > ?"; // setParameter 时下标是从1开始的 List result = entityManager.createQuery(jpql).setParameter(1, 1).getResultList(); }
登录后复制
8.1.2 createNamedQuery
@NamedQuery(name="testNamedQuery", query="select * from t_student WHERE student_id = ?") @Entity @Table(name="t_student") public class Student { @GeneratedValue @Id private Long student_id; @Column private String name; @Column private int age; }
登录后复制
public void testCreateNamedQuery(){ Query query = entityManager.createNamedQuery("testNamedQuery").setParameter(1, 3); Student student = (Student) query.getSingleResult(); }
登录后复制
8.1.3 createNativeQuery
public void testCreateNativeQuery(){ // 本地sql的意思是只能在数据库中执行的sql语句 String sql = "SELECT age FROM t_student WHERE student_id = ?"; Query query = entityManager.createNativeQuery(sql).setParameter(1, 18); Object result = query.getSingleResult(); }
登录后复制
8.2 关联查询
注意: 下面 sql 中的重点就是要加上 fetch u.orders,表示要查询出用户所关联的所有订单
public void testLeftOuterJoinFetch(){ String jpql = "FROM t_users u LEFT OUTER JOIN FETCH u.orders WHERE u.id = ?"; Users user = (Users) entityManager.createQuery(jpql).setParameter(1, 123).getSingleResult(); }
登录后复制
以上就是SpringBoot JPA常用注解如何使用的详细内容,更多请关注Work网其它相关文章!