JPA 对象关系映射

H2内嵌数据库的使用

SpringBoot可以自动的配置内嵌的H2、HSQL、Derby数据库。

步骤
1.引入相关的依赖
2.在配置文件进行相关的配置

spring.h2.console.enabled=true //开启web console功能 http://localhost:8080/h2-console/
spring.datasource.platform=h2 //数据库平台是H2,可选
spring.h2.console.path=/h2 //设置访问路径 localhost:port/h2

spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:./data/db 是相对路径
spring.datasource.password=
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect 使用的语言
spring.datasource.schema=
spring.datasource.data=

spring.jpa.show-sql = true //打印SQL语句
spring.jpa.hibernate.ddl-auto=update //三个可选值create , update , none

JPA提供的实体类注解

@Entity表明该类为实体类
@Table(name="table_name")实体类对应数据库中表的名字
@Id 表明该属性是主键
@GeneratedValue(strategy=)增长方式,声明增长方式的一种 ; @GeneratedValue(generator = "uuid2") @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")声明主键的增长方式的第二种方法
@Column(name = "id",length = 36) 每个属性都必须要的注释,声明该属性与数据库表中与之对应的字段

主键生成策略

    •      GenerationType.IDENTITY: 自增 如 mysql数据库底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增)
      
    •      GenerationType.GenerationType.SEQUENCE: 序列 如 oracle数据库底层数据库必须支持序列
      
    •     GenerationType.GenerationType.TABLE: jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增
      
    •     GenerationType.GenerationType.AUTO: 由程序自动的帮助我们选择主键生成策略
      

对象的三种状态
Managed:持久化受管对象,有id值,已经和Persistence Context建立了关联的对象。

Datached:游离态离线对象,有id值,但没有和Persistence Context建立关联的对象。

Removed:删除的对象,有id值,尚且和Persistence Context有关联,但是已经准备好从数据库中删除

状态名 作为java对象存在 在实体管理器中存在 在数据库存在

New yes no no

Managed yes yes yes

Detached no no no

Removed yes yes no

JPA操作数据库的步骤

1.配置文件,配置数据库 spring.datasource节点配置数据库驱动,url,用户密码; spring.jpa 节点配置spring,jpa.hibernate.ddl_auto,spring.jpa.hibernate.naming.strategy命名策略,默认即可,spring.jpa.properties.hibernate.dialect = hibernate的语言

2.实现接口,JpaRepository 封装了基本的CRUD ; JpaSpecificationExcutor 复杂的操作

JpaRepository 接口的方法 在接口的所以方法中,除了保存,查找操作无需要对象的主键外,其余操作都需要用到对象的主键,也就是说无论是删除操作,还是修改操作都需要在进行前标识对象的主键,表明你对那个对象操作。Object.SetId(Id)

save方法,保存对象时,事务会自动提交,所以执行语句后,数据库插入新的数据;但是 update,delete时,对象的更新不但需要主键,还需要手动提交事务,或者使用flush操作后,数据库才会同步操作,因为update,delete的对象操作的是一级缓存里面的对象。

接口的方法
findAll
count, delete, deleteAll, deleteAll, deleteById, existsById, findById, save
count, exists, findAll, findOne

此外还可以在接口定义更多的方法,可以搭配注解使用

@Query("SELECT p FROM Person p WHERE name LIKE %?1%")
Person findByName(String name);

@Query("SELECT p FROM Person p WHERE name LIKE %:name%")
Person findByName(@Param("name") String name);

@Modifying
@Query("UPDATE Person p SET p.name = :name WHERE p.id = :id")
void updatePersonName(@Param("id") Integer id, @Param("name") String name);

@Modifying注解来标识该方法执行的是更新或者删除操作

查询参数
命名查询 :param ; 位置参数 ?1

命名模糊查询
命名查询例子
public Customer findByCustName(String custName); 根据CustName进行查询

public List findByCustNameLike(String custName);根据CustName进行模糊查询

public Customer findByCustNameLikeAndCustIndustry(String custName,String custIndustry);多条件的模糊查询和精准查询

findBy --> from xxx(实体类),属性名称 --> where custName =
是对jpql查询更深一层的封装
findBy查询,根据后面的属性查询

对象关系:
一对一:@OneToOne()
一对多,多对一:@OneToMany
多对多:@ManyToMany

例子:
一对多 和多对一:
@OneToMany(targetEntity=)
@JoinColumn(name= referencedColumn=)外键

一对多的属性要注意设置拥有外键的实体类内,即一端;当然多端也是可以设置的。

多对多:
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "me_article_tag",中间表的名字
joinColumns = {@JoinColumn(name = "article_id")},中间表与主控方启用的外键
inverseJoinColumns = {@JoinColumn(name = "tag_id")}) 中间表与另外一方的启用的外键
private List tags;

如果关系不是单向的,是双向的,双方都可以维护这段关系,那么需要配置mappedBy属性,该属性的值可以为对象的类名称,小写。

mappedBy是OneToOne、OneToMany和ManyToMany这三种关联关系的属性。
mappedBy和JoinColumn/JoinTable总是互斥的,有mappedBy属性,那么就不该有JoinColumn/JoinTable注解。

fetch属性是 是否开启懒加载
cascade属性是 级联
CascadeType.REFRESH:级联刷新,当多个用户同时作操作一个实体,为了用户取到的数据是实时的,在用实体中的数据之前就可以调用一下refresh()方法
CascadeType.REMOVE:级联删除,当调用remove()方法删除Order实体时会先级联删除OrderItem的相关数据
CascadeType.MERGE:级联更新,当调用了Merge()方法,如果Order中的数据改变了会相应的更新OrderItem中的数据
CascadeType.ALL:包含以上所有级联属性。要谨慎使用。
CascadeType.PERSIST:级联保存,当调用了Persist() 方法,会级联保存相应的数据

spring与hibernate整合

1.创建EntityManagerFactory,加载配置文件,引用数据源
2.从工厂,获取EntityManager对象
3.实体类管理器,控制事务操作,manager.getTransaction()
4.执行增删改查,提交事务。

1,entityManager.persist(Object entity);  新增数据;
如果entity的主键不为空,而数据库没有该主键,会抛出异常;
如果entity的主键不为空,而数据库有该主键,且entity的其他字段与数据库不同,persist后不会更新数据库;

2、entityManager.find(Class entityClass, Object primaryKey);  根据主键查找数据;
如果主键格式不正确,会抛出illegalArgumentException异常;
如果主键在数据库未找到数据返回null;

3、entityManager.remove(Object entity);  删除数据;
只能将Managed状态的Entity实例删除,由此Entity实例状态变为Removed;

4、entityManager.merge(T entity);   将Detached状态的Entity实例转至Managed状态; 更新

5、entityManager.clear(); 将所有的Entity实例状态转至Detached状态;

6、entityManager.flush(); 将所有Managed状态的Entity实例同步到数据库;

7、entityManager.refresh(Object entity); 加载Entity实例后,数据库该条数据被修改,refresh该实例,能得到数据库最新的修改,覆盖原来的Entity实例;

posted @ 2020-10-01 17:36  lfcom  阅读(793)  评论(0编辑  收藏  举报