gpt4 book ai didi

java - Hibernate使用@Transactional创建过多的连接,如何防止这种情况?

转载 作者:行者123 更新时间:2023-12-02 06:12:23 25 4
gpt4 key购买 nike

我对Hibernate和PostgreSQL还是相当陌生,但到目前为止一切进展顺利,尽管现在遇到了无法解决的问题。在第一个操作(这是一个在数据库中插入或更新1000行的事务)填充数据库时出现错误。错误是:

SQL Error: 0, SQLState: 53300FATAL: sorry, too many clients alreadyException in thread "main" org.hibernate.exception.GenericJDBCException: Cannot open connection

This is the important code:

@Repository
public class PDBFinderDAO extends GenericDAO<PDBEntry> implements IPDBFinderDAO {
@Override
@Transactional
public void updatePDBEntry(Set<PDBEntry> pdbEntrySet) {
for (PDBEntry pdbEntry : pdbEntrySet) {
getCurrentSession().saveOrUpdate(pdbEntry);
}
}
}


getCurrentSession()是从GenericDAO扩展的,并调用sessionFactory.getCurrentSession()。

这是我的Hibernate配置:

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<property name="hibernate.connection.url">jdbc:postgresql://localhost/PDBeter</property>
<property name="hibernate.connection.username">xxxx</property>
<property name="hibernate.connection.password">xxxx</property>

<!-- Create or update the database schema on startup -->
<property name="hbm2ddl.auto">create</property>

<!-- Use the C3P0 connection pool provider -->
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">300</property>

<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

<!-- Batch size -->
<property name="hibernate.jdbc.batch_size">50</property>

<!-- this makes sure the more efficient new id generators are being used,
though these are not backwards compatible with some older databases -->
<property name="hibernate.id.new_generator_mappings">true</property>

<!-- Echo all executed SQL to stdout -->
<!--
<property name="hibernate.show_sql">true</property>
-->
<property name="format_sql">true</property>
<property name="use_sql_comments">true</property>
</session-factory>
</hibernate-configuration>


这是我的Spring配置:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">


<context:component-scan base-package="nl.ru.cmbi.pdbeter" />

<!-- Transaction Manager -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven />

<!-- Session Factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="hibernate.cfg.xml" />
<property name="packagesToScan" value="nl.ru.cmbi.pdbeter.core.model.domain" />
</bean>

<!-- Task Executor -->
<task:annotation-driven />
</beans>


我不太确定出了什么问题,每次应该只打开一个连接,然后再关闭它,这不是@Transactional应该做什么吗?另外,是否有一种简便的方法来检查在特定时间打开了多少个连接,以便我可以在错误发生之前和之后检查打开了多少个连接?

编辑:当我检查数据库时,什么都没有添加,因此它甚至无法建立一个连接,这是怎么回事?

编辑:对不起,但我已经自己解决了。这是一个非常愚蠢的错误,使用标准也执行了1000次很小的查询,但是在事务之前执行了一个查询,导致它在1000个单独的事务/会话/连接中执行(我认为,正确如果我错了我!)

编辑:好吧,原来根本解决不了这个问题,因为我需要一个小的查询来查看数据库中是否已有东西,如果是的话,请从数据库中获取该对象,以便我可以更新它的fields / columns /随便你怎么称呼它。

这是GenericDAO中的方法:

@Override
public PDBEntry findByAccessionCode(String accessionCode) {
return (PDBEntry) createCriteria(Restrictions.eq("accessionCode", accessionCode)).uniqueResult();
}


有一个函数可以构建不在DAO中的映射对象,因为它将原始数据文件转换为数据库对象,因此我想将其保留在数据库操作之外,而仅将saveOrUpdate()放在数据库模块中。我现在遇到的问题是,在将原始数据文件转换为数据库对象的过程中,findByAccessionCode()被调用了1000次,因为我需要检查数据库中是否已经存在某些数据,如果是,从数据库中获取对象,而不是创建一个新对象。

现在,在这种情况下,我将如何在一个连接内执行1000次该查询?我尝试过使用那种转换方法来转换1000个文件@transactional,但是那没用。

这是转换方法:

