版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011870280/article/details/85678155
今天发现fetch = FetchType.LAZY这个设置无效,在查询和新增都会查一遍。
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "loan_req_no", referencedColumnName = "loanReqNo", insertable = false, updatable = false, foreignKey = @ForeignKey(name = "null", value = ConstraintMode.NO_CONSTRAINT))
private LoanOrderEntity loanOrderEntity;
诸多办法尝试无果后,决定深入源码查看原因,以下是SimpleJpaRepository保存实体的源码:
@Transactional
public <S extends T> S save(S entity) {
判断是否是新实体
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
然后isNew判断如果实体不是基本类型,那么ID为null就是新实体
public boolean isNew(T entity) {
获取实体ID
ID id = getId(entity);
Class<ID> idType = getIdType();
判断ID不是基本类型
if (!idType.isPrimitive()) {
return id == null;
}
if (id instanceof Number) {
return ((Number) id).longValue() == 0L;
}
throw new IllegalArgumentException(String.format("Unsupported primitive id type %s!", idType));
}
我这实体是修改,会调用EntityManager的merge方法修改实体,其中判断实体状态
switch ( entityState ) {
case DETACHED:
entityIsDetached( event, copyCache );
break;
case TRANSIENT:
entityIsTransient( event, copyCache );
break;
case PERSISTENT:
entityIsPersistent( event, copyCache );
break;
default: //DELETED
throw new ObjectDeletedException(
"deleted instance passed to merge",
null,
getLoggableName( event.getEntityName(), entity )
);
我的实体是DETACHED(游离态),在entityIsDetached方法中的先用session.get方法查出实体,在这把实体所有关联的ManyToOne对象都查出来了,就算设置了fetch=FetchType=LAZY也毫无效果,如果依赖的对象多的话,这样是很不效率的
...
final Object result = source.get( entityName, clonedIdentifier );
source.getLoadQueryInfluencers().setInternalFetchProfile( previousFetchProfile );
if ( result == null ) {
entityIsTransient( event, copyCache );
}else {
((MergeContext) copyCache).put( entity, result, true ); //before cascade!
final Object target = source.getPersistenceContext().unproxy( result );
...
}
接下来是优化方案
1,增加RealLazy
@Retention(RetentionPolicy.RUNTIME)
public @interface RealLazy {
}
1,重写SimpleJpaRepository的save方法,判断实体类带@RealLazy注解的才不查询实体
public class CustomJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> {
private final JpaEntityInformation<T, ?> entityInformationWrap;
private final EntityManager emWrap;
public CustomJpaRepository(JpaEntityInformation entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
entityInformationWrap=entityInformation;
emWrap=entityManager;
}
@Override
public <S extends T> S save(S entity) {
if (entityInformationWrap.isNew(entity)) {
emWrap.persist(entity);
return entity;
} else {
if(Objects.nonNull(entity.getClass().getAnnotation(RealLazy.class))){
((HibernateEntityManager) emWrap).getSession().update(entity);
return entity;
}else{
return emWrap.merge(entity);
}
}
}
}
3,在启动类指定我们SimpleJpaRepository继承类
@EnableJpaRepositories(repositoryBaseClass = CustomJpaRepository.class)
tips:同理可以重写findAll方法,让findAll不要实时加载依赖类