简介
JPA(Java Persistence API,Java持久化API),定义了对象关系映射(Object Relation Mapping,ORM)以及实体对象持久化的标准接口。
JPA是一套接口规范,JPA的实现主要包括 JBoss 的 Hibernate EntityManager、Oracle 捐献给 Eclipse 社区的 EclipseLink和Apache 的 OpenJPA 等。
ORM框架的出现使得我们能够以面向对象的方式来操作关系数据库,但是长久以来实现应用系统中的数据访问层依然是一件非常繁琐的事情,简单的查询也往往涉及大量重复代码。Spring Data JPA在则基于JPA进一步简化了数据访问层的实现,它提供了一种类似于声明式编程的方式,开发者只需要编写数据访问接口(称为
Repository
),Spring Data JPA就能基于接口中的方法命名自动地生成实现。
常用标签
- @Entity --声明为一个实体bean
- @Table (name= "promotion_info" ) --为实体bean映射指定表(表名="promotion_info)
- @Id --声明了该实体bean的标识属性
- @GeneratedValue --可以定义标识字段的生成策略.
- @Transient --将忽略这些字段和属性,不用持久化到数据库
- @Column (name= "promotion_remark" )--声明列(字段名= "promotion_total" ) 属性还包括(length= 200 等)
- @Temporal (TemporalType.TIMESTAMP)--声明时间格式
- @Lob --将属性映射成数据库支持的大对象类型
- @Enumerated --声明枚举
- @Version --声明添加对乐观锁定的支持
- @OneToOne --可以建立实体bean之间的一对一的关联
- @OneToMany --可以建立实体bean之间的一对多的关联
- @ManyToOne --可以建立实体bean之间的多对一的关联
- @ManyToMany --可以建立实体bean之间的多对多的关联
- @Formula --一个SQL表达式,这种属性是只读的,不在数据库生成属性(可以使用sum、average、max等)
- @MappedSuperclass --将超类的JPA注解传递给子类,使子类能够继承超类的JPA注解
- @Embedded --将几个字段组合成一个类,并作为整个Entity的一个属性(city,street属性映射为Address对象)
关联配置
@OneToOne
这里
BlogMetaInfo
包含了一个
User
类型的属性,并且通过
@OneToOne
标注。
@Entityclass BlogMetaInfo { @Id @GeneratedValue(strategy=GenerationType.AUTO) private long id; private String title; @OneToOne private User user;}@Entitypublic class User { @Id @GeneratedValue(strategy=GenerationType.AUTO) // ...}
如果希望能够从
User
直接引用到
BlogMataInfo
,则可以给
User
增加一个类型为
BlogMetaInfo
的属性,这样两个实体类就是一种双向关联关系了。
@Entitypublic class User { @Id @GeneratedValue(strategy=GenerationType.AUTO) @OneToOne(mappedBy = "user") private BlogMetaInfo blogMetaInfo; // ... }
@OneToMany 与 @ManyToOne
以
Blog
和
Comment
为例,他们之间的关系可以如下定义,如果生成DDL的话,会默认生成
Comment
表到
Blog
表的一个外键关联。
@Entityclass Comment { @ManyToOne private Blog blog; // ...}@Entityclass Blog { // ...}
如果在
Blog
中也定义一个
Comment
类型的成员变量,则两者形成了双向关系.
@Entityclass Comment { @ManyToOne private Blog blog; // ...}@Entityclass Blog { @OneToMany(mappedBy = "blog") private List<Comment> comments; // ...}
@ManyToMany
下面的代码定义了
Blog
到
Tag
的单向多对多关系,所有操作都设置为级联的。
@Entitypublic class Blog { @ManyToMany(cascade = CascadeType.ALL) private List<Tag> tags = new ArrayList<Tag>();}@Entitypublic class Tag {}
如果在
Tag
中定义一个
Blog
集合,则形成双向关系:
@Entitypublic class Tag { @ManyToMany(mappedBy = “tags”) private List<Blog> blogs = new ArrayList<Blog>();}
注意事项
- cascade属性表示级联操作策略:
- 不定义,则对关系表不会产生任何影响
- CascadeType.PERSIST:级联新建
- CascadeType.REMOVE:级联删除
- CascadeType.REFRESH: 级联刷新
- CascadeType.MERGE: 级联更新
- CascadeType.ALL:表示选择全部四项
- fetch属性表示实体的加载方式,有LAZY和EAGER两种取值,默认值为EAGER,@*ToMany,@Lob标注的, fetch默认为LAZY。
- optional属性表示关联的实体是否能够存在null值,默认为true,表示可以存在null值。如果为false,则要同时配合使用@JoinColumn标注。
- 设置了mappedBy属性的关系标注(各种@XXXToXX),表明当前类是关系的被维护方,而另外一个类则是关系维护方,只有关系维护方才能够操作两者的关系。
构建查询
1,
在实体类上使用@NamedQuery.
@NamedQuery(name = "UserModel.findByAge",query = "select o from UserModelo where o.age >= ?1")
然后在实现的DAO的Repository接口里面定义一个同名的方法,示例如下:
public List<UserModel> findByAge(int age);
2,
@Query来指定
@Query(value="select * from tbl_user where name like %?1" ,nativeQuery=true)public List<UserModel> findByUuidOrAge(String name);@Query(value="select o from UserModel o where o.name like %:nn")public List<UserModel> findByUuidOrAge(@Param("nn") String name);
3, 接口规范方法名查询
List<UserModel> findByName(String name);
构建更新
添加@Modifying即可,比如:
@Modifying @Query(value = "update sys_pri_privilege p set p.remark=:remark , p.pri_name = :priName where p.id = :id", nativeQuery = true) int setName(@Param("id") String id, @Param("priName")String priName, @Param("remark")String remark);
注意
- 方法的返回值应该是int,表示更新语句所影响的行数.
- 在调用的地方必须加事务,没有事务不能正常执行.
- 更新各个属性是用逗号分开.
事件及监听
通过在实体的方法上标注@PrePersist,@PostPersist等声明即可在事件发生时触发这些方法。
关键字
关键字 | 例子 | 对应的JPQL语句 |
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
TRUE | findByActiveTrue() | … where x.active = true |
FALSE | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
参考链接