前后台性能优化

       1.在我们写实体类的时候,经常使用Hibernate提供的主键生成策略。在保存对象的时候,如果关联其他对象,会先查关联的这个对象,是否存在(进行保存或者更新),然后才会对原对象进行保存(去掉这一步来优化)。

  但是如果是我们自定义生成策略,不用Hibernate提供的,那么Hibernate在save的时候,就不会查关联对象的主键是否重复。但是需要我们手动控制不重复。

/** 商品gid */
  @Id
  @GeneratedValue(generator = "assigned")
  @GenericGenerator(name = "assigned", strategy = "assigned")
  @Column(name = "gid", nullable = false)
  public Integer getGid() {
    return gid;
  }

2.在开发过程中,切记。用到什么取什么,前面的文章已经说过。如果我们只需要看订单,那么我们就不需要把订单项也关联出来。所以关联对象都是lazy的。

 /** 明细行 */
  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "order")
  @OrderBy("line")
  public List<OrderDetail> getDetails() {
    return details;
  }

但是如果我们需要订单项怎么办? 那么我们可以提供一个方法单独查询订单项。或者 在查询订单的时候提供一个参数,true或者false 来判断是不是要查,然后调用私有的 查询订单项的方法。

这里还有一个地方注意,如果我们查订单,在订单项中,我们看到的只是商品的某些字段。比如,名称,图片,价格等,其他的很多比如供应商,仓库等信息都是不需要的,我们就不需要拿出来。(其实这也是 select *  和select 字段的 这种性能比较)

* 在对象关联的注解,我们不需要两边都配。只需要在一端配置即可。

 /** 明细行 */
  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "order")
  @OrderBy("line")
  public List<OrderDetail> getDetails() {
    return details;
  }


/** 订单 */

@ManyToOne(fetch = FetchType.LAZY)
  @JoinColumns({
      @JoinColumn(name = "num", referencedColumnName = "num", insertable = false, updatable = false),
      @JoinColumn(name = "cls", referencedColumnName = "cls", insertable = false, updatable = false) })
  @Display(value = false, dynamicSearchable = true)
  public Order getOrder() {
    return order;
  }

我们在Order的表没有detail这一字段,所以去掉。但是需要添加@Transient注解。表示该属性并非一个数据库字段的映射,ORM将忽略该属性。务必设置,默认为@Basic  

在只用hibernate merge  由于没有配置一对多这样的关系,在保存的时候不会去保存明细。

我们会单独去存。来提高性能(存的时候会级联 查 里面的对象 是否存在。)

(扩展:insertable = false,updatable = false,当使用JPA实体时,如果两个都映射同一个字段。(orderId字段和Order对象,都是这个对象的属性),加了之后不会报错。不能插不能更新)


  3. 这是一个api对象 和 P对象(persistence持久化)的转化器。

private static OrderConverter instance = new OrderConverter();        
public static OrderConverter getInstance(){
    return instance;
  }

上面这种方式会比下面这种方式好 ,上面 饿汉式单例。

public static OrderConverter instance;
  public static OrderConverter getInstance() {
    if (instance == null)
      instance = new OrderConverter();
    return instance;
  }

我们在转换一个order对象的时候,会关联相应的detail对象,detail会关联相应的goods对象。都会调用相应的转换器,那么都new的话,就会很慢,数据过大的情况下 内存急剧上升。

4.在前后台交互,使用spring MVC,每个方法写好映射注解,requestMapping的value/method,requestParam,requestBody,responseBody等。另外,对象在界面不再进行json序列化,通过jsonData传到后端控制器(省去前后台的序列化和反序列化,同时提高传输效率)。ajax 的jsonDate只能传过来一个对象。

**************************************************************************************************************

前台的优化。

在调用ajax的时候要对成功和失败,都有操作。并且很多地方要判断是否为空。

将所有的ajax放在一个js的方法中(return ajax),其他来调用。

原:在程序中

Ext.Ajax.request({
    url: H4Constants.MODULE["WHOLESALE"].servicePath + '/calcs.hd',
    method: 'POST',
    async: false,
    params: {
        moduleId: "wholeSale",
        componentName: H4Constants.getComponentName("DETAIL"),
        wholeSaleJson: wholeSaleJson,
        detailJson: detailJson
    },
    success: function (response, opts) {
        var result = Ext.decode(response.responseText, true);
        //刷新表格
        if (!Ext.isEmpty(result)) {
            Ext.each(details, function (item, index) {
                var rowIndex = store.find('detailId', item.detailId);
                store.getAt(rowIndex).set('customFields', result[index]);
            });

        }
        details = null;
    }
});
现在:

同步:

