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()。这样在大数据下不会影响性能。