2010-03-08 36 views
6

Chúng tôi có một số đậu EJB không trạng thái JavaEE5 chuyển EntityManager được tiêm vào người trợ giúp của nó.Bạn có thể truyền EntityManagers được tiêm vào các lớp trợ giúp của bean EJB và sử dụng nó không?

Điều này có an toàn không? Nó đã làm việc tốt cho đến bây giờ, nhưng tôi phát hiện ra một số tài liệu Oracle cho biết việc thực hiện EntityManager của nó là an toàn luồng. Bây giờ tôi tự hỏi liệu lý do chúng tôi đã không có vấn đề cho đến bây giờ, chỉ là vì việc thực hiện chúng tôi đã sử dụng đã xảy ra để được thread-an toàn (chúng tôi sử dụng Oracle).

@Stateless 
class SomeBean { 
    @PersistenceContext 
    private EntityManager em; 

    private SomeHelper helper; 

    @PostConstruct 
    public void init(){ 
     helper = new SomeHelper(em); 
    } 

    @Override 
    public void business(){ 
     helper.doSomethingWithEm(); 
    } 

} 

Trên thực tế nó làm cho tinh thần .. Nếu EntityManager là thread-an toàn, một container sẽ phải làm

inercept business() 
this.em = newEntityManager(); 
business(); 

mà sẽ không lan truyền đến lớp helper của nó.

Nếu vậy, thực hành tốt nhất trong loại tình huống này là gì? Chuyển EntityManagerFactory thay vì EntityManager?

EDIT: This question là rất thú vị vì vậy nếu bạn quan tâm đến câu hỏi này, có lẽ bạn muốn kiểm tra thế này, quá:

EDIT: Thông tin thêm. Instances ejb3.0 spec

4.7.11 Non-reentrant Các thùng chứa phải đảm bảo rằng chỉ có một chủ đề có thể được thực hiện một thể hiện tại bất cứ lúc nào. Nếu yêu cầu của khách hàng đến cho một trường hợp trong khi phiên bản là thực hiện một yêu cầu khác, thùng chứa có thể ném javax.ejb.ConcurrentAccessException đến ứng dụng thứ hai [24]. Nếu quan điểm của khách hàng EJB 2.1 được sử dụng, bình chứa có thể ném java.rmi.RemoteException để yêu cầu thứ hai nếu khách hàng là một khách hàng từ xa , hoặc javax.ejb.EJBException nếu khách hàng là một địa phương khách hàng. [25] Lưu ý rằng đối tượng phiên nhằm hỗ trợ chỉ một khách hàng. Do đó, sẽ là lỗi ứng dụng nếu hai khách hàng cố gắng gọi cùng một đối tượng phiên . Một ngụ ý của quy tắc này là một ứng dụng không thể thực hiện cuộc gọi lặp lại đến phiên bản bean phiên .

Và,

4.3.2 Dependency Injection Một session bean có thể sử dụng dependency injection cơ chế để có được tài liệu tham khảo để tài nguyên hoặc các đối tượng khác trong môi trường của nó (xem Chương 16, “Môi trường đậu doanh nghiệp”). Nếu một bean phiên sử dụng phụ thuộc tiêm, vùng chứa sẽ tiêm các tài liệu này sau khi cá thể đậu là được tạo và trước khi bất kỳ phương thức kinh doanh nào được gọi trên cá thể .Nếu phụ thuộc vào SessionContext được khai báo hoặc nếu lớp bean triển khai tùy chọn giao diện SessionBean (xem Phần 4.3.5), thì SessionContext cũng sẽ được tiêm vào lúc này. Nếu phụ thuộc không thành công, phiên bản bean được bị loại bỏ. Trong API EJB 3.0, lớp bean có thể có được giao diện SessionContext qua tiêm phụ thuộc mà không cần phải triển khai giao diện SessionBean. Trong trường hợp này, chú thích Tài nguyên (hoặc triển khai tài nguyên-env-ref phần tử mô tả) được sử dụng để biểu thị sự phụ thuộc của bean trên SessionContext. Xem Chương 16, “Môi trường đậu công nghiệp”.

