2010-09-14 33 views
7

Tôi đang làm việc trên một ứng dụng cần thực hiện một số thao tác cơ sở dữ liệu.Cách tạo chủ đề an toàn EntityManagerFactory?

Tôi tạo ra một biến tĩnh cho EntityManagerFactory và Intialized nó trong phương pháp đó được gọi bằng các ứng dụng

if (emf == null){ 
        emf = Persistence.createEntityManagerFactory("example"); 
       } 

try { 
      em = emf.createEntityManager(); 
     } catch (Exception ex) { 
      logger.error(ex.getMessage()); 
     } 

là chủ đề này an toàn không? nếu tôi tạo EntityManagerFactory trong một khối đã đồng bộ, số lượng các chủ đề chờ đợi sẽ tăng lên và làm treo ứng dụng.

Tôi đã xem các tài liệu để xem liệu Persistence.createEntityManagerFactory có phải là chủ đề an toàn không thành công hay không.

Vui lòng chỉ cho tôi các tài nguyên phù hợp.

Trả lời

11

Cách dễ dàng để "giải quyết" điều này là sử dụng lớp trợ giúp (a la HibernateUtil) và để khởi tạo EntityManagerFactory trong khối khởi tạo tĩnh. Một cái gì đó như thế này:

public class JpaUtil { 
    private static final EntityManagerFactory emf; 

    static { 
     try { 
      factory = Persistence.createEntityManagerFactory("MyPu"); 
     } catch (Throwable ex) { 
      logger.error("Initial SessionFactory creation failed", ex); 
      throw new ExceptionInInitializerError(ex); 
     } 
    } 

    ... 

} 

Và "sự cố" đã biến mất.

+0

Tôi đã làm điều đó trước đây. Tuy nhiên, một số người cảm thấy rằng nó không phải là một thực hành tốt để khởi tạo trong các khối tĩnh. Có đúng không? –

+1

@Vanchinathan Đó thực sự là một cách tiếp cận điển hình khi bạn không ở trong một môi trường được quản lý và tôi không thấy có điều gì sai trái với nó. Bây giờ, nếu bạn cung cấp một số tranh luận chống lại nó, chúng tôi có thể thảo luận về chúng nhưng cho đến lúc đó, tôi duy trì đề xuất này. –

+2

Một đối số mà tôi luôn nhận được là có mã trong các khối tĩnh, cản trở việc kiểm tra. Chúng tôi tuân thủ nghiêm ngặt việc phát triển Test Driven. Vì vậy, tôi cần một cái gì đó cũng dễ dàng hơn để kiểm tra. –

1

Bạn cần phải đặt khóa trên một đối tượng khi bạn đang tạo emf. Bạn có thể đặt khóa trên chính đối tượng emf, nhưng đó không phải là cách thực hành tốt nhất. Tạo một đối tượng khác:

private object factoryLockObject = new object(); 

và đặt ổ khóa của bạn trên đó trong khi tạo ra các nhà máy

lock(factoryLockObject) 
{ 
    if (emf == null) 
    { 
     emf = Persistence.createEntityManagerFactory("example"); 
    } 
} 

giúp đỡ đó?

+0

Điều gì tạo ra sự khác biệt? Tôi sẽ thử. –

+0

Điều này sẽ thêm một khóa đối tượng trên factoryLockObject và gây ra bất kỳ chủ đề nào khác muốn truy cập nó để chờ cho đến khi khóa được nâng lên (ở dấu ngoặc nhọn cuối cùng). http://csharpindepth.com/Articles/General/Singleton.aspx – Brad

+0

Tuy nhiên, nó sẽ không chặn các chủ đề? Nếu Persistence.createEntityManagerFactory ("example"); là chủ đề an toàn, sau đó tôi không cần phải đồng bộ hóa nó. –

1

createEntityManagerFactory() có an toàn hay không, bạn cần một số chiến lược để nó chỉ được gọi một lần. Nói cách khác, câu hỏi đó là không liên quan, bởi vì bạn phải đảm bảo rằng chỉ có một chủ đề gọi nó.

Nếu chỉ đơn giản là đợi một luồng khác để tạo nhà máy, ứng dụng của bạn sẽ xảy ra, điều gì sẽ xảy ra khi mỗi chuỗi tạo ra riêng của mình, clobbering công việc của các chủ đề khác trong quá trình?

Mã bạn hiển thị phải ở trong khối synchronized hoặc không phải là chuỗi an toàn.

