Проблема гибернации: «Слишком много подключений»

#java #hibernate

#java #гибернация

Вопрос:

Я получаю следующую ошибку:

 .
.
.
.
6844 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1040, SQLState: 08004
6844 [main] ERROR org.hibernate.util.JDBCExceptionReporter - Data source rejected establishment of connection,  message from server: "Too many connections"
Exception in thread "main" org.hibernate.exception.JDBCConnectionException: Cannot open connection
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:99)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:52)
    at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:449)
    at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
    at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:160)
    at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:81)
    at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1473)
    at sun.reflect.GeneratedMethodAccessor121.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:345)
    at $Proxy0.beginTransaction(Unknown Source)
    at com.mycomp.myproj.matcher.Matcher.findMatch(Matcher.java:228)
    at com.mycomp.myproj.Confidence.Confidence.main(Confidence.java:160)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection,  message from server: "Too many connections"
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:409)
    at com.mysql.jdbc.Util.getInstance(Util.java:384)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1015)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:984)
    at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1105)
    at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2186)
    at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:787)
    at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:49)
    at sun.reflect.GeneratedConstructorAccessor16.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:409)
    at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:357)
    at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:285)
    at java.sql.DriverManager.getConnection(Unknown Source)
    at java.sql.DriverManager.getConnection(Unknown Source)
    at org.hibernate.connection.DriverManagerConnectionProvider.getConnection(DriverManagerConnectionProvider.java:133)
    at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
    ... 11 more
  

Биты гибернации моей программы выглядят следующим образом:

 for loop_1        // this will execute say 2000 times 
{
    for loop_2       // this will execute say 1000 times
    {
        // Opening 2 sessions for 2 different databases

        Configuration config_1 = new Configuration().configure("Hibernate_1.cfg.xml");
        SessionFactory sessionFactory_1 = config_1.buildSessionFactory();
        Session session_1 = sessionFactory_1.getCurrentSession();
        session_1.beginTransaction();

        Configuration config_2 = new Configuration().configure("Hibernate_2.cfg.xml");
        SessionFactory sessionFactory_2 = config_2.buildSessionFactory();
        Session session_2 = sessionFactory_2.getCurrentSession();
        session_2.beginTransaction();

        doInsertDb_1(some_object_1, session_1);

        doUpdateDb_2(some_object_2, session_2);
    }
}

    public int doInsertDb_1(Object obj, Session session) {

        try {

            session.save(obj);
            session.flush();
            session.getTransaction().commit();

            return 1;

        } catch (Exception ex) {
            ex.printStackTrace();
            return 0;
        }
    }

    public int doUpdate_2(Object obj, Session session) {

        try {

            Query query = session.createQuery("" <Creating some query> );
            query.executeUpdate();
            session.getTransaction().commit();

            return 1;

        } catch (Exception ex) {
            ex.printStackTrace();
            return 0;
        }
    }
  

Очевидно, что где-то я не закрываю соединения должным образом. Я не могу понять, где? Может кто-нибудь, пожалуйста, помочь мне с этим?

Большое спасибо.

Ответ №1:

Вы уверены, что вам нужно создавать оба сеанса каждый раз через цикл? Создание их один раз, перед обоими циклами, скорее всего, решит вашу проблему и ускорит ваш код. Однако, если вы настаиваете на том, чтобы открывать их во внутреннем цикле, обязательно сделайте close() это впоследствии, поскольку это должно, по крайней мере, освободить соединения с базой данных, которые вы открываете (но никогда не закрываете.)

РЕДАКТИРОВАТЬ: Вам следует отложить внесение изменений до тех пор, пока вы не внесете их все, чтобы не закрывать соединения преждевременно.

ПРАВКА 2: Поскольку вам нужны результаты каждого обновления для обработки дальнейших обновлений, вы можете, по крайней мере, перенести создание SessionFactories за пределы циклов.

Комментарии:

1. @dlev: Спасибо за ваш ответ. как я ответил Cris, если я создаю их снаружи for loop_1 , я получаю Session already closed! ошибку. Это потому, что, когда я делаю session.getTransaction().commit(); , я вижу в отладчике, что он закрывает сеанс после этого stmt.

2. Интересно. Возможно, вам следует просто отложить фиксацию, пока вы не внесете все свои изменения?

3. я обязательно попробую это. где-то я обнаружил, что оператор закрытия и ResultSet помогли запрашивающему. Я также выполняю некоторые выборки в каждом цикле (которые я не добавил в свой вопрос). так и думал, что в этом проблема. но я также закрываю инструкцию и результирующий набор, и все та же проблема.

4. @dlev: ваше предложение помогает, но есть одна проблема. в цикле, когда я вставляю записи в БД, я должен рассмотреть эту запись в следующем цикле. поэтому, если я не зафиксирую это немедленно, я не смогу получить эту запись и, следовательно, конечный результат будет неправильным. есть ли способ получше?

5. Хм … одной из возможностей было бы переместить создание SessionFactory за пределы обоих циклов, но сохранить само создание сеанса внутри. Это работает?

Ответ №2:

Попробуйте создать сеансы вне цикла

Комментарии:

1. Спасибо за ваш ответ. Я попытался создать их вне for loop_2 и получил ту же ошибку. Кроме того, я попытался создать их вне for loop_2 и я получаю Session already closed! , что и ожидалось.

2. я создал сеанс вне цикла, а также удалил session.getTransaction().commit(); stmt, и теперь я совершаю транзакцию снаружи for loop_1 . но когда я вставляю записи в БД, я должен учитывать эту запись в следующем цикле. поэтому, если я не зафиксирую это немедленно, я не смогу получить эту запись и, следовательно, конечный результат будет неправильным. есть ли способ получше?