- 浏览: 1985868 次
- 性别:
- 来自: 哈尔滨
文章分类
- 全部博客 (188)
- java基础 (22)
- 经验+注意 (39)
- Oracle (34)
- javaScript (28)
- jquery (24)
- iBatIS (11)
- hibernate (8)
- struts1.x (1)
- spring (1)
- SVN (1)
- myeclipse (12)
- jbmp工作流 (1)
- 其他 (22)
- 杂谈 (4)
- struts2 (5)
- css (4)
- 正则表达式 (2)
- jstl标签 (4)
- Java Tree (2)
- Jboss (1)
- json (1)
- HttpURLConnection (1)
- Apache commons工具包 (1)
- groovy+grails (2)
最新评论
-
q2425533:
Java字符串倒序输出 + 数组的排序 -
变脸小伙:
今天也跟着学习了,用到了
struts2拦截器 获得请求方法名+获得请求参数 -
tuspark:
讲解的很不错。URLConnection类的内容也可以看这篇文 ...
HttpURLConnection详解 -
wolf746773350:
...
window.location.href/replace/reload()--页面跳转+替换+刷新 -
wolf746773350:
[/flash]
window.location.href/replace/reload()--页面跳转+替换+刷新
hibernate回调防止内存溢出,我是这样用的(事务交给spring管理,手动操作session,50个清空下session):
@Override
public void saveTCommission(final List<TProductType> productTypeList, final String typeNum,
final String employeeId) {
hibernateTemplate.execute( new HibernateCallback() {
@Override
public Object doInHibernate(Session session) throws HibernateException,
SQLException {
long start=System.currentTimeMillis();
for( int i=0; i<productTypeList.size(); i++ ) {
TCommission commission = new TCommission();
TCommissionId TCommissionId = new TCommissionId();//创建TCommissionId类
TCommissionId.setProductNum(productTypeList.get(i).getProductNum());
TCommissionId.setTypeNum(typeNum);
commission.setId(TCommissionId);
commission.setFastCommission(productTypeList.get(i).getMoney());
commission.setCreateDate(new Date());//设置创建时间
commission.setEmployeeId(employeeId);//设置处理工号
commission.setMoney(productTypeList.get(i).getMoney());
hibernateTemplate.save(commission);
if( i % 50 == 0 ) {
session.flush();
session.clear();
}
}
long end=System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
return null;
}
});
}
##注意:1.设置batch_size抓取个数、second_level_cache二级缓存
<prop key="hibernate.jdbc.batch_size">50</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<!-- spring管理hibernate这样设置 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.OracleDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.default_batch_fetch_size">50</prop>
</props>
</property>
2.new对象必须放在里面save,否则只创建部分的,因为始终是一个对象。
3.session每50个就flush()、clear()一次。
4.上面的代码保证seesion不会内存溢出,但是Jboss服务器的内存大小也要设置(默认128M,改大一些),否则一样出现内存溢出问题。
-Xms512m -Xmx1024m -XX:MaxNewSize=256m -XX:MaxPermSize=256m(将这段代码复制到myeclipse--servers--jboss4--jdk中,修改jboss默认内存大小)
##1万条大概10秒
##hibernate的回调HibernateCallback,防止内存溢出,50个清空下session,针对大数据量1万、10万条记录。
目的:使用HibernateTemplate执行execute(newHibernateCallback())方法,从HibernateCallback中得到session,在此session中做多个操作,并希望这些操作位于同一个事务中。
如果你这样写(1):
public static void main(String ss)
CtxUtil.getBaseManager().getHibernateTemplate().execute(newHibernateCallback()
public t doInHibernate(Session session) throwsHibernateException,SQLException
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
session.flush();//实际上,如果不是程序员"手痒"来调用这个flush(),HibernateTemplate中session的事务处理还是很方便的
Student stu2 = new Student();
session.save(stu2);// 没有设置name字段,预期会报出例外
session.flush();
return null;
);
你期望spring在执行完execute回调后,在关闭session的时候提交事务,想法是很好的,但spring并不会这么做。让我们来看看在Hibernate的源代码中,session.beginTransation()做了什么事。看如下代码(2):
public Transaction beginTransaction()throwsHibernateException
errorIfClosed();
if ( rootSession != null )
// todo : should seriously consider not allowing a txn tobeginfrom a child session
// can always route the request to the root session
log.warn( "Transaction started on non-root session" );
Transaction result = getTransaction();
result.begin();
return result;
这个方法中的result是一个org.hibernate.transaction.JDBCTransaction实例,而方法中的getTransaction()方法源代码为(3):
public Transaction getTransaction() throws HibernateException
if (hibernateTransactionnull)
log.error(owner.getFactory().getSettings()
.getTransactionFactory().getClass());
hibernateTransaction = owner.getFactory().getSettings()
.getTransactionFactory()
.createTransaction( this, owner );
return hibernateTransaction;
再次追踪,owner.getFactory()。getSettings().getTransactionFactory()的createTransaction()方法源代码如下(4):
public Transaction createTransaction(JDBCContextjdbcContext,Context transactionContext)
throws HibernateException
return new JDBCTransaction( jdbcContext, transactionContext);
它返回了一个JDBCTransaction,没什么特别的。
在代码2中,执行了result.begin(),其实也就是JDBCTransaction实例的begin()方法,来看看(5):
public void begin() throws HibernateException
if (begun)
return;
if (commitFailed)
throw new TransactionException("cannot re-start transactionafterfailed commit");
log.debug("begin");
try
toggleAutoCommit = jdbcContext.connection().getAutoCommit();
if (log.isDebugEnabled())
log.debug("current autocommit status: " + toggleAutoCommit);
if (toggleAutoCommit)
log.debug("disabling autocommit");
jdbcContext.connection().setAutoCommit(false);//把自动提交设为了false
catch (SQLException e)
log.error("JDBC begin failed", e);
throw new TransactionException("JDBC begin failed: ", e);
callback = jdbcContext.registerCallbackIfNecessary();
begun = true;
committed = false;
rolledBack = false;
if (timeout > 0)
jdbcContext.getConnectionManager().getBatcher().setTransactionTimeout(timeout);
jdbcContext.afterTransactionBegin(this);
在直接使用Hibernate时,要在事务结束的时候,写上一句:tx.commit(),这个commit()的源码为:
public void commit() throws HibernateException
if (!begun)
throw new TransactionException("Transaction notsuccessfullystarted");
log.debug("commit");
if (!transactionContext.isFlushModeNever()&&callback)
transactionContext.managedFlush(); // if an exceptionoccursduring
// flush, user must call
// rollback()
notifyLocalSynchsBeforeTransactionCompletion();
if (callback)
jdbcContext.beforeTransactionCompletion(this);
try
commitAndResetAutoCommit();//重点代码,它的作用是提交事务,并把connection的autocommit属性恢复为true
log.debug("committed JDBC Connection");
committed = true;
if (callback)
jdbcContext.afterTransactionCompletion(true, this);
notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_COMMITTED);
catch (SQLException e)
log.error("JDBC commit failed", e);
commitFailed = true;
if (callback)
jdbcContext.afterTransactionCompletion(false, this);
notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_UNKNOWN);
throw new TransactionException("JDBC commit failed", e);
finally
closeIfRequired();
上面代码中,commitAndResetAutoCommit()方法的源码如下:
private void commitAndResetAutoCommit() throws SQLException
try
jdbcContext.connection().commit();//这段不用说也能理解了
finally
toggleAutoCommit();//这段的作用是恢复connection的autocommit属性为true
上述代码的toggleAutoCommit()源代码如下:
private void toggleAutoCommit()
try
if (toggleAutoCommit)
log.debug("re-enabling autocommit");
jdbcContext.connection().setAutoCommit(true);//这行代码的意义很明白了吧
catch (Exception sqle)
log.error("Could not toggle autocommit", sqle);
因此,如果你是直接使用hibernate,并手动管理它的session,并手动开启事务关闭事务的话,完全可以保证你的事务.
public static void main(String ss)
CtxUtil.getBaseManager().getHibernateTemplate().execute(newHibernateCallback()
public t doInHibernate(Session session) throwsHibernateException,SQLException
log.info(session.connection().getAutoCommit());//打印一下事务提交方式
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
session.flush();
Student stu2 = new Student();
session.save(stu2);// 没有设置name字段,预期会报出例外
session.flush();
return null;
);
运行后,它打出的结果是true,也就是说,虽然保存stu2时会报出例外,但如果commit属性为true,则每一个到达数据库的sql语句会立即被提交。换句话说,在调用完session.save(stu1)后,调用session.flush(),会发送sql语句到数据库,再根据commit属性为true,则保存stu1的操作已经被持久到数据库了,尽管后面的一条insert语句出了问题。
因此,如果你想在HibernateCallback中使用session的事务,需要如下写:
public static void main(String ss)
CtxUtil.getBaseManager().getHibernateTemplate().execute(newHibernateCallback()
public t doInHibernate(Session session) throwsHibernateException,SQLException
session.connection().setAutoCommit(false);
//保存stu1
Student stu1=new Student();
stu1.setName("aaaa");//在数据库中,name字段不允许为null
session.save(stu1);
session.flush();
Student stu2 = new Student();
session.save(stu2);//没有设置name字段,预期会报出例外
session.flush();
session.connection().commit();
//至于session的关闭就不用我们操心了
return null;
);
运行上述代码,没问题了。至此,可能有些读者早就对代码1不满意了:为什么每次save()以后要调用flush()?这是有原因的。下面我们来看看把session.flush()去掉后会出什么问题。改掉后的代码如下:
public static void main(String ss)
CtxUtil.getBaseManager().getHibernateTemplate().execute(newHibernateCallback()
public t doInHibernate(Session session) throwsHibernateException,SQLException
session.connection().setAutoCommit(false);
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
// session.flush();
Student stu2 = new Student();
session.save(stu2);// 没有设置name字段,预期会报出例外
// session.flush();
session.connection().commit();
return null;
);
运行上述代码,后台报数据库的notnull错误,这个是合理的,打开数据库,没有发现新增记录,这个也是合理的。你可能会说:由于事务失败,数据库当然不可能会有任何新增记录。好吧,我们再把代码改一下,去除notnull的错误,以确保它能正常运行。代码如下:
public static void main(String ss)
CtxUtil.getBaseManager().getHibernateTemplate().execute(newHibernateCallback()
public t doInHibernate(Session session) throwsHibernateException,SQLException
session.connection().setAutoCommit(false);
// 保存stu1
Student stu1 = new Student();
stu1.setName("aaaa");// 在数据库中,name字段不允许为null
session.save(stu1);
// session.flush();
Student stu2 = new Student();
stu2.setName("asdfasdf");//好了,这个字段设过值,不会再报not null错误了
session.save(stu2);
// session.flush();
session.connection().commit();
return null;
);
至此再运行上述代码,出现了一个奇怪的问题:虽然控制台把insert语句打出来了,但是:数据库没有出现任何新的记录。
究其原因,有二:
一、session.connection()。commit()确实导致数据库事务提交了,但是此刻session并没有向数据库发送任何语句。
二、在spring后继的flushIfNecessary()和closeSessionOrRegisterDeferredClose()方法中,第一个方法向数据库发送sql语句,第二个方法关闭session,同时关闭connection,然后问题在于:connection已经在程序中被手动设置为auttocommit=false了,因此在关闭数据库时,也不会提交事务。
解决这个问题很容易,在程序中手动调用session.flush()就可以了。如下代码:
public static void main(String ss)
CtxUtil.getBaseManager().getHibernateTemplate().execute(newHibernateCallback()
public t doInHibernate(Session session) throwsHibernateException,SQLException
session.connection().setAutoCommit(false);
//保存stu1
Student stu1=new Student();
stu1.setName("aaaa");//在数据库中,name字段不允许为null
session.save(stu1);
Student stu2 = new Student();
session.save(stu2);//没有设置name字段,预期会报出例外
session.flush();//向数据库发送sql
session.connection().commit();
return null;
);
运行上述代码,打开数据库查看,没有新增任何记录。在代码中新加一行stu2.setName("aaa");再次运行代码,发现数据库表中多了两条记录。事务操作成功。
至此,虽然操作成功,但事情还没有结束。这是因为spring在调用doInHibernate()的后继的步骤中,还要进行flushIfNecessary()操作,这个操作其实最后调用的还是session.flush()。因为在程序中已经手动调用过session.flush(),所以由spring调用的session.flush()并不会对数据库发送sql(因为脏数据比对的原因)。虽然不会对结果有什么影响,但是多调了一次flush(),还是会对性能多少有些影响。能不能控制让spring不调用session.flush()呢?可以的,只要加上一句代码,如下所示:
public static void main(String ss)
CtxUtil.getBaseManager().getHibernateTemplate().setFlushMode(0);//0也就是FLUSH_NEVER
CtxUtil.getBaseManager().getHibernateTemplate().execute(newHibernateCallback()
public t doInHibernate(Session session) throwsHibernateException,SQLException
session.connection().setAutoCommit(false);
//保存stu1
Student stu1=new Student();
stu1.setName("aaaa");//在数据库中,name字段不允许为null
session.save(stu1);
Student stu2 = new Student();
stu2.setName("sdf");
session.save(stu2);//没有设置name字段,预期会报出例外
session.flush();
session.connection().commit();
return null;
);
通过设置HibernateTemplate的flushMode=FLUSH_NEVER来通知spring不进行session.flush()的调用,则spring的flushIfNecessary()将不进行任何操作,它的flushIfNecessary()源代码如下:
protected void flushIfNecessary(Session session,booleanexistingTransaction) throws HibernateException
if (getFlushMode() FLUSH_EAGER (!existingTransaction&&getFlushMode() != FLUSH_NEVER))
logger.debug("Eagerly flushing Hibernate session");
session.flush();
至此,代码1中的main()终于修改完毕。但事实上,这样的操作无疑是比较麻烦的,因此如果在spring中想利用session进行事务操作时,最好还是用TransactionTemplate(编程式事务)或是声明式事务比较方便一些。
本例通过这么一个虽然简单但又绕来绕去的例子,主要是说明hibernate事务的一些内在特性,以及HibernateTemplate中如何处理session和事务的开关,让读者对HibernateTemplate的源代码处理细节有一些了解,希望能给读者有抛砖引玉的作用。
发表评论
-
Hibernate查询返回 List
2011-07-21 15:59 2156###Hibernate一般是返回对象实体,但是如果你非要返回 ... -
Hibernate中No row with the given identifier exists
2011-05-25 17:51 2390今天做价格策略,报如下异常: org.springframe ... -
HibernateTemplate常规用法
2011-05-17 11:23 1588转自:http://kewb.iteye.com/blog/1 ... -
Hibernate回调--bernate的复杂用法HibernateCallback
2011-05-17 11:15 1706转自:http://kewb.iteye.com/blog/1 ... -
Hibernate3.x调用存储过程
2011-05-17 11:10 1228转自:http://www.blogjava.net/kewe ... -
懒加载异常web.xml中OpenSessionInViewFilter与struts2,谁前谁后?
2011-04-02 17:41 1920##注意hibernateFilter过滤器和struts2过 ... -
hibernate使用oracle的sequence
2011-03-31 23:53 9052一、在很多情况下,我们使用Hibernate在已经建立好数据库 ...
相关推荐
- **execute**:这是`HibernateTemplate`的核心方法,它执行由`HibernateCallback`接口定义的数据访问操作,并将Hibernate抛出的异常转换为Spring的数据访问异常。 ```java public <T> T execute...
这个内部类通常继承自Struts2的ResultSupport类,覆盖execute方法,这样我们可以在回调函数中处理分页的相关逻辑,例如计算总页数、设置当前页数据等。 5. **JSP页面展示**:在前端页面,使用Struts2提供的标签库,...
本文将深入探讨如何利用Hibernate中的`HibernateTemplate`类进行批量数据删除操作,这不仅能够提高数据处理效率,还能优化数据库性能。 ### HibernateTemplate与批量删除 在Hibernate框架中,`HibernateTemplate`...
### HibernateTemplate类的使用详解 #### 一、引言 在Java开发中,持久层框架Hibernate因其优秀的ORM(Object-Relational Mapping)特性被广泛应用。为了更便捷地使用Hibernate,Spring框架提供了一系列工具类来简化...
hibernateTemplate.execute(new HibernateCallback() { public Void doInHibernate(Session session) throws HibernateException, SQLException { session.save(new Person("王五", "123456789")); // 更多业务...
- **功能**:执行指定的回调方法,并返回其结果。 - **示例代码**: ```java template.execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, ...
这里传入了一个实现了`HibernateCallback`接口的匿名内部类,该类的`doInHibernate`方法定义了具体的数据库操作逻辑。 ##### 2. 处理查询结果 ```java List list = smokeEventServer.everyDaySmoke(); for (Object...
`HibernateTemplate`是Spring框架中用于操作Hibernate的一个便捷工具类,它极大地简化了Hibernate在实际应用中的集成与开发工作。通过`HibernateTemplate`,开发者可以非常方便地进行数据的增删改查等基本操作,而...
`HibernateTemplate`还支持分页查询,这对于大数据量的应用场景非常有用。例如,可以通过以下方法设置每页的记录数量: - `void setMaxResults(int maxResults)`:设置分页的最大结果数。 通过结合`find`方法使用...
- **快速开发**:由于HibernateTemplate封装了许多常用的数据访问操作,因此可以显著减少编码工作量。 - **统一的异常处理**:使用HibernateTemplate可以避免出现由Session关闭不当导致的问题。 - **集成Spring框架*...
HibernateTemplate 汇总 HibernateTemplate 是 Spring 框架中的一個关键组件,用于简化 Hibernate 的使用,提供了許多实用的方法来进行数据库操作。在本文中,我们将对 HibernateTemplate 的主要方法进行总结和解释...
// 回调 callback.doInHibernate(s); s.getTransaction().commit(); } catch (Exception e) { s.getTransaction().rollback(); } finally { s.close(); s = null; } } private Session getSession() { ...
《轻量级 J2EE 企业应用实战: Struts+Spring+Hibernate 整合开发》一书中详述了Spring与Hibernate的整合,其中一个重要组件就是HibernateTemplate。它为简化Hibernate在Spring框架中的使用提供了便利,减少了手动...
`HibernateTemplate`的主要价值在于让开发者能够将更多的精力聚焦于业务逻辑上,而不是繁琐的数据访问细节。这一点体现在以下几个方面: 1. **事务管理**:`HibernateTemplate`提供了内置的事务管理机制,开发者...
HibernateTemplate的简单示例
在`HibernateTemplate`中执行事务操作通常涉及到`execute`方法,该方法接受一个实现了`HibernateCallback`接口的匿名类实例作为参数。`HibernateCallback`的`doInHibernate`方法会在Hibernate的Session上下文中执行...
开发者可以在实现`doInHibernate(Session session)`方法后,通过`HibernateTemplate.execute(HibernateCallback<T> action)`方法执行回调。 2. **命名SQL查询** 命名SQL查询允许预先在配置文件中定义SQL语句,然后...
3. **使用HibernateTemplate**:在我们的业务逻辑类中,我们可以通过@Autowired注解或者使用getBean方法从Spring容器中获取HibernateTemplate实例,然后调用它的方法进行数据库操作。例如: ```java @Service ...
为了简化Hibernate与Spring的整合,Spring提供了`HibernateTemplate`类,它是一个封装了Hibernate Session的工具类,使得在处理数据库操作时更加方便。`HibernateTemplate`在事务管理、异常转换等方面提供了很多便利...