解决数据量大的问题我觉得最主要的有两点:
1、即使清理缓存
在处理大数据量时,会有大量的数据缓冲保存在Session的一级缓存中,这缓存大太时会严重显示性能,所以在使用Hibernate处理大数据量的,可以使用session.clear()或者session. evict(Object) 在处理过程中,清除全部的缓存或者清除某个对象。
2、减少与数据库的交互次数
对于大数据量新增、修改、删除操作或者是对大数据量的查询,与数据库的交互次数是决定处理时间的最重要因素,减少交互的次数是提升效率的最好途径。
在Hibernate的配置文件中有一项hibernate.jdbc.batch_size
Hibernate提供了配置参数来设置JDBC的批处理操作的大小。但并不是说这个数值越大就越好。一般设为30,50就够了,至于这个参数的性能问题,找了许久也没人能说出个大概。这里不做讨论。
如果启用了二级缓存,从机制上讲Hibernate为了维护二级缓存,我们在做插入、更新、删除操作时,Hibernate都会往二级缓存充入相应的数据。性能上就会有很大损失,所以笔者建议在批处理情况下禁用二级缓存。
将use_second_level_cache=false;
接着就熟悉的代码坐下解释。
public ModelAndView saveImport(HttpServletRequest request
,HttpServletResponse response) {
String fileName = StringUtils.varFormat(request.getParameter("fileName"));
boolean successful = true;
if (fileName.equals("")) {
request.setAttribute("mesage", this.MSG_NO_DATA_FOUND);
return new ModelAndView(this.failView);
}
Map formatMap = new HashMap();
int i=0;
formatMap.put(i++, "customerName");
formatMap.put(i++, "customerSex");
formatMap.put(i++, "phoneNo");
formatMap.put(i++, "categoryName");
formatMap.put(i++, "cardType");
formatMap.put(i++, "cardId");
//添加2010-03-31
formatMap.put(i++,"customerCorp");
formatMap.put(i++,"homeAddr");
formatMap.put(i++,"customerJoy");
List data = ExcelUtils.importExcel(fileName, formatMap, true);//包含标题
if (data.size() == 0) {
request.setAttribute("mesage", this.MSG_NO_DATA_FOUND);
return new ModelAndView(this.failView);
}
//定义手机集合,判断导入的数据是否重复
StringBuffer phoneNos=new StringBuffer();
//定义客户类型集合,避免每次查询,节约时间
StringBuffer types=new StringBuffer();
//开启事务
Session session = customerDao.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
//定义循环因素
int num=1;
//获得公司部门Id与实体,节省时间
int corpSid=this.staff.getCompany().getCorpSid();
String deptSid=this.staff.getDepartment().getDepartmentSid();
Company company=this.staff.getCompany();
Department department=this.staff.getDepartment();
//导入数据
try{
//将客户类型从数据库中拿出来放入List中,以后有用到客户类型表的时候就不用在从数据库中去取了,减少数据库访问的次数。这点很重要。
CustomerCategory category = new CustomerCategory();
List<CustomerCategory> categoryList=customerCategoryDao.createQuery("from CustomerCategory t WHERE " +
"t.department.departmentSid='"+deptSid+"' and t.company.corpSid="+corpSid).list();
for (Map map : (List<Map>)data) {
String customerName = StringUtils.varFormat(String.valueOf(map.get("customerName")));
String categoryName = StringUtils.varFormat(String.valueOf(map.get("categoryName")));
String sex = StringUtils.varFormat(String.valueOf(map.get("customerSex")));
String phoneNo = StringUtils.varFormat(String.valueOf(map.get("phoneNo")));
String cardType = StringUtils.varFormat(String.valueOf(map.get("cardType")));
String cardId = StringUtils.varFormat(String.valueOf(map.get("cardId")));
String customerCorp=StringUtils.varFormat(String.valueOf(map.get("customerCorp")));
String homeAddr=StringUtils.varFormat(String.valueOf(map.get("homeAddr")));
String customerJoy=StringUtils.varFormat(String.valueOf(map.get("customerJoy")));
int index=phoneNos.indexOf(phoneNo);
//判断导入的手机号码自身有没有重复
if(index!=-1){
continue;
}
phoneNos.append(phoneNo+",");
//判断手机号码长度
if((!("".equals(phoneNo)))&& (phoneNo.length()==11||phoneNo.length()==7||phoneNo.length()==8)) {
String sql;
sql="select * from customer where phone_no='"+phoneNo+"' and dept_sid_fk='"+deptSid+"' and corp_sid_fk="+corpSid;
//在此我用了session.createSQLQuery(sql).list(),而不是customerDao.find(hql),避免了数据从数据库中查出来以后,封装成对象的过程。不过这样会带来一个数据对象转换的问题,可以对比下边的一处代码,那个地方我还是用了hql.
List<Customer> customers=session.createSQLQuery(sql).list();
if(customers.size()==0){
Customer customer = new Customer();
customer.setCustomerSex(sex);
customer.setPhoneNo(phoneNo);
customer.setCompany(company);
customer.setDepartment(department);
customer.setCardType(cardType);
customer.setCardId(cardId);
customer.setSmsConfirmState("N");
customer.setCustomerCorp(customerCorp);
customer.setHomeAddr(homeAddr);
customer.setCustomerJoy(customerJoy);
if ("".equals(customerName)) {
customerName = "--UNNAMED--";
}
customer.setCustomerName(customerName);
if (!("".equals(categoryName))) {//指定分类
//这里就是我为什么要定义一个StringBuffer类型的types的原因,当前面已经执行过相同客户类型的操作时,就可以完全的跳过index_type==-1中的操作,减少数据库的访问。
int index_type=types.indexOf(categoryName);
if(index_type==-1){
//这里用了session.createQuery(hql).list().而不是session.createSQLQuery(sql).list(),因为这样会在category=categoryList.get(m);时报类型转换异常。
List<CustomerCategory> categorys = session.createQuery("from CustomerCategory t WHERE t.department.departmentSid='"+deptSid+"' AND t.categoryName='"+StringUtils.sqlFormat(categoryName)+"'").list();
if (categorys.size() == 0) {
category = new CustomerCategory();
category.setCategoryName(categoryName);
category.setCompany(company);
category.setDepartment(department);
category.setCreateDate(new Date());
customerCategoryDao.save(category);
}else{
category=categorys.get(0);
}
types.append(categoryName+",");
}else{
for(int m=0;m<categoryList.size();m++){
if(categoryList.get(m).getCategoryName().equals(categoryName)){
category=categoryList.get(m);
}
}
}
//前边的if...else都是为了得到category对象。
customer.setCustomerCategory(category);
}
customer.setCreateDate(new Date());
session.save(customer);
//此处很重要,这就是在前便提到的及时清除session中的缓存的地方,当数量达到40时及时清除,和batch_size数值对应。
if(num%40==0){
session.flush();
session.clear();
}
}
}
num++;
}
}catch(Exception e){
e.printStackTrace();
tx.rollback();
successful=false;
}
if (successful) {
tx.commit();
session.close();
request.setAttribute("message", this.MSG_SUCCESS);
request.setAttribute("redirectUrl", this.requestUri+".do?method=list");
return new ModelAndView(this.successView);
} else {
session.close();
request.setAttribute("message", this.MSG_FAIL);
return new ModelAndView(this.failView);
}
}
分享到:
相关推荐
使用Hibernate将大量记录插入到数据库
很多人都对Java在批量数据的处理方面是否是其合适的场所持有怀疑的念头,由此延伸,...下面以Hibernate为例来做为说明,假如我们真的不得不在Java中使用Hibernate来对数据进行批量处理的话。 向数据库插入100 000条数据
1) 在处理大数据量时,会有大量的数据缓冲保存在Session的一级缓存中 2) 对大数据量查询时,慎用list()或者iterator()返回查询结果, 3) 对于关联操作,Hibernate虽然可以表达复杂的数据关系 4) 对含有关联的PO...
spring+hibernate解决多数据源问题3.pdf
在Java SE中使用Hibernate处理数据
hibernate中处理大字段 网上收集的文档
Hibernate 使用缓存时,数据同步问题
Hibernate配置各种数据源 <hibernate-configuration> <!– 各属性的配置–> <!—为true表示将Hibernate发送给数据库的sql显示出来 –> ”show_sql”>true <!– SQL方言,这边设定的是MySQL –> ”dialect”>...
HIBERNATE FOR NETBEANS 数据操作方法 还有的是,这是对HIBERNATE 的简单使用的介绍..
适合初学者使用。使用Hibernate做查询数据库,代码为eclipse项目,直接导入即可使用,只供参考。
Spring Hibernate 事务处理 详细说明 Spring Hibernate 事务处理 详细说明
hibernate入门数据简单插入
看完该文件你就可以最高效率的批量处理数据
Hibernate面试题专栏 - 最全的Hibernate面试题, Hibernate笔试题, Hibernate问题 Hibernate教程
hibernate常见问题及处理。
Hibernate中数据类型,涵盖了所有数据库的字段类型与Java基本类型间的映射关系
Spring+Hibernate多数据源的整合实现demo
Hibernate进行数据查询
spring boot 2多数据源,里面有hibernate和mybatis的多数据源代码。代码拿过去即可集成使用。