簡體   English   中英

Hibernate中並發事務的最大數量是否有限制?

[英]Is there a limit for maximum number of concurrent transactions in Hibernate?

我有一個客戶端,它向使用Hibernate的服務層發送3個請求。

每個單個請求都使Hibernate開始一個事務( session.beginTransaction() )。

我發現, 有時 ,一個事務(來自2個以上正在運行的並發事務)因createQuery is not valid without active transaction失敗createQuery is not valid without active transaction

這是我使用的Hibernate配置(在Tomcat 6.0.x和OC4j 10.1.3.4中運行):

<property name="hibernate.connection.pool_size">5</property>
        <!--  <property name="hibernate.current_session_context_class">thread</property> -->
        <property name="hibernate.current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</property>
        <property name="connection.autoReconnect">true</property>
        <property name="connection.autoReconnectForPools">true</property>
        <property name="connection.is-connection-validation-required">true</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">false</property>

        <!-- auto commit -->
        <!-- <property name="connection.autocommit">true</property> -->

        <!-- configuration pool via c3p0 -->
        <property name="c3p0.idleConnectionTestPeriod">1000</property>
        <property name="c3p0.initialPoolSize">5</property>
        <property name="c3p0.maxPoolSize">10</property>
        <property name="c3p0.maxIdleTime">1</property>
        <property name="c3p0.maxStatements">30</property>
        <property name="c3p0.minPoolSize">1</property>

        <property name="cache.use_query_cache">true</property>
        <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
        <property name="cache.use_second_level_cache">true</property>

編輯:我正在使用以下代理來管理所有事務:

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;


/**
 * http://stackoverflow.com/questions/2587702
 * 
 * @author mohammad_abdullah
 */
public class ServiceProxy implements InvocationHandler {

    private Object object;
    private Logger logger = Logger.getLogger(this.getClass().getSimpleName());
    private static final String SESSION_FIELD = "session";

    public static final Map<Long, Transaction> ACTIVE_TRANSACTIONS = new HashMap<Long, Transaction>();

    private ServiceProxy(Object object) {
        this.object = object;
    }

    public static Object newInstance(Object object) {
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new ServiceProxy(object));
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object result = null;
        Session session = null;
        boolean joined = false;
        try {
            if (Modifier.isPublic(method.getModifiers())) {

                session = HibernateUtil.getSessionFactory().getCurrentSession();

                Field sessionField = object.getClass().getSuperclass().getDeclaredField(SESSION_FIELD);
                if (sessionField == null)
                    throw new UPSAdminException("Service Implementation should have field named: \"" + SESSION_FIELD + "\".");
                sessionField.setAccessible(true);
                sessionField.set(object, session);

                if (session.getTransaction().isActive()) {
                    joined = true;
                    logger.info("Using Already Active transaction" + " Method: " + method.getName() + " Thread: "
                            + Thread.currentThread().getId());
                    ACTIVE_TRANSACTIONS.put(Thread.currentThread().getId(), session.getTransaction());
                } else {
                    logger.info("Transaction Began" + " Method: " + method.getName() + " Thread: " + Thread.currentThread().getId());
                    Transaction newTnx = session.beginTransaction();
                    ACTIVE_TRANSACTIONS.put(Thread.currentThread().getId(), newTnx);
                }
                result = method.invoke(object, args);

                if (!joined) {
                    ACTIVE_TRANSACTIONS.get(Thread.currentThread().getId()).commit();
                    ACTIVE_TRANSACTIONS.remove(Thread.currentThread().getId());
                    logger.info("Transaction Commited" + " Method: " + method.getName() + " Thread: " + Thread.currentThread().getId());
                }
            } else {
                result = method.invoke(object, args);
            }

            return result;

        } catch (InvocationTargetException _ex) {
            Throwable cause = _ex.getCause();
            logger.severe("Caller Exception: " + cause + " Method: " + method.getName() + " Thread: " + Thread.currentThread().getId());

            if (!joined && session != null && session.getTransaction().isActive()) {
                ACTIVE_TRANSACTIONS.get(Thread.currentThread().getId()).rollback();
                ACTIVE_TRANSACTIONS.remove(Thread.currentThread().getId());
            }

            if (cause instanceof HibernateException) {
                logger.severe("Hibernate Error. Rollbacked Back. Method: " + method.getName() + " Thread: "
                        + Thread.currentThread().getId());
                throw new DBException(cause.getCause().getMessage());

            } else if (cause instanceof SetRollbackException) {
                logger.severe("Transaction marked for Rollback. Rollbacked Back. Method: " + method.getName() + " Thread: "
                        + Thread.currentThread().getId());
                return result;

            } else {
                logger.severe("Error in Business Method : " + method + ". Rollbacked Back." + " Thread: " + Thread.currentThread().getId());
                throw cause;
            }
        } catch (Exception ex) {
            logger.severe("Error in Proxy code :" + ex + " Method :" + method + " Thread: " + Thread.currentThread().getId());

            if (!joined && session != null && session.getTransaction().isActive()) {
                ACTIVE_TRANSACTIONS.get(Thread.currentThread().getId()).rollback();
                ACTIVE_TRANSACTIONS.remove(Thread.currentThread().getId());
            }

            if (ex instanceof HibernateException)
                throw new DBException(ex.getCause().getMessage());

            throw ex;
        }
    }
}

由於您已經創建了一個大小為5的連接池,對於並發事務,它應該運行沒有很多問題。 createQuery()方法更新臟持久性對象,該對象需要在事務內運行。 我認為這就是您出錯的原因。

當涉及到事務和連接時 ,每個事務都必須擁有一個連接,但是由於連接是池化的,因此如果事務處於等待狀態,它將把連接釋放回池中。 如果有太多的並發事務,並且連接數較少,則會延遲處理。 對於長時間的交易,甚至有可能出現死鎖等問題。

您可以在鏈接中找到用於事務上下文會話的休眠API。

您是否測試beginTransaction()成功?

您在釋放池后是否關閉連接而沒有等待池自動關閉?

來自http://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html的示例:

Session sess = factory.openSession();
Transaction tx;
try {
   tx = sess.beginTransaction();
   //do some work
   ...
   tx.commit();
}
catch (Exception e) {
   if (tx!=null) tx.rollback();
      throw e;
   }
finally {
   sess.close();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM