Spring Data JPA--注解使用(一)

一、基本实体注解

文档地址: https://www.w3cschool.cn/java/jpa-entitymanager.html

1. 自动更新实体创建时间和修改时间

@Data
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public class BaseEntity {
    /**
     * 将字段声明为protected ,千万不要使用private否则访问不到
     *
     * @CreatedDate 注解:创建时间字段(inster 自动设置)
     * @LastModifiedDate 注解:最后修改时间字段(update 自动设置)
     * @Temporal 定义时间类型 只能作用于Date类型与Calendar
     */
    @CreatedDate
    @Temporal(TemporalType.TIMESTAMP)
    @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss")
    @Column(columnDefinition = "datetime comment '创建时间'")
    protected Date createTime;

    @LastModifiedDate
    @Temporal(TemporalType.TIMESTAMP)
    @Column(columnDefinition = "datetime comment '更新时间'")
    protected Date updateTime;

    @Column(columnDefinition = "bit comment '逻辑删除'")
    protected Boolean deleted;
}

说明:
实体类必须添加:
@EntityListeners(AuditingEntityListener.class)
SpringBoot启动类必须加注解:
@EnableJpaAuditing
或者数据库字段中添加:
createTime : CURRENT_TIMESTAMP
modifyTime : CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

2. @MappedSuperclass 注解

继承关系共用字段。
这个注解表示在父类上面的,用来标识父类。
基于代码复用和模型分离的思想,在项目开发中使用JPA的@MappedSuperclass注解将实体类的多个属性分别封装到不同的非实体类中。例如,数据库表中都需要id来表示编号,id是这些映射实体类的通用的属性,交给jpa统一生成主键id编号,那么使用一个父类来封装这些通用属性,并用@MappedSuperclas标识。
注意:

1) 标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。
2) .标注为@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口。

3. @EntityListeners 实体监听器

对实体属性变化的跟踪,它提供了保存前,保存后,更新前,更新后,删除前,删除后等状态,就像是拦截器一样,可以在拦截方法里重写你的个性化逻辑。

1) 实体类监听器:
@Slf4j
public class TestEntityListeners {
    /**
     *  被@Prepersist注解的方法 ,完成save之前的操作。
     * @param entity
     */
    @PrePersist
    public void PrePersist(Object entity){
        log.info("开始保存--"+entity.toString());
    }
    /**
     *  被@Preupdate注解的方法 ,完成update之前的操作。
     * @param entity
     */
    @PreUpdate
    public void PreUpdate(Object entity){
        log.info("开始更新--"+entity.toString());
    }
    /**
     *  被@Postpersist注解的方法 ,完成save之后的操作。
     * @param entity
     */
    @PostPersist
    public void PostPersist(Object entity){
        log.info("结束保存--"+entity.toString());
    }
    /**
     *  被@Postupdate注解的方法 ,完成update之后的操作。
     * @param entity
     */
    @PostUpdate
    public void PostUpdate(Object entity){
        log.info("结束更新--"+entity.toString());
    }
}

2) 实体类定义:
@Data
@javax.persistence.Table(name="sys_role")
@Table(appliesTo="sys_role",comment = "角色表")    //此注解主要为了添加表注释
@Entity
@EntityListeners(value = {TestEntityListeners.class})
public class Role implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    @Column(nullable = false, columnDefinition = "varchar(63) comment '角色名称'")
    private String roleName;
    @Column( columnDefinition = "varchar(63) comment '角色描述'")
    private String description;
    @Column( columnDefinition = "bit comment '是否启用'")
    private Boolean enabled;
}

3) 测试
    @Test
    public void updateRole(){
        Role role=new Role();
        role.setId(4L);
        role.setRoleName("管理员");
        roleRepository.saveAndFlush(role);
    }
4) 结果:
Hibernate: select role0_.id as id1_1_0_, role0_.description as descript2_1_0_, role0_.enabled as enabled3_1_0_, role0_.role_name as role_nam4_1_0_ from sys_role role0_ where role0_.id=?
2019-05-31 09:28:29.242  INFO 15548 --- [           main] c.x.a.repository.TestEntityListeners     : 开始更新--Role(id=4, roleName=管理员, description=null, enabled=null)
Hibernate: update sys_role set description=?, enabled=?, role_name=? where id=?
2019-05-31 09:28:29.273  INFO 15548 --- [           main] c.x.a.repository.TestEntityListeners     : 结束更新--Role(id=4, roleName=管理员, description=null, enabled=null)

在方法中利用反射机制,可以实现对(创建日期,创建者,更新日期更新者,删除日期,删除者)等注解的字段的赋值操作。

3. @Embedded和@Embeddable注解

当一个实体类要在多个不同的实体类中进行使用,而本身又不需要独立生成一个数据库表,这就是需要使用@Embedded、@Embeddable
Address里加上了@Embeddable这个注解表示,Address这个类是一个可以被嵌套的类,而在Author类中,我们声明了一个Address类型的变量address,然后给它加上@Embedded注解,意思是我们要在Author类嵌套Address类。
当被引用的对象和主对象拥有相同的生命周期的时候才考虑使用@Embedded和@Embeddable。简单的说就是Author类存在的时候才会有Address类,当Author类不存在的时候,对应Author类所以诞生的Address类也应该是不存在的。通俗的说就是作者存在的时候才会有这个作者的地址。而不会是有一个地址存在着却没有人属于这个地址。而且内嵌类会和主类生成一张表,所以内嵌类对应主类应该是要唯一的和拥有相同生命周期的。
@Embedded 用来修饰 对象属性(引用类型 -- 类对象 -- 属性注解)
@Embeddable 用来修饰 类(类注解)
Address .java