+0

Không cần chiến lược chỉ gọi nhà máy một lần. Một tra cứu phải được thực hiện trong mọi trường hợp và mẫu Singleton sẽ đảm bảo xử lý cho cá thể hiện tại (một) luôn được trả về. Tất cả các chuỗi cuộc gọi sẽ nhận được cùng một tham chiếu đến cùng một nhà máy. Không cần phải đồng bộ hóa và bổ sung sẽ tạo ra một vấn đề hiệu suất như các chủ đề đang chiến đấu để đạt được màn hình chỉ được trả lại nhà máy xử lý một và chỉ anyway. –

+0

@ DarrellTeague Người gọi xác định xem nhà máy có được chia sẻ hay không và do đó, liệu người gọi đó có bị đóng bởi người gọi đó không? Theo OP, việc khởi tạo nhà máy tốn nhiều thời gian. Việc tạo ra nhiều cá thể không cần thiết trong suốt vòng đời của ứng dụng có vẻ là một vấn đề hiệu suất lớn hơn bất kỳ tranh chấp nào có thể xảy ra trong thời gian cần để đồng bộ hóa và đọc biến, khi được khởi tạo. – erickson

+0

Tôi đang sử dụng Persistence.createEntityManagerFactory (ID) như là một trường hợp tĩnh, số ít và nó là an toàn thread. Những gì phải được bảo vệ an toàn là các trường hợp của EntityManager từ EMF.createEntityManager(). Điều đó cần phải được bên trong một phương thức nhất định, sau đó tạo ra một giao dịch, cam kết nó và sau đó gọi close() trên EntityManager (giống như J2EE DataSource Connection.close() để giải phóng kết nối JDBC trở lại pool-manager). Đây là mô hình tương tự như tiền JPA với DataSource và kết nối JDBC thông qua một người quản lý nhóm. –

3

Tôi không thấy bất kỳ sự cố nào với phương pháp chặn tĩnh. Hoặc bạn có thể làm tương tự theo cách dưới đây mà là một mô hình với kích đúp khóa séc

public class JPAHelper { 

private static JPAHelper myHelper = new JPAHelper(); 
private static EntityManagerFactory myFactory = null; 

/** 
    * Private constructor. Implementing synchronization with double-lock check 
    */ 
private JPAHelper() { 

    if(myFactory == null) { 
    synchronized (JPAHelper.class) { 

    // This second check will be true only for the first thread entering the block incase 
    // of thread race 
    if(myFactory == null) { 
    myFactory = Persistence.createEntityManagerFactory("MyUnit"); 
    } 
    } 
    } 
} 

/** 
    * Static Accessor Method 
    * @return 
    */ 
public static JPAHelper getInstance() { 
    if(myHelper == null) { 
    myHelper = new JPAHelper(); 
    } 
    return myHelper; 
} 


public EntityManagerFactory getJPAFactory() { 
    return myFactory; 
} 

Và Singleton bạn sẽ gọi

EntityManager myManager = JPAhelper.getInstance().getJPAFactory().createEntityManager(); 
+0

Mẫu Singleton được khuyên dùng nhưng không cần (hoặc có hiệu lực) sử dụng khóa đã kiểm tra kép. createEntityManagerFactory() đã an toàn thread và sẽ trả về cùng một handle cho cùng một nhà máy trong mọi trường hợp. Một Singleton viết đúng cách tải nhà máy tĩnh sẽ luôn trả về một tay cầm. Khóa kiểm tra kép không hoạt động trong các hệ thống/thùng chứa ứng dụng trong thế giới thực. Xem phần này: [http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html](http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html) –

+0

Khóa kiểm tra kép Làm việc trong các ứng dụng trong thế giới thực. Đoạn mã trên nên khai báo myFactory là dễ bay hơi. Bài viết được tham chiếu tương tự giải thích "Sửa khóa kép được kiểm tra bằng cách sử dụng dễ bay hơi" – mcoolive

0

Câu trả lời cho câu hỏi là: CÓ, createEntityManagerFactory() an toàn chỉ dựa trên tài liệu lớp, nguồn và kết quả ứng dụng trong thế giới thực.

Câu trả lời mẫu Singleton là chính xác nhất để tránh cuộc gọi bổ sung để truy xuất một bộ xử lý một cách hiệu quả nhưng lưu ý không cần khóa kiểm tra kép như đã nhận xét trước đó.