2010-07-09 77 views
10

我正在使用weblogic和oracle編寫Web應用程序。 數據源通過JNDI進行配置,具有可以將DML轉換爲表但不能DDL的受限數據庫用戶。您可能會猜到,該用戶不是這些表的所有者,但他已被授予訪問權限。JPA - EclipseLink - 如何更改默認架構

比方說,他是GUEST_USER

應用程序使用JPA +的EclipseLink,並有大量已定義的實體。我不想在每個實體類中寫入屬性來更改模式。 我試過了一個SessionCustomizer和這段代碼。

public class MyCustomizer implements SessionCustomizer{ 

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

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

,似乎有什麼東西uninitiallized,我得到一個空指針異常,我甚至不知道這是要改變架構的連接在使用之前的方式。 任何樣品或想法?

在此先感謝您的幫助!

回答

16

如果所有實體都使用相同的模式,則可以使用xml映射文件來定義默認模式。

像這樣的東西應該工作(例如是JPA 2.0,更改爲1.0的schemaLocation)

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這聽起來不錯 – 2010-07-11 11:24:45

+2

這是好的,但仍然不動態,如果我需要更改同一應用程序的兩個版本的模式指向兩個diff數據庫實例,該怎麼辦? – 2014-05-28 19:39:00

+0

此外,如果我使用'SET search_path TO ...'設置特定EntityManager的模式,將實體管理器傳遞給其他方法沒有任何影響。我想Wild野(在我的情況下)採用之前創建的公共默認模式池之一的連接 – Chris 2016-02-04 09:10:22

3

你可以以編程方式進行。您可以爲每個會話配置默認架構值。

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

然後設置會話定製到實體管理器工廠性能:

PersistenceUnitProperties.SESSION_CUSTOMIZER 

例如

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

是否有JPA標準的方式來做到這一點? – 2015-08-25 13:22:37

+0

JPA標準方法在註釋['@ Table'](http://docs.oracle.org/)中使用參數模式。COM/JavaEE的/ 7/API /的javax /持久/ Table.html) – Ati 2016-03-13 13:56:49

0

我用EJB權查詢數據庫之前,所以通過使用Interceptors我能夠通過查看當前已驗證用戶設置的EJB環境的模式。

然後,當我建立實體管理器時,我可以設置正確的模式。通過這種方式,通過在表名之前不指定模式,PostgreSQL將查看search_path以確定要查詢的模式。

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

然後當你建立實體管理器時,你可以設置你想要的模式。