@Data
public class Address implements Serializable{
    private String country;
    private String province;
    private String city;
    private String detail;
}

Person.java

@Entity
public class Person implements Serializable{
    @Id
    @GeneratedValue
    private Long id;
    @Column(nullable = false)
    private String name;
    @Column(nullable = false)
    private Integer age;
    private Address address;

}
1) 两个注解全不使用

那么两个实体类和上面的相同,Address属性字段会映射成tinyblob类型的字段,这是用来存储不超过255字符的二进制字符串的数据类型,显然我们通常不会这么使用。

2) 只使用@Embeddable

在Address实体类上加上@Embeddable注解,变成如下类:

@Embeddable
@Data
public class Address implements Serializable{
    private String country;
    private String province;
    private String city;
    private String detail;
}

而Person实体类不变,把Address中的字段映射成数据列嵌入到Person表中了。

@Embeddable
@Data
public class Address implements Serializable{
    @Column(nullable = false)
    private String country;
    @Column(length = 30)
    private String province;
    @Column(unique = true)
    private String city;
    @Column(length = 50)
    private String detail;
}

在Address中配置的属性全部成功映射到Person表中。

只使用@Embedded和只使用@Embeddable产生的效果是相同的。
覆盖@Embeddable类中字段的列属性:
这里就要使用另外的两个注解@AttributeOverrides和@AttributeOverride,这两个注解是用来覆盖@Embeddable类中字段的属性的。
@AttributeOverrides:里面只包含了@AttributeOverride类型数组;
@AttributeOverride:包含要覆盖的@Embeddable类中字段名name和新增的@Column字段的属性;
Person类:

@Data
@Entity
public class Person implements Serializable{
    private static final long serialVersionUID = 8849870114127659929L;

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private Integer age;

    @Embedded
    @AttributeOverrides({@AttributeOverride(name="country", column=@Column(name = "person_country", length = 25, nullable = false)),
                        @AttributeOverride(name="city", column = @Column(name = "person_city", length = 15))})
    private Address address;
}

Address类:

@Embeddable
@Data
public class Address implements Serializable{
    @Column(nullable = false)
    private String country;
    @Column(length = 30)
    private String province;
    @Column(unique = true)
    private String city;
    @Column(length = 50)
    private String detail;
}

4. @DynamicInsert和@DynamicUpdate

动态更新与插入:
@DynamicInsert属性:设置为true,设置为true,表示insert对象的时候,生成动态的insert语句,如果这个字段的值是null就不会加入到insert语句当中.默认false。
比如希望数据库插入日期或时间戳字段时,在对象字段为空的情况下,表字段能自动填写当前的sysdate。
@DynamicUpdate属性:设置为true,设置为true,表示update对象的时候,生成动态的update语句,如果这个字段的值是null就不会被加入到update语句中,默认false。
比如只想更新某个属性,但是却把整个对象的属性都更新了,这并不是我们希望的结果,我们希望的结果是:我更改了哪些字段,只要更新我修改的字段就够了。

1) 实体类:

默认值为:true
@DynamicUpdate(false)

@Data
@javax.persistence.Table(name="sys_role")
@Table(appliesTo="sys_role",comment = "角色表")    //此注解主要为了添加表注释
@Entity
@DynamicUpdate(true)
public class Role extends BaseEntity implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    @Column(nullable = false, columnDefinition = "varchar(63) comment '角色名称'")
    private String roleName;
    @Column( columnDefinition = "varchar(63) comment '角色描述'")
    private String description;
    @Column( columnDefinition = "bit comment '是否启用'")
    private Boolean enabled;
    @CreatedDate
    @Temporal(TemporalType.TIMESTAMP)
    @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss")
    @Column(columnDefinition = "datetime comment '创建时间'")
    protected Date createTime;

    @LastModifiedDate
    @Temporal(TemporalType.TIMESTAMP)
    @Column(columnDefinition = "datetime comment '更新时间'")
    protected Date updateTime;

    @Column(columnDefinition = "bit comment '逻辑删除'")
    protected Boolean deleted;
}
2) 测试:
@Test
public void updateRole(){
    Role role=new Role();
    role.setId(4L);
    role.setRoleName("管理员");
    roleRepository.saveAndFlush(role);
}
3) 结果:
Hibernate: select role0_.id as id1_1_0_, role0_.create_time as create_t2_1_0_, role0_.deleted as deleted3_1_0_, role0_.update_time as update_t4_1_0_, role0_.description as descript5_1_0_, role0_.enabled as enabled6_1_0_, role0_.role_name as role_nam7_1_0_ from sys_role role0_ where role0_.id=?
Hibernate: update sys_role set create_time=?, update_time=? where id=?

因为数据表中的create_time有值,所set后面会有create_time字段。
一定要注意,如果要保留该值,一定要传入该参数。
说明:
@DynamicUpdate 如果为空,则不会生成sql语句,不更新,如果内容不为空,没有设置值,则会生成语句,更新为空。

你可能感兴趣的:(Spring Data JPA--注解使用(一))