7

I keep getting this error even though i have started the transaction manually.

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
transaction = session.getTransaction();
if(!transaction.isActive())
{
    transaction = session.beginTransaction();
}

accessToken = session.get(OAuthAccessToken.class, token);

hibernate.cfg.xml

<property name="hibernate.connection.autoReconnect">true</property>

    <!-- Use the C3P0 connection pool. -->
    <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">3000</property>

    <!-- Disable second-level cache. -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    <property name="cache.use_query_cache">false</property>
    <property name="cache.use_minimal_puts">false</property>
    <property name="max_fetch_depth">3</property>

    <!-- Bind the getCurrentSession() method to the thread. -->
    <property name="current_session_context_class">thread</property>

    <property name="hibernate.jdbc.batch_size">30</property>

HibernateUtils

public class HibernateUtil
{
private static final SessionFactory sessionFactory;

static
{
    try
    {
        // Create the SessionFactory from hibernate.cfg.xml
        Configuration config = new Configuration().configure();
        config.setProperty("hibernate.show_sql", String.valueOf(ConfigManager.getInstance().getBoolean(Consts.CONFIG_DB_SHOW_SQL, false)));
        config.setProperty("hibernate.format_sql", String.valueOf(ConfigManager.getInstance().getBoolean(Consts.CONFIG_DB_FORMAT_SQL, false)));

        config.setProperty("hibernate.dialect", ConfigManager.getInstance().getString(Consts.CONFIG_DB_DIALECT, "org.hibernate.dialect.MySQLDialect"));
        config.setProperty("hibernate.connection.driver_class", ConfigManager.getInstance().getString(Consts.CONFIG_DB_DRIVER_CLASS, "com.mysql.jdbc.Driver"));
        config.setProperty("hibernate.connection.url", ConfigManager.getInstance().getString(Consts.CONFIG_DB_URL, "jdbc:mysql://localhost/photometo"));
        config.setProperty("hibernate.connection.useUnicode", "true");
        config.setProperty("hibernate.connection.characterEncoding", "UTF-8");
        config.setProperty("hibernate.connection.username", ConfigManager.getInstance().getString(Consts.CONFIG_DB_USERNAME, "root"));
        config.setProperty("hibernate.connection.password", ConfigManager.getInstance().getString(Consts.CONFIG_DB_PASSWORD, ""));
        config.setProperty("hibernate.hbm2ddl.auto", ConfigManager.getInstance().getString(Consts.CONFIG_DB_HBMDDL_AUTO, "update"));
        sessionFactory = config.buildSessionFactory();
    }
    catch (Throwable ex)
    {
        throw new ExceptionInInitializerError(ex);
    }
}

public static SessionFactory getSessionFactory()
{
    return sessionFactory;
}

}

I noticed that this starts happening after some time. If i restart tomcat or re-deploy app, problem goes away

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
pedja
  • 3,285
  • 5
  • 36
  • 48
  • 1
    given configuration looks fine. Is this possible to push minimum viable version of code which can demonstrates the issue on githhub? Or add at least stack trace to question. – skadya Feb 04 '17 at 19:00

1 Answers1

2

You never started a Transaction and you can't get a transaction of other. That's why you are getting an error when you are calling it:

    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    transaction = session.getTransaction(); // Here is the error! You can't get an active transaction, becasue there isn't even started 
    if(!transaction.isActive()) // transaction.isActive() is usually for closing a transction in the end
    {
        transaction = session.beginTransaction(); // You are starting the transaction!
    }

accessToken = session.get(OAuthAccessToken.class, token);

You can't get the active transaction because there isn't even started. Change the code to this:

 // Non-managed environment idiom with getCurrentSession()
try {
    factory.getCurrentSession().beginTransaction();

    // do some work
    ...

    factory.getCurrentSession().getTransaction().commit();
}
catch (RuntimeException e) {
    factory.getCurrentSession().getTransaction().rollback();
    throw e; // or display error message
}

The correct why of starting transactions in a Non-managed environment is this from the Documentation of Hibernate:

// Non-managed environment idiom with getCurrentSession()
try {
    factory.getCurrentSession().beginTransaction();

    // do some work
    ...

    factory.getCurrentSession().getTransaction().commit();
}
catch (RuntimeException e) {
    factory.getCurrentSession().getTransaction().rollback();
    throw e; // or display error message
}

// Non-managed environment idiom with getCurrentSession() try {
    factory.getCurrentSession().beginTransaction();

    // do some work
    ...

    factory.getCurrentSession().getTransaction().commit(); } catch (RuntimeException e) {
    factory.getCurrentSession().getTransaction().rollback();
    throw e; // or display error message }

Following the documentation of getTransaction(), your current session doesn't started a transaction.

getTransaction()
      Get the Transaction instance associated with this session.

And here is why start a transaction 11.2 Database Transaction demarcation:

Database, or system, transaction boundaries are always necessary. No communication with the database can occur outside of a database transaction (this seems to confuse many developers who are used to the auto-commit mode). Always use clear transaction boundaries, even for read-only operations.

And having long transaction is bad for the DB, because generated a lot of locks in your DB,Session and transaction scopes

In order to reduce lock contention in the database, a database transaction has to be as short as possible. Long database transactions will prevent your application from scaling to a highly concurrent load. It is not recommended that you hold a database transaction open during user think time until the unit of work is complete.

Gatusko
  • 2,503
  • 1
  • 17
  • 25
  • I did start the transaction, if you look at my question you will also see this: `transaction = session.beginTransaction();` – pedja Feb 07 '17 at 18:58
  • But you are trying to call `transaction = session.getTransaction();` before starting it, that's why the error. – Gatusko Feb 07 '17 at 19:02
  • No, error is thrown on `session.get` not `getTransaction` – pedja Feb 07 '17 at 21:08
  • Edited the answer. You can't get the active transaction because there isn't an active one. So that's why the Exepction. – Gatusko Feb 07 '17 at 21:33
  • No, that is wrong, if transaction is already started than `beginTransaction` will throw exception – pedja Feb 08 '17 at 09:11