getVendor: function (code) {
    var response = Ext.Ajax.request({
        url: this.baseUrl + 'getVendor.hd',
        method: 'GET',
        async: false,
        params: {
            code: code
        }
    });
    return Ext.decode(response.responseText, true);
}
异步:
loadByNum: function (num, fetchDetailCustomFields, target) {
    return Ext.Ajax.request({
        url: this.baseUrl + 'loadByNumber.hd',
        mask: {
            target: target,
            message: '加载中...'
        },
        method: 'GET',
        params: {
            "billNumber": num,
            "fetchDetailCustomFields": fetchDetailCustomFields
        }
    });
},
使用方式:
 var vendor = OrdService.getVendor(value.code);
        viewModel.set('order.vendor', vendor);  //和前台的对象bind
上面是同步的;
如果异步使用方式:
 OrdService.save(order, targetState, cacheKey).//
            then(function (response, opts) {
             ...				//失败执行
             }).otherwise(function (response, opts) {
              callback.onFail(num, response);
}).
	    always(function(){});               //总是执行   
相当于try catch finally
mask 请求的遮罩层,请求等待效果。遮罩的范围通过target传递过来。

5.保存的时候。如果对象的关联对象 数据过大。建议分开保存。增加大数据分配传输逻辑

前台

/**
 * 启动数据上传(明细页面必须定义moduleId属性) * @param datas
 * 上传数据(Array,not null * @param cacheKey
 * 数据缓存标识,必须唯一,not null * @param uploadSize
 * 上传分片大小(默认500)。
 * @returns {promise}
 */
startUploadData: function (datas, cacheKey, uploadSize) {
    var me = this,
        deferred = new Ext.Deferred();

    if (!uploadSize) {
        uploadSize = 500;
    }

    if (datas.length <= uploadSize) {
        deferred.resolve();
        return deferred.promise;
    }

    me.processMsgBox = Ext.Msg.progress("请耐心等待", "明细数据分批上传中...", "0/100");

    return me.uploadData(deferred, datas, cacheKey, Math.ceil(datas.length / uploadSize) - 1, 0, uploadSize);
},
/**
 * 循环分批上传数据(明细页面必须定义moduleId属性) * @param deferred
 * 延迟对象,not null * @param datas
 * 上传数据对象(Array),not null * @param cacheKey
 * 数据缓存标识,必须唯一,not null * @param cacheCount
 * 循环上传总次数,not null * @param cacheIndex
 * 上传次数索引(从0开始),not null * @param uploadSize
 * 上传分片大小,not null * @returns {promise}
 */
uploadData: function (deferred, datas, cacheKey, cacheCount, cacheIndex, uploadSize) {
    var me = this,
        view = me.getView();

    var caches = Ext.Array.slice(datas, 0, uploadSize);
    var _500Date = new Date();
    Ext.Ajax.request({
        url: H4Constants.MODULE[view.moduleId.toUpperCase()].servicePath + '/putCache.hd',
        method: 'POST',
        params: {
            key: cacheKey,
            clean: cacheIndex == 0
        },
        jsonData: caches                                   (jsonData 只能传一个对象)
    }).//
    then(function (response, opts) {
        console.log("@分批上传500条明细花费总时间:" + ((new Date()) - _500Date));
        cacheIndex++;
        Ext.Array.removeAt(datas, 0, uploadSize);
        me.processMsgBox.updateProgress(cacheIndex / cacheCount, Math.ceil((cacheIndex * 100) / cacheCount) + "/100");

        if (datas.length <= uploadSize) {
            me.processMsgBox.hide();
            deferred.resolve();
        } else {
            me.uploadData(deferred, datas, cacheKey, cacheCount, cacheIndex, uploadSize);
        }
    }).//
    otherwise(function (response) {
        var data = Ext.decode(response.responseText, true);
        deferred.reject(data.message);
        deferred.promise.otherwise(function (message) {
            Ext.MessageBox.show({
                title: '上传数据发生错误',
                msg: message,
                icon: Ext.MessageBox.ERROR,
                buttons: Ext.Msg.OK
            });
        });
    });

    return deferred.promise;
},

promise和deferred可以参考上一篇文章

(Ext.clone不递归克隆,Ext.array.slice,返回一个数组中一部分的浅表复制(Array,begin,end))


6.如今很多前端的技术,都会帮你封装好一堆的控件。他会一层一层的封装,如果你使用简单的封装就可以解决的东西,就不要使用复杂的。构造复杂,会影响性能的。

一些情况下,我们可以将 控件的渲染,或者 事件的触发 等 挂起。 

在构造好的很多控件,panel等 如果我们不销毁他会一直存在。所以我们需要手动销毁。

一些,事件,引用,和控件绑定(只有创建时候才算是绑定)

onLog: function () {
    var me = this,
        logDialog = me.logDialog,
        stateFlows = me.getView().moduleContext.stateFlows;
    if (!logDialog)
        logDialog = Ext.create('Common.widget.BillLogDialog', {
            stateFlows: stateFlows
        });
    logDialog.setValue(me.getView().diralc);
    logDialog.show();
},
红色部分的参数,在控件销毁的时候一起销毁。而后面的参数则不会销毁。


7. 在ExtJS重新配置表格的时候,如果store里面有数据,重构的时候会比较慢,在这之前要第一要挂起渲染,然后将store.removeAll()。这样在大数据下不会影响性能。















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值