Spring Data JPA JPA 重要的是实战,这里仅对小部分知识点进行总结。
如何使用 JPA 在数据库中非持久化一个字段? 假如我们有下面一个类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Entity(name="USER") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "ID") private Long id; @Column(name="USER_NAME") private String userName; @Column(name="PASSWORD") private String password; private String secrect; }
如果我们想让secrect
这个字段不被持久化,也就是不被数据库存储怎么办?我们可以采用下面几种方法:
1 2 3 4 5 static String transient1; final String transient2 = "Satish" ; transient String transient3; @Transient String transient4;
一般使用后面两种方式比较多,我个人使用注解的方式比较多。
JPA 的审计功能是做什么的?有什么用? 审计功能主要是帮助我们记录数据库操作的具体行为比如某条记录是谁创建的、什么时间创建的、最后修改人是谁、最后修改时间是什么时候。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Data @AllArgsConstructor @NoArgsConstructor @MappedSuperclass @EntityListeners(value = AuditingEntityListener.class) public abstract class AbstractAuditBase { @CreatedDate @Column(updatable = false) @JsonIgnore private Instant createdAt; @LastModifiedDate @JsonIgnore private Instant updatedAt; @CreatedBy @Column(updatable = false) @JsonIgnore private String createdBy; @LastModifiedBy @JsonIgnore private String updatedBy; }
@CreatedDate
: 表示该字段为创建时间字段,在这个实体被 insert 的时候,会设置值
@CreatedBy
:表示该字段为创建人,在这个实体被 insert 的时候,会设置值
@LastModifiedDate
、@LastModifiedBy
同理。
实体之间的关联关系注解有哪些?
@OneToOne
: 一对一。
@ManyToMany
:多对多。
@OneToMany
: 一对多。
@ManyToOne
:多对一。
利用 @ManyToOne
和 @OneToMany
也可以表达多对多的关联关系。
SpringBoot JAP 创建表 @Entity
声明一个类对应一个数据库实体。
@Table
设置表名
1 2 3 4 5 6 7 8 9 10 @Entity @Table(name = "role") public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String description; 省略getter/setter...... }
创建主键 @Id
:声明一个字段为主键。
使用@Id
声明之后,我们还需要定义主键的生成策略。我们可以使用 @GeneratedValue
指定主键生成策略。
1.通过 @GeneratedValue
直接使用 JPA 内置提供的四种主键生成策略来指定主键生成策略。
1 2 3 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
JPA 使用枚举定义了 4 种常见的主键生成策略,如下:
Guide:枚举替代常量的一种用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public enum GenerationType { TABLE, SEQUENCE, IDENTITY, AUTO }
1 @GeneratedValue`注解默认使用的策略是`GenerationType.AUTO
1 2 3 4 5 public @interface GeneratedValue { GenerationType strategy () default AUTO; String generator () default "" ; }
一般使用 MySQL 数据库的话,使用GenerationType.IDENTITY
策略比较普遍一点(分布式系统的话需要另外考虑使用分布式 ID)。
通过 @GenericGenerator
声明一个主键策略,然后 @GeneratedValue
使用这个策略
1 2 3 4 @Id @GeneratedValue(generator = "IdentityIdGenerator") @GenericGenerator(name = "IdentityIdGenerator", strategy = "identity") private Long id;
等价于:
1 2 3 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
jpa 提供的主键生成策略有如下几种:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class DefaultIdentifierGeneratorFactory implements MutableIdentifierGeneratorFactory , Serializable, ServiceRegistryAwareService { @SuppressWarnings("deprecation") public DefaultIdentifierGeneratorFactory () { register( "uuid2" , UUIDGenerator.class ); register( "guid" , GUIDGenerator.class ); register( "uuid" , UUIDHexGenerator.class ); register( "uuid.hex" , UUIDHexGenerator.class ); register( "assigned" , Assigned.class ); register( "identity" , IdentityGenerator.class ); register( "select" , SelectGenerator.class ); register( "sequence" , SequenceStyleGenerator.class ); register( "seqhilo" , SequenceHiLoGenerator.class ); register( "increment" , IncrementGenerator.class ); register( "foreign" , ForeignGenerator.class ); register( "sequence-identity" , SequenceIdentityGenerator.class ); register( "enhanced-sequence" , SequenceStyleGenerator.class ); register( "enhanced-table" , TableGenerator.class ); } public void register (String strategy, Class generatorClass) { LOG.debugf( "Registering IdentifierGenerator strategy [%s] -> [%s]" , strategy, generatorClass.getName() ); final Class previous = generatorStrategyToClassNameMap.put( strategy, generatorClass ); if ( previous != null ) { LOG.debugf( " - overriding [%s]" , previous.getName() ); } } }
设置字段类型 @Column
声明字段。
示例:
设置属性 userName 对应的数据库字段名为 user_name,长度为 32,非空
1 2 @Column(name = "user_name", nullable = false, length=32) private String userName;
设置字段类型并且加默认值,这个还是挺常用的。
1 2 @Column(columnDefinition = "tinyint(1) default 1") private Boolean enabled;
指定不持久化特定字段 @Transient
:声明不需要与数据库映射的字段,在保存的时候不需要保存进数据库 。
如果我们想让secrect
这个字段不被持久化,可以使用 @Transient
关键字声明。
1 2 3 4 5 6 7 8 @Entity(name="USER") public class User { ...... @Transient private String secrect; }
除了 @Transient
关键字声明, 还可以采用下面几种方法:
1 2 3 static String secrect; final String secrect = "Satish" ; transient String secrect;
一般使用注解的方式比较多
声明大字段 @Lob
:声明某个字段为大字段。
1 2 @Lob private String content;
更详细的声明:
1 2 3 4 5 6 @Lob @Basic(fetch = FetchType.EAGER) @Column(name = "content", columnDefinition = "LONGTEXT NOT NULL") private String content;
创建枚举类型的字段 可以使用枚举类型的字段,不过枚举字段要用@Enumerated
注解修饰。
1 2 3 4 5 6 7 8 9 public enum Gender { MALE("男性" ), FEMALE("女性" ); private String value; Gender(String str){ value=str; } }
1 2 3 4 5 6 7 8 9 10 11 12 @Entity @Table(name = "role") public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String description; @Enumerated(EnumType.STRING) private Gender gender; 省略getter/setter...... }
数据库里面对应存储的是 MALE/FEMALE。
增加审计功能 只要继承了 AbstractAuditBase
的类都会默认加上下面四个字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Data @AllArgsConstructor @NoArgsConstructor @MappedSuperclass @EntityListeners(value = AuditingEntityListener.class) public abstract class AbstractAuditBase { @CreatedDate @Column(updatable = false) @JsonIgnore private Instant createdAt; @LastModifiedDate @JsonIgnore private Instant updatedAt; @CreatedBy @Column(updatable = false) @JsonIgnore private String createdBy; @LastModifiedBy @JsonIgnore private String updatedBy; }
我们对应的审计功能对应地配置类可能是下面这样的(Spring Security 项目):
1 2 3 4 5 6 7 8 9 10 11 @Configuration @EnableJpaAuditing public class AuditSecurityConfiguration { @Bean AuditorAware<String> auditorAware () { return () -> Optional.ofNullable(SecurityContextHolder.getContext()) .map(SecurityContext::getAuthentication) .filter(Authentication::isAuthenticated) .map(Authentication::getName); } }
简单介绍一下上面涉及到的一些注解:
@CreatedDate
: 表示该字段为创建时间字段,在这个实体被 insert 的时候,会设置值
@CreatedBy
:表示该字段为创建人,在这个实体被 insert 的时候,会设置值
@LastModifiedDate
、@LastModifiedBy
同理。
@EnableJpaAuditing
:开启 JPA 审计功能。
删除/修改数据 @Modifying
注解提示 JPA 该操作是修改操作,注意还要配合@Transactional
注解使用。
1 2 3 4 5 6 7 @Repository public interface UserRepository extends JpaRepository <User, Integer> { @Modifying @Transactional(rollbackFor = Exception.class) void deleteByUserName (String userName) ; }
关联关系
@OneToOne
声明一对一关系
@OneToMany
声明一对多关系
@ManyToOne
声明多对一关系
@ManyToMany
声明多对多关