private void updatePDBSet(Set<RawPDBEntry> RawPDBEntrySet) {
Set<PDBEntry> pdbEntrySet = new LinkedHashSet<PDBEntry>();

for (RawPDBEntry pdb : RawPDBEntrySet) {
PDBEntry pdbEntry = pdbEntryDAO.findByAccessionCode(pdb.id);
if (pdbEntry == null) {
pdbEntry = new PDBEntry(pdb.id, pdb.header.date);
}

pdbEntry.setHeader(pdb.header.header);

ExpMethod expMethod = new ExpMethod.Builder(pdbEntry, pdb.expMethod.expMethod.toString()).build();
if (pdb.expMethod.resolution != null) {
expMethod.setResolution(pdb.expMethod.resolution);
}
if (pdb.expMethod.rFactor != null) {
expMethod.setRFactor(pdb.expMethod.rFactor.rFactor);

if (pdb.expMethod.rFactor.freeR != null) {
expMethod.setFreeR(pdb.expMethod.rFactor.freeR);
}
}

if (pdb.hetGroups != null) {
for (PFHetId hetId : pdb.hetGroups.hetIdList) {
HetGroup hetGroup = new HetGroup(pdbEntry, hetId.hetId);

if (hetId.nAtom != null) {
hetGroup.setNAtom(hetId.nAtom);
}

if (hetId.name != null) {
hetGroup.setName(hetId.name);
}
}
}

for (PFChain chain : pdb.chainList) {
new Chain(pdbEntry, chain.chain);
}

pdbEntrySet.add(pdbEntry);
}

pdbFinderDAO.updatePDBEntry(pdbEntrySet);
}


(pdbFinderDAO.updatePDBEntry(pdbEntrySet)是我最初认为问题起源的地方)

编辑:首先很抱歉,我创建了这个新文章,我真的以为我找到了答案,但是我将继续在这篇文章中进行进一步的编辑。

好的,现在我通过将一组原始数据文件发送到DAO来将所有1000个findAccessionCode条件放置在DAO中,以便它可以检索其中的ID,然后在数据库中查找它们,获取可以找到的ID并将其添加到一个HashMap,其中将数据库对象与对原始数据文件的引用作为键进行映射(因此我知道哪些原始数据属于哪个数据库条目)。我将@Transactional设为该函数,如下所示:

@Override
@Transactional
public Map<RawPDBEntry, PDBEntry> getRawPDBEntryToPDBEntryMap(Set<RawPDBEntry> rawPDBEntrySet) {
Map<RawPDBEntry, PDBEntry> RawPDBEntryToPDBEntryMap = new HashMap<RawPDBEntry, PDBEntry>();

for (RawPDBEntry pdb : rawPDBEntrySet) {
RawPDBEntryToPDBEntryMap.put(pdb, (PDBEntry) createCriteria(Restrictions.eq("accessionCode", pdb.id)).uniqueResult());
}

return RawPDBEntryToPDBEntryMap;
}


仍然没有成功……我得到了完全相同的错误,但它确实告诉我是导致它的标准。为什么我不能在同一连接中执行所有这1000个查询?

编辑:另一个更新:我尝试将所有查询1乘以1,这很慢,但是有效。我是在一个空数据库上完成的。接下来,我尝试了相同的操作,但是现在数据库已经包含了第一次尝试的内容,并且出现了以下错误:

线程“主” org.hibernate.HibernateException中的异常:非法试图将一个集合与两个打开的会话相关联


我猜想这与以下事实有关:我正在DAO中获取对象(已经存在于数据库中,因此必须进行更新),然后将引用发送回转换方法,然后更改其字段,然后将它们发送回DAO以使其持久化。尽管经过一段时间的搜索,我发现在POJO中带有注释的人在集合方面存在问题:


@OneToMany(mappedBy =“ pdbEntry”,级联= CascadeType.ALL,提取= FetchType.LAZY)


级联引起问题的地方。我是否必须删除所有这些级联并对所有不同的映射对象进行硬编码saveOrUpdate()操作?还是与该错误无关?

最后:我仍然无法弄清楚如何一次处理1000个对象。

最佳答案

解决了这个问题,它与Spring的错误设置有关,导致@Transactional无法识别。我解决了这个问题,然后错误消失了。

关于java - Hibernate使用@Transactional创建过多的连接,如何防止这种情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3996432/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com