java - @Resource数据源中断数据库连接

标签 java jpa jdbc jboss wildfly

我最近在我的 Web 应用程序中编写了一个类,用于解析一个巨大的 XML 文件并向数据库表提供其内容。我的应用程序在 Wildfly9 上运行,并使用 JPA 和 Hibernate 提供程序来处理 MySQL 数据库。

AS 配置非常标准,我刚刚添加了我的数据源配置:

<datasource jta="false" jndi-name="java:jboss/datasources/spazio_visione" pool-name="spazio_visione" enabled="true" use-ccm="false">
                    <connection-url>jdbc:mysql://127.0.0.1:3306/spazio_visione?zeroDateTimeBehavior=convertToNull&amp;rewriteBatchedStatements=true</connection-url>
                    <driver-class>com.mysql.jdbc.Driver</driver-class>
                    <driver>mysql</driver>
                    <security>
                        <user-name>myuser</user-name>
                        <password>mypasswd</password>
                    </security>
                    <validation>
                        <validate-on-match>false</validate-on-match>
                        <background-validation>false</background-validation>
                    </validation>
                    <statement>
                        <share-prepared-statements>false</share-prepared-statements>
                    </statement>
                </datasource>

这是我的 persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

    <persistence-unit name="backoffice" transaction-type="JTA">
        <jta-data-source>java:jboss/datasources/spazio_visione</jta-data-source>        
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
        <properties>            
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <property name="hibernate.cache.use_query_cache" value="true" />
            <property name="hibernate.cache.use_second_level_cache" value="true" />
            <property name="hibernate.jdbc.batch_size" value="100" />
            <property name="hibernate.order_inserts" value="true" />
            <property name="hibernate.order_updates" value="true" />            
            <!-- <property name="hibernate.show_sql" value="true"/> -->       
            <!-- <property name="hibernate.hbm2ddl.auto" value="validate"/> -->
        </properties>
    </persistence-unit>

</persistence>

使用 JPA 实体来管理我的域模型,一切始终运行良好。

回到我的解析器...实际上,由于多种原因,它需要使用 native JDBC 查询将我的数据插入数据库。代码如下:

public class XMLFeedParser extends DefaultHandler {

    @Inject Logger logger;
    @Resource(lookup="java:jboss/datasources/spazio_visione") DataSource datasource;

    private static final int STATEMENT_BATCH_THRESHOLD = 1000;      
    private MyXMLFeedItem item; 

    private Connection connection;
    private PreparedStatement ps;

    public XMLFeedParser() {

    }

    protected void initParser() throws SQLException {

        connection = datasource.getConnection();    

        Statement deleteStatement = connection.createStatement();
        deleteStatement.executeUpdate("DELETE FROM mytable WHERE id_feed = "+feed.getId());
        deleteStatement.close();

        ps = connection.prepareStatement(
                "INSERT INTO mytable "
                + "( first, second, ...) "
                + "values ( ?, ?, ... )"
                );
    }

    protected void finalizeParser() throws SQLException {
        if (ps!=null) {
            ps.executeBatch();
            ps.close();
        }
        if (connection!=null) {
            connection.close();
        }       
    }

    public void parseAndWriteToDatabase(String filePath) throws ParserConfigurationException, SAXException, IOException, SQLException {

        File file = Paths.get(filePath).toFile();       

        SAXParserFactory factory = SAXParserFactory.newInstance();          
        SAXParser saxParser = factory.newSAXParser();

        initParser();
        saxParser.parse(file, this);
        finalizeParser();               
    }

    private void writeToDb(MyXMLFeedItem item) {

        try {

            ps.setString(1, "first");
            ps.setString(2, "second");
            // ...
            ps.addBatch();

            if ( counter % STATEMENT_BATCH_THRESHOLD == 0 ) {
                ps.executeBatch();
            }

        } catch (SQLException e) {              
            logger.severe(e.getMessage());
        }

    }

    @Override
    public void startElement(String namespaceURI, String localName, String qualifiedName, Attributes attrs) throws SAXException {       
        // ...parsing logic
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        // ...parsing logic
    }

    @Override
    public void endElement(String namespaceURI, String localName, String qualifiedName) throws SAXException {
        // calls writeToDb() for each record found
    }

}

我的 XMLFeedParser 被注入(inject)(使用 @Inject)到我的一个 EJB 中,它将调用 parseAndWriteToDatabase() 方法。有用!

痛苦从这里开始。自解析结束以来,我的应用程序开始在其他点随机地给出错误。堆栈跟踪如下所示:

Caused by: javax.resource.ResourceException: IJ000453: Unable to get managed connection for java:jboss/datasources/spazio_visione
    at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.getManagedConnection(AbstractConnectionManager.java:646)
    at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.getManagedConnection(AbstractConnectionManager.java:552)
    at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:737)
    at org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:138)
    ... 165 more
Caused by: javax.resource.ResourceException: IJ000655: No managed connections available within configured blocking timeout (30000 [ms])
    at org.jboss.jca.core.connectionmanager.pool.mcp.SemaphoreArrayListManagedConnectionPool.getConnection(SemaphoreArrayListManagedConnectionPool.java:553)
    at org.jboss.jca.core.connectionmanager.pool.AbstractPool.getSimpleConnection(AbstractPool.java:622)
    at org.jboss.jca.core.connectionmanager.pool.AbstractPool.getConnection(AbstractPool.java:594)
    at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.getManagedConnection(AbstractConnectionManager.java:579)
    ... 168 more

看起来我没有关闭连接,但事实并非如此! 有什么建议吗?

最佳答案

有几种可能会出现问题。首先,您在 initParser() 中打开连接,但在 finalizeParser() 中关闭它,而不使用finally。如果抛出异常,则连接不会关闭。使用 try-with-resources 仍然会更好。

另一个潜在的问题是该类不是线程安全的。例如,如果在没有同步的情况下使用实例,如果您在 finalizeParser() 之前调用 XMLFeedParser.initParser() 两次,则可能会丢失对 connection 的引用 然后永远不会关闭(注入(inject) XMLFeedParser 的 EJB 是什么样子?)

编辑:使用 try-with-resources: 这取决于您在哪里需要连接。您可以在 parseAndWriteToDatabase() 中打开连接并将其传递给您需要它的方法。因此您不必显式调用 close()。您的PreparedStatements 和ResultSets 也可以包装在try-with-resources 中。

例如:

 public void parseAndWriteToDatabase(String filePath) throws ParserConfigurationException, SAXException, IOException, SQLException {

    // ...
    try (Connection connection = getDataSource().getConnection();)
    {
    initParser(connection);
    saxParser.parse(file, this);
    finalizeParser(connection);               
    }
}

因此,当您的 Connection 和其他变量不是类的成员时,您不必担心其他线程访问它们。

关于java - @Resource数据源中断数据库连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30909977/

相关文章:

java - Hibernate 中对所有表的所有查询的通用条件限制

java - 如果 specfile 中的某些条件不满足,如何中止 rpm 包的安装?

java - 不活动 transaciotn : javax. persistence.TransactionRequiredException:执行更新/删除查询

java - Hibernate 无法运行 session

javascript - 保留字符串java,javascript中的空格

java - JPA 2.0/EclipseLink 和 sqlite 3.7.2 - 无法创建表

java - 包含 LIKE 转换为条件的 JPQL 查询

java - jdbc 在内存中保留准备好的语句?

java - Mac 上的 CLASSPATH,以及 Mac 如何查找 mysql-connector-java-bin.jar

MySQL 驱动程序配置以增加 CloudSQL 的吞吐量