Je dois m'assurer que de nombreux utilisateurs simultanés puissent accéder à la base de données. Bien que, après chaque validation, je ferme la session mais parfois mon code rencontre l'erreur suivante, mais lorsque je fais la même opération plusieurs fois, l'erreur est dépassée et fonctionne.
Mon hibernation est 4.2.1.Final
Messages:
nested transactions not supported
File: org/hibernate/engine/transaction/spi/AbstractTransactionImpl.Java
Line number: 152
Mon code
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();
}
}
}
Configuration
<?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>
Dans votre extrait de code "Mon code", il peut y avoir des problèmes:
finally
pour fermer la session.session.close()
, mais cela diffère de HibernateUtils.closeSession()
. Donc, la ThreadLocal
n'est pas effacée.catch
pour les exceptions; en conséquence, il n'y a pas rollback
.S'il existe une exception dans le bloc "à faire" après begin()
, la transaction reste ouverte et ThreadLocal
n'est pas effacé.
Votre code peut fonctionner correctement normalement, mais sous une charge élevée, il peut y avoir des délais d'attente (verrouillage SQL), etc., et dans ce cas, une exception est occasionnelle.
Vérifiez donc chaque extrait pour corriger le traitement des exceptions:
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();
}
Vous pouvez ajouter du code "comptable" à HibernateUtil.getSession()
et HibernateUtil.closeSession()
: enregistrez chaque accès, y compris le nom du fil de discussion. Finalement, un ou plusieurs "obtient" par le même fil doivent être suivis d'un "fermer".
Dans votre cas, j’envisagerais même d’avoir un seul "get" et de passer la session aussi longtemps que votre thread accomplit son unité de travail: De cette façon, il est probablement plus facile de trouver le problème.
Une autre question sur SO signale un problème similaire: Hibernate 4.1.9 (dernière version finale) signalant `les transactions imbriquées non prises en charge .
Vous pouvez ajouter du code après commit()
pour vérifier si la transaction est vraiment terminée (en appelant wasCommitted()
).
Une citation de la Javadoc de wasCommitted()
:
Cette méthode peut retourner false même après un appel réussi de commit (). À titre d'exemple, les stratégies basées sur JTA ne fonctionnent pas sur les appels de commit () si elles n'ont pas démarré la transaction; dans ce cas, ils signalent également wasCommitted () comme faux.
Vous avez probablement déjà commencé une transaction et essayé d’en commencer une autre sans avoir validé ou annulé la précédente. L'idiome utilisé lors de l'utilisation de la démarcation programmatique de transaction est le suivant:
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
... to do ....
transaction.commit();
}
catch (RuntimeException e) {
transaction.rollback();
throw e;
}
Ajoutez la propriété suivante dans votre fichier Hibernate.cfg.xml
<prop key="hibernate.current_session_context_class">thread</prop>
Utilisez session.beginTransaction () au lieu de session.getTransaction (). Begin () dans votre code. Vous devez commencer une nouvelle unité de travail, donc beginTransaction commencera une nouvelle transaction . Votre code ressemblera à ceci:
session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
... to do ....
transaction.commit();
Cliquez sur ici pour obtenir plus d'informations sur beginTransaction (); méthode.
Je pense que cela résoudra votre problème. S'il vous plaît laissez-moi savoir si le problème persiste.
Je faisais face au même problème, j'ai résolu mon problème en mettant tr.commit (); fonction après chaque transaction ..___ Cela ne se produit que lorsque vous démarrez une transaction sans fermer la transaction précédente.
session = HibernateUtil.getSession();
session.getTransaction().begin(); OR session.beginTransaction();
... to do ....
session.getTransaction().commit();
session.close(); OR HibernateUtil.closeSession();
On dirait que vous faites aussi la même erreur.
J'ai rencontré un problème similaire: Org.hibernate.TransactionException: transactions imbriquées non prises en charge
Dans mon cas, j'ai ouvert une session et essayé de sauvegarder. Sans commit, j'ai appelé une autre méthode et appelé session.beginTransaction (); Ainsi, il renvoie l'erreur . Afin d'éviter, j'ai envoyé l'objet de session en tant que paramètre de méthode et appelé simplement session.save au lieu de nouveau faire commence. Pratiquement utilisé l'objet de session . Cela a fonctionné pour moi!