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,自行百度
双向一对一
表继承
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();