2013-07-09 53 views
20

Tôi cần đảm bảo nhiều người dùng đồng thời có thể truy cập cơ sở dữ liệu. Mặc dù sau mỗi lần commit tôi đóng phiên nhưng đôi khi mã của tôi chạy vào lỗi sau, nhưng khi tôi thực hiện thao tác tương tự trong vài lần, nó vượt qua lỗi và hoạt động.Làm cách nào để tránh lỗi giao dịch lồng nhau không được hỗ trợ?

ngủ đông của tôi là 4.2.1.Final

Messages: 
nested transactions not supported 
File: org/hibernate/engine/transaction/spi/AbstractTransactionImpl.java 
Line number: 152 

Mã My

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(); 
    } 
    } 
} 

Cấu hình

<?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> 
+0

Trông giống như một mối nguy hiểm đối với tôi; có nhiều cạm bẫy để viết các giao dịch phạm vi 'ThreadLocal' của riêng bạn. Tôi khuyên bạn nên viết mã quản lý phiên của riêng mình, sử dụng một trong các ['CurrentSessionContext'] (http://docs.jboss.org/hibernate/orm/3.6/javadocs/org/hibernate/context/CurrentSessionContext.html) triển khai được cung cấp. –

+0

bạn có biết ví dụ nào không? –

+0

Có thể bắt đầu với [tài liệu] (http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/architecture.html#architecture-current-session). –

Trả lời

25

của bạn Trong "Mã của tôi" đoạn mã của bạn, có thể có một số vấn đề :

  1. trong trường hợp ngoại lệ, không có finally khối để đóng phiên
  2. Bạn đang mô sẹo ng session.close(), nhưng điều này khác với HibernateUtils.closeSession(). Vì vậy, ThreadLocal không bị xóa.
  3. Không có khối catch cho trường hợp ngoại lệ; kết quả là không có rollback.
  4. Bạn có rút lại ngoại lệ hay không (âm thầm) bị bỏ qua?

Nếu có ngoại lệ trong khối "cần làm" sau begin(), giao dịch vẫn mở và ThreadLocal không bị xóa.

Mã của bạn có thể hoạt động bình thường, nhưng dưới tải cao có thể có thời gian chờ (khóa SQL) vv, và trong trường hợp này, thỉnh thoảng, một ngoại lệ sẽ được ném.

Vì vậy, kiểm tra mỗi đoạn cho xử lý ngoại lệ chính xác:

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(); 
} 

Bạn có thể thêm một số "sổ sách kế toán" mã để HibernateUtil.getSession()HibernateUtil.closeSession(): Đăng nhập mỗi truy cập, trong đó có tên của chủ đề . Cuối cùng một hoặc nhiều "được" bởi cùng một chủ đề phải được theo sau bởi một "đóng".

Trong trường hợp của bạn, tôi thậm chí sẽ xem xét chỉ có một "nhận" và chuyển phiên xung quanh miễn là chuỗi của bạn đang thực hiện đơn vị công việc: Bằng cách này, việc tìm sự cố có thể dễ dàng hơn.


Có một câu hỏi khác về SO báo cáo vấn đề tương tự: Hibernate 4.1.9 (latest final build) reporting `nested transactions not supported.

Bạn có thể thêm một số mã sau commit() để kiểm tra, nếu giao dịch đã được thực sự hoàn thành (bằng cách gọi wasCommitted()).

Một trích dẫn từ Javadoc của wasCommitted():

Phương pháp này có thể trở lại sai ngay cả sau khi gọi thành công cam kết(). Ví dụ, chiến lược dựa trên JTA no-op trên commit() gọi nếu chúng không bắt đầu giao dịch; trong trường hợp đó, họ cũng báo cáo isCommitted() là sai.

+1

Cảm ơn câu hỏi được cập nhật, –

+0

cảm ơn câu trả lời của bạn, bạn có nghĩ rằng các cài đặt hiện tại của tôi đủ để xử lý số lượng người dùng lớn không? –

+0

@ Moor Moorido Vấn đề chính của bạn có được giải quyết không? Bạn chưa chọn câu trả lời. Dù sao thì cũng khó để biết cài đặt của bạn có phù hợp với một số lượng lớn người dùng hay không. Bạn nên thiết lập một thử nghiệm với số lượng người dùng đồng thời khác nhau. – Beryllium

5

Sử dụng session.beginTransaction() thay vì session.getTransaction(). Begin() trong mã của bạn. Bạn cần bắt đầu một đơn vị công việc mới, vì vậy beginTransaction sẽ bắt đầu một giao dịch mới. Vì vậy, mã của bạn sẽ trông giống như:

session = HibernateUtil.getSession(); 
Transaction transaction = session.beginTransaction(); 
     ... to do .... 
transaction.commit(); 

Bấm Here để có thêm thông tin về beginTransaction(); phương pháp.

Tôi nghĩ điều đó sẽ giải quyết được vấn đề của bạn. Vui lòng cho tôi biết nếu sự cố vẫn tiếp diễn.

+1

Câu hỏi cảm ơn được cập nhật –

13

Bạn có thể đã bắt đầu một giao dịch và cố gắng bắt đầu một giao dịch khác mà không phải cam kết hoặc hoàn vốn trước đó. Các thành ngữ khi sử dụng ranh giới giao dịch có lập trình là một trong những sau:

Transaction transaction = null; 
    try { 
     session = HibernateUtil.getSession(); 
     transaction = session.beginTransaction(); 
     ... to do .... 
     transaction.commit(); 
    } 
    catch (RuntimeException e) { 
     transaction.rollback(); 
     throw e; 
    } 

Thêm thuộc tính sau đây trong hibernate.cfg.xml

<prop key="hibernate.current_session_context_class">thread</prop> 
+0

Câu hỏi cảm ơn được nâng lên –

+0

Có nhu cầu của chủ đề địa phương .... ?? – MayurB

+0

Tôi nghĩ tôi cần, bạn có biết những ưu và nhược điểm của nó không? –

Các vấn đề liên quan