JPA实践

JPA介绍及实践

0.概念梳理

  • DAO: Data Access Object(数据访问对象),一种设计模式,通过映射应用程序对持久层的调用,DAO提供一些特定的数据操作,而无需暴露数据库细节。
  • ORM:Object Relational Mapping(对象关系映射),一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。
  • JPA: Java Persistence Api(Java 持久化 API),
  • Hibernate:Hibernate为Java提供了一个开源的对象关系映射框架。版本3.2及更高版本提供了JPA的实现。
  • Mybatis:是一个Java持久化框架,与其他的对象关系映射框架不同,MyBatis并没有将Java对象与数据库表关联起来,而是将Java方法与SQL语句关联。
  • Spring Data JPA:抽象存储库的实现是Java应用程序框架Spring的领域驱动设计的关键构建块。透明地支持所有可用的JPA实现,并支持CRUD操作以及方便地执行数据库查询。

1.Hibernate总体设计

hibernate.png

image.png

  • 高亮部分属于 JPA规范
  • raw jpa example

 

EntityManagerFactory sessionFactory = Persistence.createEntityManagerFactory( "org.hibernate.tutorial.jpa" );

EntityManager entityManager = sessionFactory.createEntityManager();
entityManager.getTransaction().begin();
entityManager.persist( new Event( "Our very first event!", new Date() ) );
entityManager.persist( new Event( "A follow up event", new Date() ) );
entityManager.getTransaction().commit();
entityManager.close();

persistence.xml

META-INF/persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
        version="2.0">
    <persistence-unit name="org.hibernate.tutorial.jpa">
        ...
    </persistence-unit>
</persistence>

2.association

owning side & inverse side(拥有方和被拥有方)

简单理解,关系拥有方在数据库中拥有指向被拥有方的外键.(如一对多关系中,学生拥有class_id指向班级,学生为拥有方) 

  • why 为什么要区分?不区分有什么问题?

没有指定owning side,Hibernate不知道该由谁来维护这个关系,会创建关联表(即双方都不维护而由第三方关联表来管理).

  • how 

使用@mappedBy 如下例,  mappedBy出现在inverse side

@OneToOne, @OneToMany, or @ManyToMany 拥有mappedBy属性(many-to-one为什么没有?)

public class Clazz {
    private int         id;
    private String      name;
  
    @OneToMany(mappedBy="clazz")
    private List<Student>  students;
}

使用@joinColumn,@joinTable 如下例,出现在owning side

public class Student {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "clazzId")
    private Clazz   clazz;
}

 

Unidirectional and Bidirectional (单向和双向)

单向例子

 

public class Student {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "clazzId")
    private Clazz   clazz;
}

public class Class {
    private int     id;
    private String  name;
}

双向例子

 

public class Student {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "clazzId")
    private Clazz   clazz;
}
public class Clazz {
    private int         id;
    private String      name;
    @OneToMany(mappedBy="clazz")
    private List<Student>  students;
}

区别:

两个方向都能获取到另一边(student可以获取class,class可以获取student),从而可以使用cascading.

 

四种关系

  • oneToMany (1...*)

 

public @interface OneToMany {
    Class targetEntity() default void.class;

    CascadeType[] cascade() default {};

    FetchType fetch() default FetchType.LAZY;

    String mappedBy() default "";

    boolean orphanRemoval() default false;
}

 

  • ManyToMany (*...*)

 

public @interface ManyToMany {
    Class targetEntity() default void.class;

    CascadeType[] cascade() default {};

    FetchType fetch() default FetchType.LAZY;

    String mappedBy() default "";
}
  • oneToOne (1...1(0))
public @interface OneToOne {
    Class targetEntity() default void.class;

    CascadeType[] cascade() default {};

    FetchType fetch() default FetchType.EAGER;

    boolean optional() default true;

    String mappedBy() default "";

    boolean orphanRemoval() default false;
}

 

  • manyToOne(* ... 1 (0))
public @interface ManyToOne {
    Class targetEntity() default void.class;

    CascadeType[] cascade() default {};

    FetchType fetch() default FetchType.EAGER;

    boolean optional() default true;
}

image.png

image.png

 

image.png

reference: https://www.slideshare.net/VladMihalcea/high-performance-hibernate-devoxx-france

 

3.DTO projections(DTO映射)

  • why:query不想取整个entity
  • how:

1.Class-Based Projections

@Query("select new package.DeadlineType(a.id, a.code) from ABDeadlineType a ")
    List<DeadlineType> findAllSummarizedBy();

dto+jpql

limit: 不支持嵌套,属性名必须相同

2.Interface-Based Projections

public interface DelegationApplyQueryRepository extends JpaRepository<DelegationApplyEntity, Long> {
    /**
     * 根据代收付申请编号和商户ID查询
     *
     * @param outReqNo
     * @param merchantId
     * @return
     */
    DelegationApplyView findByOutReqNoAndMerchantId(String outReqNo, Long merchantId);
}

public interface DelegationApplyView {
    String getOutReqNo();

    String getOrderNo();

    String getTermNo();
}

spring-data-jpa

支持嵌套,属性名不同时可以使用@value修饰,但使用后无法优化,即使用@value后会查询出所有columns

3. dynamic projections

同一个方法可以返回不同的结果.

/**
 * 根据代收付申请编号和商户ID查询
 *
 * @param outReqNo
 * @param merchantId
 * @param clazz
 * @return
 */
<T> T findByOutReqNoAndMerchantId(String outReqNo, Long merchantId, Class<T> clazz);

TIPS:

1.queryRepository与apprepository分离

2.使用interface-based projections 将映射接口放到model文件夹

image.png

3.view中的方法名应当严格按照entity属性来取,如需转换在DTO做

4.常用的repository建议添加 dynamic projections

5.使用native query+ view可以完成大部分业务需求查询

//使用 nativequery update的 例子
@Modifying//非查询需要标记
@Query(value = "update carloan_delegation_apply a " +
            "set a.status=:status,a.finish_time=:finishTime,a.remark=:content where a.out_req_no=:outReqNo", nativeQuery = true)
    int updateDelegationApply(@Param("outReqNo") String outReqNo, @Param("status") Integer status, @Param("finishTime") Date finishTime, @Param("content") String content);

4.查询

参考 git clone https://github.com/tuzhenxian/Jpa-demo

查看测试文件夹下的test case

  • jpa

jpql

criteria api(2.0)

  • hibernate

hql

criteria api(deprecated)

  • spring data

enhanced repository

JpaSpecificationExecutor 2.0  criteria api

@query //jpql

@query(nativequery=true,) //sql db-based

@Modifying

  • querydsl

 

5.常见问题

  • LazyInitializationException

造成原因:

fetchType为lazy时,不会直接获取相关属性,等到要获取的时候由于底层的session已经关闭导致异常

bad practice:

Open Session in View  anti-pattern

image.png

hibernate.enable_lazy_load_no_trans 

better way:

dto projection 

  • 在one-to-many和many-to-many的relation中,list增删更新时,发现数据库先执行全量删除再插入的操作.

错误的应用了relation,在one-to-many中需要指定index column,many-to-many使用set.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值