2010-07-09 36 views
10

Tôi đang lập trình một ứng dụng web bằng cách sử dụng weblogic và oracle. nguồn dữ liệu được định cấu hình thông qua JNDI, với người dùng cơ sở dữ liệu bị hạn chế có thể DML vào bảng, nhưng không thể DDL. Như bạn có thể đoán, người dùng đó không phải là chủ sở hữu của những bảng đó, nhưng anh ấy được cấp quyền truy cập.JPA - EclipseLink - Cách thay đổi lược đồ mặc định

Giả sử anh ấy là GUEST_USER

Ứng dụng đang sử dụng JPA + EclipseLink và có nhiều thực thể đã được xác định. Tôi không muốn viết trong mỗi một lớp thực thể thuộc tính để thay đổi lược đồ. Tôi đã thử một SessionCustomizer, với mã này.

public class MyCustomizer implements SessionCustomizer{ 

    @Override 
    public void customize(Session session) throws Exception { 

    session.executeNonSelectingSQL("ALTER SESSION SET CURRENT_SCHEMA = OWNERS_SCHEMA"); 
    } 
} 

Dường như có điều gì đó không được khởi động, tôi nhận được ngoại lệ con trỏ null, tôi thậm chí không chắc chắn đây có phải là cách thay đổi lược đồ cho các kết nối trước khi chúng được sử dụng hay không. Bất kỳ mẫu hoặc ý tưởng nào?

Cảm ơn trước sự giúp đỡ của bạn!

Trả lời

16

Nếu tất cả các thực thể sử dụng cùng một lược đồ, bạn có thể sử dụng tệp ánh xạ xml để xác định lược đồ mặc định.

Something như thế này nên làm việc (ví dụ là cho JPA 2.0, thay đổi schemaLocation cho 1.0)

orm.xml:

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd" 
    version="2.0"> 
    <persistence-unit-metadata> 
     <persistence-unit-defaults> 
      <schema>OWNERS_SCHEMA</schema> 
     </persistence-unit-defaults> 
    </persistence-unit-metadata> 
    . . . 
</entity-mappings> 

persistence.xml:

<persistence 
    xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" 
    version="2.0" > 
    <persistence-unit name="foo"> 
     . . . 
     <mapping-file>orm.xml</mapping-file> 
     . . . 
    </persistence-unit> 
</persistence> 
+0

+1 Điều này nghe tốt –

+2

điều này là tốt nhưng vẫn không năng động, nếu tôi cần lược đồ thay đổi cho hai phiên bản của cùng một ứng dụng trỏ đến hai trường hợp db khác? –

+0

Hơn nữa, nếu tôi đặt lược đồ cho một EntityManager cụ thể với 'SET search_path TO ...', chuyển trình quản lý thực thể sang các phương thức khác không có hiệu ứng. Tôi cho rằng Wildfly (trong trường hợp của tôi) có một trong các kết nối của hồ bơi trước đó được tạo ra với lược đồ mặc định công cộng – Chris

3

Bạn có thể làm điều đó theo chương trình. Bạn có thể cấu hình giá trị lược đồ mặc định cho mỗi phiên.

public class MySessionCustomizer implements SessionCustomizer { 

    private static String schemaName; 

    public static void setSchemaName(String schemaName) { 
     MySessionCustomizer.schemaName = schemaName; 
    } 

    @Override 
    public void customize(Session session) throws Exception { 
     if (StringUtils.hasText(this.schemaName)) { 
      session.getLogin().setTableQualifier(this.schemaName); 
     } 
    } 
} 

Sau đó thiết lập các tùy biến phiên để tính nhà máy quản lý thực thể:

PersistenceUnitProperties.SESSION_CUSTOMIZER 

ví dụ

propertiesMap.put(PersistenceUnitProperties.SESSION_CUSTOMIZER, MySessionCustomizer.class.getName()); 
+1

Có cách nào để làm điều này theo tiêu chuẩn JPA không? –

+0

Cách tiêu chuẩn JPA đang sử dụng lược đồ tham số trong chú thích ['@ Table'] (http://docs.oracle.com/javaee/7/api/javax/persistence/Table.html) – Ati

0

tôi sử dụng EJB ngay trước khi truy vấn cơ sở dữ liệu, vì vậy bằng cách sử dụng Interceptors tôi có thể thiết lập các lược đồ trong bối cảnh EJB bằng cách xem người sử dụng chứng thực hiện hành.

Sau đó, khi tôi xây dựng trình quản lý đối tượng, tôi có thể đặt đúng lược đồ. Bằng cách này, bằng cách không chỉ định lược đồ trước tên bảng, PostgreSQL sẽ xem xét search_path để xác định lược đồ nào cần truy vấn.

<!-- language: lang-java --> 

public class Interceptor { 

    Logger logger = Logger.getLogger(Interceptor.class); 

    /** 
    * 
    * @param ctx is always null before being passed to EJB implementation. We always query database 
    * for populating context data, making user's session accessible to all EJB implementations 
    * @return 
    * @throws Exception 
    */ 
    @SuppressWarnings({ "unchecked", "unused" }) 
    @AroundInvoke 
    public Object intercept(InvocationContext ctx) throws Exception { 
     Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 

     String ejbName = ctx.getMethod().getDeclaringClass().getSimpleName(); 
     String methodName = ctx.getMethod().getName(); 
     Boolean override_schema = false; 
     String overridden_schema = ""; 

     logger.info("Intercepting " + ejbName + "." + methodName); 

     if(auth != null) { 

      UserDetails userDetails = (UserDetails)auth.getPrincipal(); 
      String username = userDetails.getUsername(); 

      Collection<SimpleGrantedAuthority> permList = (Collection<SimpleGrantedAuthority>) auth.getAuthorities(); 
      List<String> permissions = new ArrayList<String>(); 

      for (SimpleGrantedAuthority authority : permList) { 
       permissions.add(authority.getAuthority()); 
      } 


      Query query = getMasterEntityManager() 
          .createNativeQuery(
       "SQL for retrieving the schema by the current logged in user"); 

      query.setParameter("username", username); 
      List<Object[]> result = null; //query.getResultList(); 

      if(result != null) { 
       logger.info("Interceptor: context set for " + username); 
       Object[] userObj = result.get(0); 

       getContext().getContextData().put("username", username); 
       getContext().getContextData().put("schema_name",(String)userObj[1]); 
      } 
     } 

     return ctx.proceed(); 
     } 
    } 

Sau đó, khi bạn tạo người quản lý thực thể, bạn có thể đặt giản đồ bạn muốn.

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