欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

使用jpa之动态插入与修改(重写save)

程序员文章站 2022-06-22 15:40:58
目录jpa之动态插入与修改(重写save)1.动态插入2.重写save(修改)3.启动类扩展jpa方法,重写save方法为什么要重构save?一、重写save二、扩张jpa方法jpa之动态插入与修改(...

jpa之动态插入与修改(重写save)

1.动态插入

@data
@entity
@dynamicinsert
@table(name = "cpu_dynamics_information")
@entitylisteners(auditingentitylistener.class)
public class cpudynamicsinformation extends commonentity implements serializable {
  private static final long serialversionuid = -662804563658253624l;
  // cpu动态属性
  private integer cpucore;
  // cpu用户使用率
  private double cpuuserate;
  // cpu系统使用率
  private double cpusysrate;
  // cpu等待率
  private double cpuwaitrate;
  // cpu空闲率
  private double cpuidlerate;
  // cpu总的使用率
  private double cpucombinerate;
  private long serverid;
}

关键注解:

@dynamicinsert
@entitylisteners(auditingentitylistener.class)

2.重写save(修改)

@suppresswarnings(value = "all")
public class jparepositoryrebuild<t, id> extends simplejparepository<t, id> {
  private final jpaentityinformation<t, ?> entityinformation;
  private final entitymanager em;
  @autowired
  public jparepositoryrebuild(
      jpaentityinformation<t, ?> entityinformation, entitymanager entitymanager) {
    super(entityinformation, entitymanager);
    this.entityinformation = entityinformation;
    this.em = entitymanager;
  }
  /** 通用save方法 :新增/选择性更新 */
  @override
  @transactional
  public <s extends t> s save(s entity) {
    // 获取id
    id entityid = (id) this.entityinformation.getid(entity);
    t managedentity;
    t mergedentity;
    if (entityid == null) {
      em.persist(entity);
      mergedentity = entity;
    } else {
      managedentity = this.findbyid(entityid).get();
      if (managedentity == null) {
        em.persist(entity);
        mergedentity = entity;
      } else {
        beanutils.copyproperties(entity, managedentity, getnullproperties(entity));
        em.merge(managedentity);
        mergedentity = managedentity;
      }
    }
    return entity;
  }
  /** 获取对象的空属性 */
  private static string[] getnullproperties(object src) {
    // 1.获取bean
    beanwrapper srcbean = new beanwrapperimpl(src);
    // 2.获取bean的属性描述
    propertydescriptor[] pds = srcbean.getpropertydescriptors();
    // 3.获取bean的空属性
    set<string> properties = new hashset<>();
    for (propertydescriptor propertydescriptor : pds) {
      string propertyname = propertydescriptor.getname();
      object propertyvalue = srcbean.getpropertyvalue(propertyname);
      if (stringutils.isempty(propertyvalue)) {
        srcbean.setpropertyvalue(propertyname, null);
        properties.add(propertyname);
      }
    }
    return properties.toarray(new string[0]);
  }
}

3.启动类

@enablejpaauditing
@springbootapplication(exclude = mongoautoconfiguration.class)
@enablejparepositories(
    value = {"com.fooww.research.repository", "com.fooww.research.shiro.repository"},
    repositorybaseclass = jparepositoryrebuild.class)
public class monitorserverapplication {
  public static void main(string[] args) {
    springapplication.run(monitorserverapplication.class, args);
  }
}

关键注释:

  • enablejparepositories 扫描的repository包
  • repositorybaseclass 重写的save类
  • enablejpaauditing 使@entitylisteners(auditingentitylistener.class) 生效

扩展jpa方法,重写save方法

为什么要重构save?

jpa提供的save方法会将原有数据置为null,而大多数情况下我们只希望跟新自己传入的参数,所以便有了重写或者新增一个save方法。

本着解决这个问题,网上搜了很多解决方案,但是没有找到合适的,于是自己研究源码,先展示几个重要源码

1、simplejparepository方法实现类,由于代码过多只展示部分源码

public class simplejparepository<t, id> implements jparepository<t, id>, jpaspecificationexecutor<t> {
    private static final string id_must_not_be_null = "the given id must not be null!";
    private final jpaentityinformation<t, ?> entityinformation;
    private final entitymanager em;
    private final persistenceprovider provider;
    @nullable
    private crudmethodmetadata metadata;
 
    public simplejparepository(jpaentityinformation<t, ?> entityinformation, entitymanager entitymanager) {
        assert.notnull(entityinformation, "jpaentityinformation must not be null!");
        assert.notnull(entitymanager, "entitymanager must not be null!");
        this.entityinformation = entityinformation;
        this.em = entitymanager;
        this.provider = persistenceprovider.fromentitymanager(entitymanager);
    }
 
    public simplejparepository(class<t> domainclass, entitymanager em) {
        this(jpaentityinformationsupport.getentityinformation(domainclass, em), em);
    }
 
    public void setrepositorymethodmetadata(crudmethodmetadata crudmethodmetadata) {
        this.metadata = crudmethodmetadata;
    }
 
    @nullable
    protected crudmethodmetadata getrepositorymethodmetadata() {
        return this.metadata;
    }
 
    protected class<t> getdomainclass() {
        return this.entityinformation.getjavatype();
    }
 
    private string getdeleteallquerystring() {
        return queryutils.getquerystring("delete from %s x", this.entityinformation.getentityname());
    }
    @transactional
    public <s extends t> s save(s entity) {
        if (this.entityinformation.isnew(entity)) {
            this.em.persist(entity);
            return entity;
        } else {
            return this.em.merge(entity);
        }
    }
}

2、jparepositoryfactorybean

public class jparepositoryfactorybean<t extends repository<s, id>, s, id> extends transactionalrepositoryfactorybeansupport<t, s, id> {
    @nullable
    private entitymanager entitymanager; 
    public jparepositoryfactorybean(class<? extends t> repositoryinterface) {
        super(repositoryinterface);
    }
 
    @persistencecontext
    public void setentitymanager(entitymanager entitymanager) {
        this.entitymanager = entitymanager;
    }
 
    public void setmappingcontext(mappingcontext<?, ?> mappingcontext) {
        super.setmappingcontext(mappingcontext);
    }
 
    protected repositoryfactorysupport docreaterepositoryfactory() {
        assert.state(this.entitymanager != null, "entitymanager must not be null!");
        return this.createrepositoryfactory(this.entitymanager);
    }
 
    protected repositoryfactorysupport createrepositoryfactory(entitymanager entitymanager) {
        return new jparepositoryfactory(entitymanager);
    }
 
    public void afterpropertiesset() {
        assert.state(this.entitymanager != null, "entitymanager must not be null!");
        super.afterpropertiesset();
    }
} 

根据源码及网上资料总结如下方案

一、重写save

优势:侵入性小,缺点将原方法覆盖。

创建jparepositoryrebuild方法继承simplejparepository。

直接上代码

public class jparepositoryrebuild<t, id> extends simplejparepository<t, id> { 
    private final jpaentityinformation<t, ?> entityinformation;
    private final entitymanager em; 
    @autowired
    public jparepositoryrebuild(jpaentityinformation<t, ?> entityinformation, entitymanager entitymanager) {
        super(entityinformation, entitymanager);
        this.entityinformation = entityinformation;
        this.em = entitymanager;
    }
 
    /**
     * 通用save方法 :新增/选择性更新
     */
    @override
    @transactional
    public <s extends t> s save(s entity) {
         
        //获取id
        id entityid = (id) this.entityinformation.getid(entity);
        t managedentity;
        t mergedentity;
        if(entityid == null){
            em.persist(entity);
            mergedentity = entity;
        }else{
            managedentity = this.findbyid(entityid).get();
            if (managedentity == null) {
                em.persist(entity);
                mergedentity = entity;
            } else {
                beanutils.copyproperties(entity, managedentity, getnullproperties(entity));
                em.merge(managedentity);
                mergedentity = managedentity;
            }
        }
        return entity;
    }
 
    /**
     * 获取对象的空属性
     */
    private static string[] getnullproperties(object src) {
        //1.获取bean
        beanwrapper srcbean = new beanwrapperimpl(src);
        //2.获取bean的属性描述
        propertydescriptor[] pds = srcbean.getpropertydescriptors();
        //3.获取bean的空属性
        set<string> properties = new hashset<>();
        for (propertydescriptor propertydescriptor : pds) {
            string propertyname = propertydescriptor.getname();
            object propertyvalue = srcbean.getpropertyvalue(propertyname);
            if (stringutils.isempty(propertyvalue)) {
                srcbean.setpropertyvalue(propertyname, null);
                properties.add(propertyname);
            }
        }
        return properties.toarray(new string[0]);
    }
}

启动类加上jparepositoryrebuild 方法

@enablejparepositories(value = "com.xxx", repositorybaseclass = jparepositoryrebuild.class)
@springbootapplication
@enablediscoveryclient // 即消费也注册
public class systemapplication { 
    public static void main(string[] args) {
        springapplication.run(systemapplication.class, args);
    }     
}

二、扩张jpa方法

1、新建新增方法接口baserepository

@norepositorybean
public interface baserepository<t, id extends serializable> extends jparepository<t, id> { 
    /**
     * 保存但不覆盖原有数据
     * @param entity
     * @return
     */
    t savenotnull(t entity);
}

2、创建baserepositoryimpl方法

@norepositorybean
public class baserepositoryimpl<t, id extends serializable> extends simplejparepository<t, id> implements baserepository<t, id> {  
    private final jpaentityinformation<t, ?> entityinformation;
    private final entitymanager em;   
    public baserepositoryimpl(jpaentityinformation<t, ?> entityinformation, entitymanager entitymanager) {
        super(entityinformation,entitymanager);
        this.entityinformation = entityinformation;
        this.em = entitymanager;
    }
 
    public baserepositoryimpl(class<t> domainclass, entitymanager em) {
        this(jpaentityinformationsupport.getentityinformation(domainclass, em), em);
    }
 
    @override
    @transactional
    public t savenotnull(t entity) { 
        //获取id
        id entityid = (id) this.entityinformation.getid(entity);
        t managedentity;
        t mergedentity;
        if(entityid == null){
            em.persist(entity);
            mergedentity = entity;
        }else{
            managedentity = this.findbyid(entityid).get();
            if (managedentity == null) {
                em.persist(entity);
                mergedentity = entity;
            } else {
                beanutils.copyproperties(entity, managedentity, getnullproperties(entity));
                em.merge(managedentity);
                mergedentity = managedentity;
            }
        }
        return mergedentity;
    } 
 
    private static string[] getnullproperties(object src) {
        //1.获取bean
        beanwrapper srcbean = new beanwrapperimpl(src);
        //2.获取bean的属性描述
        propertydescriptor[] pds = srcbean.getpropertydescriptors();
        //3.获取bean的空属性
        set<string> properties = new hashset<>();
        for (propertydescriptor propertydescriptor : pds) {
            string propertyname = propertydescriptor.getname();
            object propertyvalue = srcbean.getpropertyvalue(propertyname);
            if (stringutils.isempty(propertyvalue)) {
                srcbean.setpropertyvalue(propertyname, null);
                properties.add(propertyname);
            }
        }
        return properties.toarray(new string[0]);
    }
}

3、创建工厂baserepositoryfactory

public class baserepositoryfactory<r extends jparepository<t, id>, t, id extends serializable> extends jparepositoryfactorybean<r, t, id> { 
    public baserepositoryfactory(class<? extends r> repositoryinterface) {
        super(repositoryinterface);
    }
 
    @override
    protected repositoryfactorysupport createrepositoryfactory(entitymanager em) {
        return new myrepositoryfactory(em);
    }
 
    private static class myrepositoryfactory extends jparepositoryfactory { 
        private final entitymanager em;
        public myrepositoryfactory(entitymanager em) {
            super(em);
            this.em = em;
        }
 
        @override
        protected object gettargetrepository(repositoryinformation information) {
            return new baserepositoryimpl((class) information.getdomaintype(), em);
        }
 
        @override
        protected class getrepositorybaseclass(repositorymetadata metadata) {
            return baserepositoryimpl.class;
        } 
    } 
}

4、启动类引入

@enablejparepositories(repositoryfactorybeanclass = baserepositoryfactory.class, basepackages ="com.xxx")
@springbootapplication
@enablediscoveryclient // 即消费也注册
public class systemapplication { 
    public static void main(string[] args) {
        springapplication.run(systemapplication.class, args);
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。