看看这里:
------------------------------------
14.1. 批量插入(Batch inserts)如果要将很多对象持久化,你必须通过经常的调用 flush() 以及稍后调用 clear() 来控制第一级缓存的大小。Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
if ( i % 20 == 0 ) { //20, same as the JDBC batch size //20,与JDBC批量设置相同
//flush a batch of inserts and release memory:
//将本批插入的对象立即写入数据库并释放内存
session.flush();
session.clear();
}
}
tx.commit();
session.close();
-------------------------
因为你采用的是声明式事务,那就可以不用管session和transaction的打开关闭问题。session实例可以通过Dao的getSession()或sessionFactory.getCurrentSession()获得。
------------------------------------
14.1. 批量插入(Batch inserts)如果要将很多对象持久化,你必须通过经常的调用 flush() 以及稍后调用 clear() 来控制第一级缓存的大小。Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
if ( i % 20 == 0 ) { //20, same as the JDBC batch size //20,与JDBC批量设置相同
//flush a batch of inserts and release memory:
//将本批插入的对象立即写入数据库并释放内存
session.flush();
session.clear();
}
}
tx.commit();
session.close();
-------------------------
因为你采用的是声明式事务,那就可以不用管session和transaction的打开关闭问题。session实例可以通过Dao的getSession()或sessionFactory.getCurrentSession()获得。
没错,我使用的是spring的hibernateTemplate模板,请问如何解决!
(spring直接使用hibernate方法)
public void Foo(){
getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
if ( i % 20 == 0 ) { //20, same as the JDBC batch size //20,与JDBC批量设置相同
//flush a batch of inserts and release memory:
//将本批插入的对象立即写入数据库并释放内存
session.flush();
session.clear();
}
}
return new Integer(100000); //象征性的返回一个obj }
});
}楼主可以试试,至于批量更新,批量删除,可以直接用hql的update和delete来做,更为简单,可以参考hibernate文档
for(int i=0;i<10000;i++)
service.add(obj[i])
如果是这样的话,得把这些都挪到业务层里去做就ok了。楼主最好能让偶看看具体的代码。
btw:几千条数据还不算大批数据,应该不会有什么问题。
public Object doInHibernate(Session session)
throws HibernateException {
}另外,批量更新和删除是hibernate3里出来的,2.x版本里没有。
楼主的问题,应该是你的批量更新没在一个事务中,每更新一个就创建一个connection ,而又不能立即释放,直到连接数等于数据库连接数
我是本帖的作者,我在service的循环里既有既有jdbc的操作,又有hibernate的操作。以下是我的方法:
public boolean saveTYearsSalary(int comp, String eemp, String memp) throws
Exception {
int isDelete = this.getYearsSalaryJdbc().deleteTYearsSalaryByComp(comp);
// boolean isDelete = this.getYearsSalaryDao().deleteTYearsSalaryByComp(comp);
boolean isSave = false; DbTime dbTime = new DbTime();
Date now = dbTime.getNow(); List list = this.getPersonDao().loadTPersonByComp(comp);
List listTYearsSalary=new ArrayList();
int inYears = 0;
int yrAllow = 0;
if (list.size() > 0) {
for (int i = 0; i <= list.size() - 1; i++) {
System.out.println("i: " + i);
TPerson tPerson = new TPerson();
tPerson = (TPerson) list.get(i); TYearsSalary tYearsSalary = new TYearsSalary();
tYearsSalary.setComp(new Short(tPerson.getComp().toString()));
tYearsSalary.setPerNo(tPerson.getPerNo());
tYearsSalary.setInDate(tPerson.getInCdt());
tYearsSalary.setPostType(tPerson.getPost());
tYearsSalary.setEemp(eemp);
tYearsSalary.setCdt(now);
tYearsSalary.setUdt(now);
tYearsSalary.setMemp(memp); if (tPerson.getInCdt() != null) {
inYears = this.getPersonServiceTiger().getLengthOfPerson(tPerson.
getInCdt());
tYearsSalary.setInYears(new Byte(Integer.toString(inYears)));//post有可能变动:
if (tPerson.getPost().equalsIgnoreCase("22")) { //员工
switch (inYears) {
case 0:
yrAllow = 0;
break;
case 1:
yrAllow = 100;
break;
case 2:
yrAllow = 150;
break;
case 3:
yrAllow = 200;
break;
default:
yrAllow = 200;
}
}
else { //非员工
switch (inYears) {
case 0:
yrAllow = 0;
break;
case 1:
yrAllow = 20;
break;
case 2:
yrAllow = 40;
break;
case 3:
yrAllow = 60;
break;
case 4:
yrAllow = 80;
break;
case 5:
yrAllow = 100;
break;
case 6:
yrAllow = 120;
break;
case 7:
yrAllow = 140;
break;
case 8:
yrAllow = 160;
break;
case 9:
yrAllow = 280;
break;
case 10:
yrAllow = 200;
break;
default:
yrAllow = 200;
}
}
tYearsSalary.setYrAllow(new BigDecimal(Integer.toString(yrAllow)));
}
else {
tYearsSalary.setInYears(new Byte(Integer.toString(0)));
tYearsSalary.setYrAllow(new BigDecimal(Integer.toString(0)));
} if (tYearsSalary.getInYears().intValue() > 0) { //如果工龄小于一年的员工就不会新增到年资表
// try {
listTYearsSalary.add(tYearsSalary);
// isSave = this.getYearsSalaryDao().saveTYearsSalary(tYearsSalary);
/* }
catch (Exception ex) {
System.out.println(ex.toString());
this.getYearsSalaryJdbc().deleteTYearsSalaryByComp(comp);
// this.getYearsSalaryDao().deleteTYearsSalaryByComp(comp);
return false;
}*/
}
}
isSave = this.getYearsSalaryDao().saveTYearsSalaryPL(listTYearsSalary);
return isSave;
}
else { //没有符合的记录
return false;
}
}
估计应该是你的 isSave = this.getYearsSalaryDao().saveTYearsSalaryPL(listTYearsSalary);这句出问题了吧,跟踪一下看看。看看你相应的DAO操作
批量更新是指在一个事务中更新大批量数据,批量删除是指在一个事务中删除大批量数据。以下程序直接通过Hibernate API批量更新CUSTOMERS表中年龄大于零的所有记录的AGE字段:
代码内容
tx = session.beginTransaction();
Iterator customers=session.find("from Customer c where c.age>0").iterator();
while(customers.hasNext()){
Customer customer=(Customer)customers.next();
customer.setAge(customer.getAge()+1);
}
tx.commit();
session.close();
如果CUSTOMERS表中有1万条年龄大于零的记录,那么Session的find()方法会一下子加载1万个Customer对象到内存。当执行tx.commit()方法时,会清理缓存,Hibernate执行1万条更新CUSTOMERS表的update语句:
代码内容
update CUSTOMERS set AGE=? …. where ID=i;
update CUSTOMERS set AGE=? …. where ID=j;
update CUSTOMERS set AGE=? …. where ID=k;
以上批量更新方式有两个缺点:
(1) 占用大量内存,必须把1万个Customer对象先加载到内存,然后一一更新它们。
(2) 执行的update语句的数目太多,每个update语句只能更新一个Customer对象,必须通过1万条update语句才能更新一万个Customer对象,频繁的访问数据库,会大大降低应用的性能。
为了迅速释放1万个Customer对象占用的内存,可以在更新每个Customer对象后,就调用Session的evict()方法立即释放它的内存: 代码内容
tx = session.beginTransaction();
Iterator customers=session.find("from Customer c where c.age>0").iterator();
while(customers.hasNext()){
Customer customer=(Customer)customers.next();
customer.setAge(customer.getAge()+1);
session.flush();
session.evict(customer);
}
tx.commit();
session.close();
在以上程序中,修改了一个Customer对象的age属性后,就立即调用Session的flush()方法和evict()方法,flush()方法使Hibernate立刻根据这个Customer对象的状态变化同步更新数据库,从而立即执行相关的update语句;evict()方法用于把这个Customer对象从缓存中清除出去,从而及时释放它占用的内存。
但evict()方法只能稍微提高批量操作的性能,因为不管有没有使用evict()方法,Hibernate都必须执行1万条update语句,才能更新1万个Customer对象,这是影响批量操作性能的重要因素。假如Hibernate能直接执行如下SQL语句: update CUSTOMERS set AGE=AGE+1 where AGE>0; 那么以上一条update语句就能更新CUSTOMERS表中的1万条记录。但是Hibernate并没有直接提供执行这种update语句的接口。应用程序必须绕过Hibernate API,直接通过JDBC API来执行该SQL语句: 代码内容
tx = session.beginTransaction();
Connection con=session.connection();
PreparedStatement stmt=con.prepareStatement("update CUSTOMERS set AGE=AGE+1 "
+"where AGE>0 ");
stmt.executeUpdate();
tx.commit();
以上程序演示了绕过Hibernate API,直接通过JDBC API访问数据库的过程。应用程序通过Session的connection()方法获得该Session使用的数据库连接,然后通过它创建PreparedStatement对象并执行SQL语句。值得注意的是,应用程序仍然通过Hibernate的Transaction接口来声明事务边界。
如果底层数据库(如Oracle)支持存储过程,也可以通过存储过程来执行批量更新。存储过程直接在数据库中运行,速度更加快。在Oracle数据库中可以定义一个名为batchUpdateCustomer()的存储过程,代码如下: 代码内容
create or replace procedure batchUpdateCustomer(p_age in number) as
begin
update CUSTOMERS set AGE=AGE+1 where AGE>p_age;
end;
以上存储过程有一个参数p_age,代表客户的年龄,应用程序可按照以下方式调用存储过程:
代码内容
tx = session.beginTransaction();
Connection con=session.connection();
String procedure = "{call batchUpdateCustomer(?) }";
CallableStatement cstmt = con.prepareCall(procedure);
cstmt.setInt(1,0); //把年龄参数设为0
cstmt.executeUpdate();
tx.commit(); 从上面程序看出,应用程序也必须绕过Hibernate API,直接通过JDBC API来调用存储过程。
Session的各种重载形式的update()方法都一次只能更新一个对象,而delete()方法的有些重载形式允许以HQL语句作为参数,例如: 代码内容
session.delete("from Customer c where c.age>0");
如果CUSTOMERS表中有1万条年龄大于零的记录,那么以上代码能删除一万条记录。但是Session的delete()方法并没有执行以下delete语句 代码内容
delete from CUSTOMERS where AGE>0;
Session的delete()方法先通过以下select语句把1万个Customer对象加载到内存中: 代码内容
select * from CUSTOMERS where AGE>0;
接下来执行一万条delete语句,逐个删除Customer对象: 代码内容
delete from CUSTOMERS where ID=i;
delete from CUSTOMERS where ID=j;
delete from CUSTOMERS where ID=k;
由此可见,直接通过Hibernate API进行批量更新和批量删除都不值得推荐。而直接通过JDBC API执行相关的SQL语句或调用相关的存储过程,是批量更新和批量删除的最佳方式,这两种方式都有以下优点: (1) 无需把数据库中的大批量数据先加载到内存中,然后逐个更新或修改它们,因此不会消耗大量内存。
(2) 能在一条SQL语句中更新或删除大批量的数据。
如果对跨数据库要求不是很高的话,就用jdbc好了。
我是本帖的作者,我的事务管理方法里面确实既有hibernate操作,又有JDBC操作!
也就是在方法的每一次循环里(大概有好几千个循环)都分别执行了几个hibernate操作和JDBC操作! 请问现在程序出现这样的异常:
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Data source rejected establishment of connection, message from server: "Too many connections")
是不是跟这个原因有关呢?
我是本帖的作者,下面是我的方法中写在循环里的数据库操作的方法:
(1)int isDelete = this.getYearsSalaryJdbc().deleteTYearsSalaryByComp(comp);
(2)inYears = this.getPersonServiceTiger().getLengthOfPerson(tPerson.getInCdt());(3)isSave = this.getYearsSalaryDao().saveTYearsSalaryPL(listTYearsSalary); 其中,(1)和(2)都是JDBC的操作,(3)是hibernate操作,而这些方法我都是写在Dao这一层,在service层中调用,而没有直接在service层中实现,所以你在我的代码中没有看看数据库操作的语句。并且我对这个方法做了声明试的事务管理,结果运行不久程序就报这个链接错误了。
而我现在想知道的就是能否在一个事务管理中管理既有JBDC操作又有hibernate操作的情况,如果可以的话,请告诉我解决的方法!