我有一个在Tomcat 7上运行的Java Web应用程序 - jdk1.7
此应用程序使用Spring 4.1.5.RELEASE和Hibernate 4.2.2.Final
我的问题是构建部分工厂的堆空间的OutOfMemoryException
这是我打开SessionFactory
的静态方法public class GenericDAO {
public static SessionFactory sessionFactory = null;
public static ServiceRegistry serviceRegistry = null;
Transaction tx = null;
public static SessionFactory createSessionFactory() {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(
configuration.getProperties()). buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
}
这是DAO的一个例子
public class SpecificDAO extends GenericDAO {
public int save(MyObject item) {
Session session = createSessionFactory().openSession();
try {
tx = session.beginTransaction();
session.save(item);
tx.commit();
return item.getId();
} catch (HibernateException e) {
if (tx != null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return -1;
}
}
错误发生在包含
的行sessionFactory = configuration.buildSessionFactory(serviceRegistry);
问题不会在部署时立即发生,但在使用2天后仍然存在
这是我的Hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:sqlserver://192.168.XX.XXX:1433;databaseName=DatabaseName</property>
<property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="connection.username">username</property>
<property name="connection.password">password</property>
<mapping class="it.company.client.project.hibernate.MyObject"/>
<!-- DB schema will be updated if needed -->
<!-- <property name="hbm2ddl.auto">update</property> -->
</session-factory>
</hibernate-configuration>
答案 0 :(得分:2)
您必须只创建一次会话工厂,因为它是一个重量级的对象,请参阅hibernate documentation了解其详细信息。
以下是doc应如何创建的示例代码:
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory(
new StandardServiceRegistryBuilder().build() );
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
答案 1 :(得分:1)
最好在使用后刷新并清除会话,您可以同时使用
from("servlet:apiwrapper?matchOnUriPrefix=true")
.to("bean:httpHeaderSetter?method=setHttpHeaders")
.to("http://HOST/BASEPATH?throwExceptionOnFailure=false&httpClient.authenticationPreemptive=true");
答案 2 :(得分:1)
您正在为每次save()调用创建一个SessionFactory对象。
即你为每个save()调用重复创建一个新的SessionFactory,但是没有关闭内存中现有的SessionFactory对象。
调用save()多少次?会话中没有SessionFactory,这会导致内存泄漏。
SessionFactory是重量级对象,因此您可以在应用程序初始化时创建。您可以创建一个SingleTon来实例化SessionFactory。
答案 3 :(得分:0)
避免在每个DAO操作上实例化SessionFactory对象。它非常慢并导致内存泄漏。在this answer
中有更好的解释如果您仍然使用Spring
,最好委托Spring
使用SessionFactory,处理事务和处理SQL异常。例如,save()方法将减少为一行代码sessionFactory.getCurrentSession().save(item);
手动事务打开/提交/回滚应替换为@Transactional
属性。此外,通常更好地将事务放在整个服务方法上,而不是放在每个DAO方法上,但它取决于业务逻辑。
Here示例如何使用Hibernate
配置弹出上下文(仅适用于Google的第一篇文章)
我稍微采用了这个例子来解决当前的问题
@Repository
public class SpecificDAO {
private SessionFactory sessionFactory;
@Autowired
public SpecificDAO(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Transactional(propagation=Propagation.REQUIRED)
public int save(MyObject item) {
try{
sessionFactory.getCurrentSession().save(item);
}catch (HibernateException e) {
return -1;
}
}
}
Spring配置
<context:annotation-config/>
<context:component-scan base-package="it.company.client.project"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://192.168.XX.XXX:1433;databaseName=DatabaseName"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>it.company.client.project.hibernate.MyObject</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.connection.provider_class">org.hibernate.connection.DatasourceConnectionProvider</prop>
<prop key="hibernate.show_sql">false</prop>
<!--prop key="hibernate.hbm2ddl.auto">update</prop-->
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>