SpringData&JPA学习笔记

jpa:Java Persistence api,是一种规范,hibernate是它的一种实现。
jpql/hql:查询语言,jpql是hql的子集。
1、基础用法以及注解解释
@MappedSuperclass
1.标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。
2.标注为@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口。

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {
    @Getter
    @Setter
    @CreatedDate
    @Column(columnDefinition="datetime not null comment '创建时间'")
    private LocalDateTime createdAt;
    @Getter
    @Setter
    @LastModifiedDate
    @Column(columnDefinition="datetime not null comment '更新时间'")
    private LocalDateTime modifiedAt;
}

@EntityListeners(AuditingEntityListener.class) 注解用于监听实体类,在save、update之后的状态。
记得在Application启动类上加@EnableJpaAuditing, 要不然@CreatedDate、@CreatedBy、@LastModifiedDate、@LastModifiedBy不生效。
但是CreatedBy和LastModifiedBy并没有赋值,因为需要实现AuditorAware接口来返回你需要插入的值。

@Configuration
public class UserAuditorConfig implements AuditorAware<String> {
    @Override
    public Optional<String> getCurrentAuditor() {
        //获取用户信息代码省略..............
        return Optional.of(SpringSecurityHolder.currentUserName());
    }
}

表配置

@Entity
@Table(name = "t_customer")
@org.hibernate.annotations.Table(appliesTo = "t_customer", comment = "顾客表")
@Getter
@Setter
public class Customer extends BaseEntity implements Serializable {
    //@TableGenerator() 配置table生成主键,@SequenceGenerator()。自己百度学。
    @GeneratedValue(strategy = GenerationType.IDENTITY) //主键自增
    @Id
    @Column(columnDefinition="bigint unsigned COMMENT '主键'")//列定义
    private Long id;

    @Column(columnDefinition="varchar(32) COMMENT '名称'")
    private String lastName;

    @Column(columnDefinition="int COMMENT '年龄'")
    private Integer age;
}

@Basic 基本注解 默认都有,fetch加载策略, optional是否允许为空。
@Transient 非表字段使用之。
@Tempora(TemporalType.TIMESTAMP) 用在Date类型的属性,指定日期格式(带不带时分秒)。

表生成主键策略(了解即可)