+0

Bây giờ điều này thật thú vị "Thông số EJB 3.1 cho biết việc tiêm phụ thuộc chỉ được thực hiện vào thời gian xây dựng, để tất cả người gọi của MyRepository sẽ sử dụng cùng một phiên bản EntityManager." : http: //stackoverflow.com/questions/2015184/how-is-threadsafty-guranteed-with-persistencecontext –

+0

FYI, đọc thêm § 4.1.13 hoặc xem câu trả lời http: // stackoverflow này.com/questions/1954137/how-is-that-instance-pooling-with-ejbs-can-improve-performance/1954229 # 1954229. Vì vậy, mỗi người trợ giúp sẽ được truy cập bởi một luồng tại một thời điểm. – ewernli

+0

Đây chính là mẫu mà tôi đang nghĩ đến việc triển khai. Tôi rất vui khi thấy rằng điều đó là có thể. Bài đăng tuyệt vời. Cảm ơn. – b3bop

Trả lời

2

Tôi đã sử dụng một mẫu tương tự, nhưng trình trợ giúp đã được tạo trong @PostConstruct và trình quản lý thực thể được tiêm được truyền trong hàm tạo làm tham số. Mỗi cá thể EJB có helper và thread-safety của riêng nó đều được đảm bảo.

Tôi cũng đã có một biến thể là người quản lý thực thể không được tiêm (vì EJB không sử dụng nó hoàn toàn), do đó người trợ giúp phải tra cứu với InitialContext. Trong trường hợp này, bối cảnh Persistence vẫn phải được "nhập khẩu" trong EJB mẹ với @PersistenceContext:

@Stateless 
@PersistenceContext(name="OrderEM") 
public class MySessionBean implements MyInterface { 
    @Resource SessionContext ctx; 
    public void doSomething() { 
    EntityManager em = (EntityManager)ctx.lookup("OrderEM"); 
    ... 
    } 
} 

Nhưng nó thực sự dễ dàng hơn để bơm nó (ngay cả khi EJB không sử dụng nó) hơn là nhìn nó lên , đặc biệt là cho testability.

Nhưng để quay trở lại câu hỏi chính của bạn, tôi nghĩ rằng người quản lý thực thể được tiêm hoặc tra cứu là một trình bao bọc chuyển tiếp đến người quản lý thực thể hoạt động cơ bản bị ràng buộc với giao dịch.

Hy vọng điều đó sẽ hữu ích.

EDIT

Phần § 3.3 và 5.6 § trong spec trang trải một chút chủ đề.

+0

Cảm ơn, tôi rất vui khi biết rằng chúng tôi không phải đào sâu mã sản xuất của chúng tôi! –

2

Tôi đã sử dụng trợ giúp phương pháp và thông qua EntityManager ở đó và hoàn toàn OK. Vì vậy, tôi khuyên bạn nên chuyển nó đến các phương pháp bất cứ khi nào cần thiết, hoặc tự làm cho người trợ giúp một hạt, bơm nó (sử dụng @EJB) và tiêm EntityManager ở đó.

+0

Các phương thức trợ giúp nghe rất đơn giản và tốt. Cảm ơn! –

0

Vâng, cá nhân, tôi không muốn phải chuyển Trình quản lý thực thể tới tất cả POJO của tôi trong các phương thức hoặc phương thức của tôi. Đặc biệt là cho các chương trình không tầm thường, nơi số lượng POJOs lớn.

Tôi sẽ cố gắng tạo POJOs/HelperClasses để xử lý các thực thể được EntityManager trả về, thay vì sử dụng trực tiếp entitymanager.

Nếu không thể, tôi đoán tôi sẽ tạo một EJB Bean mới.

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