hibernate - transacción - ¿Cómo evitar transacciones anidadas no soportadas error?
transacciones sql server (4)
En tu fragmento de código "Mi código", puede haber algunos problemas:
- En caso de una excepción, no hay un bloque final para cerrar la sesión
- Está llamando a
session.close()
, pero esto es diferente deHibernateUtils.closeSession()
. Así que elThreadLocal
no se borra. - No hay bloque de
catch
para excepciones; como consecuencia no hayrollback
. - ¿Vuelve a hacer excepciones o son ignoradas (en silencio)?
Si hay una excepción en el bloque "para hacer" después de begin()
, la transacción permanece abierta y ThreadLocal
no se borra.
Su código puede funcionar bien normalmente, pero bajo una carga alta puede haber tiempos de espera (bloqueo de SQL), etc., y en este caso, de vez en cuando, se lanzará una excepción.
Así que revise cada fragmento de código para el correcto manejo de excepciones:
final Session session = HibernateUtil.getSession();
try {
final Transaction transaction = session.beginTransaction();
try {
// The real work is here
transaction.commit();
} catch (Exception ex) {
// Log the exception here
transaction.rollback();
throw ex;
}
} finally {
HibernatilUtil.closeSession();
}
Puede agregar algún código de "contabilidad" a HibernateUtil.getSession()
y HibernateUtil.closeSession()
: Registre cada acceso, incluido el nombre del hilo. Finalmente, uno o varios "get" por el mismo hilo deben ir seguidos de un "close".
En su caso, incluso consideraría tener un solo "get", y transmitir la sesión siempre y cuando su hilo esté haciendo su unidad de trabajo: de esta manera posiblemente sea más fácil encontrar el problema.
Hay otra pregunta en SO que informa un problema similar: Hibernate 4.1.9 (última compilación final) que informa sobre transacciones anidadas no admitidas .
Puede agregar algo de código después de commit()
para verificar, si la transacción se ha completado realmente (llamando a wasCommitted()
).
Una cita del Javadoc de wasCommitted()
:
Este método podría devolver falso incluso después de una invocación exitosa de commit (). Como ejemplo, las estrategias basadas en JTA no-op en las llamadas commit () si no iniciaron la transacción; en ese caso, también informaron que wasCommitted () como falso.
Necesito asegurarme de que muchos usuarios simultáneos puedan acceder a la base de datos. Aunque después de cada confirmación, cierro la sesión, pero a veces mi código se ejecuta en el siguiente error, pero cuando hago la misma operación varias veces, supera el error y funciona.
Mi hibernación es 4.2.1.Final
Messages:
nested transactions not supported
File: org/hibernate/engine/transaction/spi/AbstractTransactionImpl.java
Line number: 152
Mi código
session = HibernateUtil.getSession();
session.getTransaction().begin(); OR session.beginTransaction();
... to do ....
session.getTransaction().commit();
session.close(); OR HibernateUtil.closeSession();
HibernateUtil
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
public class HibernateUtil {
private static ServiceRegistry serviceRegistry;
private static final ThreadLocal<Session> threadLocal = new ThreadLocal();
private static SessionFactory sessionFactory;
private static SessionFactory configureSessionFactory() {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
} catch (HibernateException e) {
System.out.append("** Exception in SessionFactory **");
e.printStackTrace();
}
return sessionFactory;
}
static {
try {
sessionFactory = configureSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
private HibernateUtil() {
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession() throws HibernateException {
Session session = threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession() : null;
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory() {
try {
sessionFactory = configureSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
}
Configuración
<?xml version=''1.0'' encoding=''utf-8''?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/MyProject
</property>
<property name="connection.username">root</property>
<property name="connection.password"></property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">12</property>
<!-- SQL dialect -->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!-- Enable Hibernate''s automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">
org.hibernate.cache.NoCacheProvider
</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<mapping class="com.project.common.Project" />
<mapping class="com.project.common.School" />
<mapping class="com.project.common.Address" />
<mapping class="com.project.common.Female" />
<mapping class="com.project.common.Male" />
<mapping class="com.project.common.Credential" />
<mapping class="com.project.common.Users" />
</session-factory>
</hibernate-configuration>
Estaba enfrentando el mismo problema, resolví mi problema poniendo tr.commit (); función después de cada transacción. Ocurre solo cuando inicia una transacción sin cerrar la transacción anterior.
session = HibernateUtil.getSession();
session.getTransaction().begin(); OR session.beginTransaction();
... to do ....
session.getTransaction().commit();
session.close(); OR HibernateUtil.closeSession();
Parece que también estás haciendo el mismo error.
Probablemente haya iniciado una transacción e intente iniciar otra sin haber confirmado o revertido la anterior. La expresión idiomática cuando se usa la demarcación de transacción programática es la siguiente:
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
... to do ....
transaction.commit();
}
catch (RuntimeException e) {
transaction.rollback();
throw e;
}
Agregue la siguiente propiedad en su Hibernate.cfg.xml
<prop key="hibernate.current_session_context_class">thread</prop>
Use session.beginTransaction () en lugar de session.getTransaction (). Begin () en su código. Debe comenzar una nueva unidad de trabajo, por lo que beginTransaction comenzará una nueva transacción. Entonces tu código se verá como:
session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
... to do ....
transaction.commit();
Haga clic Here para obtener más información sobre beginTransaction (); método.
Creo que eso resolverá tu problema. Por favor, hágamelo saber si el problema persiste.