CREATE TABLE `id_generators` (
  `id` int(10) NOT NULL,
  `pk_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `pk_value` int(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `jpa`.`id_generators`(`id`, `pk_name`, `pk_value`) VALUES (1, 'customer_id', 1);
@TableGenerator(name = "id_generator",
        table = "id_generators",//生成主键的表
        pkColumnName = "pk_name",
        pkColumnValue = "customer_id",
        valueColumnName = "pk_value",
        allocationSize = 1)//allocationSize 表示每次主键值增加的大小
@GeneratedValue(strategy = GenerationType.TABLE, generator = "id_generator")
@Id
@Column(columnDefinition = "bigint unsigned COMMENT '主键'")
private Long id;

表关系

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {

}
@Repository
public interface OrderRepository extends JpaRepository<Order, Long>, JpaSpecificationExecutor<Order> {

}

单向多对一

@Entity
@Table(name = "t_order")
@org.hibernate.annotations.Table(appliesTo = "t_order", comment = "订单表")
@Getter
@Setter
public class Order extends BaseEntity implements Serializable {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(columnDefinition="bigint unsigned COMMENT '主键'")
    private Long id;

    @Column(columnDefinition="varchar(32) COMMENT '订单名称'")
    private String orderName;

    /**
     * 多对一  foreignKey配置不生成外键
     */
    @ManyToOne
    @JoinColumn(name = "customer_id", foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
    private Customer customer;
}
一定先保存一的一端,再保存多的一端,否则会多发更新sql语句。 fetch配置懒加载。
删除的时候,删除一的一方会报错。因为有外键约束。select @@foreign_key_checks;

一定先保存一的一端,否则可能报错
单向一对n

@Entity
@Table(name = "t_order")
@org.hibernate.annotations.Table(appliesTo = "t_order", comment = "订单表")
@Date
public class Order extends BaseEntity implements Serializable {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(columnDefinition="bigint unsigned COMMENT '主键'")
    private Long id;

    @Column(columnDefinition="varchar(32) COMMENT '订单名称'")
    private String orderName;
}

@Entity
@Table(name = "t_customer")
@org.hibernate.annotations.Table(appliesTo = "t_customer", comment = "顾客")
@Getter
@Setter
public class Customer extends BaseEntity implements Serializable {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(columnDefinition = "bigint unsigned COMMENT '主键'")
    private Long id;

    @Column(columnDefinition = "varchar(32) COMMENT '名称'")
    private String lastName;

    @Column(columnDefinition = "int COMMENT '年龄'")
    private Integer age;
    /**
     * 单向1-n执行保存时,一定会多出 update语句,因为n的一方保存时,不会插入时不会插入外键
     * 默认懒加载模式,OneToMany 中的fetch属性 修改
     * 删除时,如果删除一的一端,会置空Customer(多的一方)表中的customer_id,再删。
     * 配置级联删除 @OneToMany(cascade = {CascadeType.REMOVE})
     */
    @OneToMany(cascade = {CascadeType.REMOVE})
    @JoinColumn(name = "customer_id", foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
    private Set<Order> orders;
    //记得用idea 生成 equals hashcode toString 不包含orders字段。
}

双向1-n

@Entity
@Table(name = "t_order")
@org.hibernate.annotations.Table(appliesTo = "t_order", comment = "订单表")
@Getter
@Setter
public class Order extends BaseEntity implements Serializable {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(columnDefinition = "bigint unsigned COMMENT '主键'")
    private Long id;

    @Column(columnDefinition = "varchar(32) COMMENT '订单名称'")
    private String orderName;

    @ManyToOne
    @JoinColumn(name = "customer_id", foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
    private Customer customer;

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Order order = (Order) o;
        return Objects.equals(id, order.id) && Objects.equals(orderName, order.orderName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, orderName);
    }
}

@Entity
@Table(name = "t_customer")
@org.hibernate.annotations.Table(appliesTo = "t_customer", comment = "顾客")
@Getter
@Setter
public class Customer extends BaseEntity implements Serializable {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(columnDefinition = "bigint unsigned COMMENT '主键'")
    private Long id;

    @Column(columnDefinition = "varchar(32) COMMENT '名称'")
    private String lastName;

    @Column(columnDefinition = "int COMMENT '年龄'")
    private Integer age;

    /**
     * mappedBy 由多的一方维护关联关系,mappedBy 配置 customer维护
     * OneToMany配置了mappedBy 就不能配置@JoinColum了,注意此时order表会生成外键
     */
    @OneToMany(cascade = {CascadeType.REMOVE}, mappedBy = "customer")
    private Set<Order> orders;

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Customer customer = (Customer) o;
        return Objects.equals(id, customer.id) && Objects.equals(lastName, customer.lastName) && Objects.equals(age, customer.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, lastName, age);
    }
}

单向一对n,双向一对n,保存时,如果报错object references an unsaved transient instance - save the transient instance before flushing…是正常的
可配置cascade = CascadeType.PERSIST,自行百度

单向向一对一

@Table(name = "t_manager")
@Entity
@org.hibernate.annotations.Table(appliesTo = "t_manager", comment = "部门")
@Getter
@Setter
public class Manager extends BaseEntity implements Serializable {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id@Column(columnDefinition = "bigint unsigned COMMENT '主键'")
    private Long id;

    @Column(columnDefinition = "varchar(32) COMMENT '经理名称'")
    private String mgrName;
}

@Table(name = "t_department")
@Entity
@org.hibernate.annotations.Table(appliesTo = "t_department", comment = "部门")
@Getter
@Setter
public class Department extends BaseEntity implements Serializable {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id@Column(columnDefinition = "bigint unsigned COMMENT '主键'")
    private Long id;

    @Column(columnDefinition = "varchar(32) COMMENT '部门名称'")
    private String departmentName;
    /**
     * 先保存不维护 关联关系的一方。unique = true唯一索引,可去掉。
     * 查询部门,管理员懒加载,查询管理员 不会去查部门。
     */
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "mgr_id", unique = true, foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
    private Manager mgr;
}

双向向一对一 不推荐使用

Manager 类多 一个属性
@OneToOne(mappedBy = "mgr", fetch = FetchType.LAZY)
private Department department;

双向向多对多 查询一方时默认懒加载

@Entity
@Table(name = "t_item")
@org.hibernate.annotations.Table(appliesTo = "t_item", comment = "商品")
@Getter
@Setter
public class Item implements Serializable {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(columnDefinition = "bigint unsigned COMMENT '主键'")
    private Long id;

    @Column(columnDefinition = "varchar(32) COMMENT '商品名称'")
    private String itemName;

    @JoinTable(name = "t_item_category",
            joinColumns = {@JoinColumn(name = "item_id", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "category_id", referencedColumnName = "id")},
            foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT),
            inverseForeignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
    @ManyToMany
    private Set<Category> categories;
}

@Entity
@Table(name = "t_category")
@org.hibernate.annotations.Table(appliesTo = "t_category", comment = "类别")
@Getter
@Setter
public class Category implements Serializable {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(columnDefinition = "bigint unsigned COMMENT '主键'")
    private Long id;

    @Column(columnDefinition = "varchar(32) COMMENT '类型名称'")
    private String categoryName;
//  @ManyToMany(mappedBy = "categories")
//  private Set<Item> items;
}

Specification 连表查询要和上面的关系注解配合使用。
表继承

父表
@PrimaryKeyJoinColumn(foreignKey = @ForeignKey(name = "none"))
@Inheritance(strategy = InheritanceType.JOINED)

2、常用方法
Hibernate实体对象四大状态
瞬时态(临时态):由 new 操作符创建,且尚未与Hibernate Session 关联的对象被认定为瞬时的。瞬时对象不会被持久化到数据库中,也不会被赋予持久化标识。
持久态:持久的实例可能是刚被保存的,或刚被加载的。它存在于相关联的Session作用范围内。在flush()缓存时或提交事务时,会根据对象属性变化自动更新数据库。
游离态(托管态):有持久化主键,持久对象关联的Session被关闭后,对象就变为脱管的。脱管态不能直接持久化。
删除态:调用Session的delete方法之后,对象就变成删除态,有持久化主键,但从数据库中删除了。

jap

获取EntityManager对象
@Resource
private EntityManagerFactory entityManagerFactory;
//类似与hibernate的 sessionFactory
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
//处理业务代码
transaction.commit();
entityManager.close();
//find方法 类似hibernate中Session的get方法
Customer employee = entityManager.find(Customer.class, 1);
//getReference方法 类似与hibernate Session的load方法,懒加载。使用对象的时候再查询。
//如果使用使用前提交事务并且关闭entityManager,会有异常。
Customer reference = entityManager.getReference(Customer.class, 1);
//persist持久化 类似与hibernate Session的save方法,对象游离态变为持久态。
//区别是若对象有id,persist会抛异常,无法插入,save方法不会。
entityManager.persist(employee);
//remove 类似与hibernate Session的 delete方法,区别只能移除持久化对象,而hibernate的delete方法可以移除临时对象。
Customer customer = entityManager.find(Customer.class, 3);
entityManager.remove(customer);
//merge 类似与hibernate Session的saveOrUpdate方法,
entityManager.merge(customer2);
传入临时对象,把临时对象复制到新对象,再把新对象持久化,只有customer1有id。
Customer customer = new Customer();
customer.setLastName("小舞3");
Customer customer1 = entityManager.merge(customer);
System.out.println("employee:" + customer.getId()); //无id
System.out.println("employee1:" + customer1.getId());//有id
//传入游离对象(有主键id)
//1、若EntityManager缓存和数据库都无此对象,把游离对象复制到新对象,再把新对象持久化。customer id是1000,customer1 id真正的主键id。
//2、若EntityManager缓存无此对象,数据库有此对象,JPA查询对应的记录,返回此记录对象2,copy游离对象属性复制到对象2,对象2执行update。
//3、若EntityManager缓存有此对象,JPA把游离对象属性复制到缓存对象,对缓存对象update。hibernate不满足第三点。

entityManager.flush();内存中数据和数据库数据保持一致
//即可能发sql语句(持久化对象被修改时),事务提交前默认flush。
entityManager.refresh(customer);重新获取一下数据库里面的对象
contains(Object entity):判断一个实例是否属于当前持久上下文环境管理的实体。
isOpen():判断当前的实体管理器是否是打开状态。
close():关闭实体管理器。
//关闭后,若调用实体管理器实例的方法或其派生的查询对象的方法都将抛出IllegalStateException
//不过,当与实体管理器关联的事务处于活动状态时调,用close方法后持久上下文将仍处于被管理状态,直到事务完成。

hibernate

获取SessionFactory
@Resource
private EntityManagerFactory entityManagerFactory;
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
//处理业务代码
transaction.commit();
session.close();
sessionFactory.close();
//原始 Connection 调用存储过程
session.doWork(new Work() {
   @Override
   public void execute(Connection connection) throws SQLException {
       CallableStatement callableStatement = connection.prepareCall("(call procedureA())");
       callableStatement.executeUpdate();
   }
});

乐观锁

@Version
private Long version;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值