Java JPA - EclipseLink - 如何更改默认架构

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3211138/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 17:27:09  来源:igfitidea点击:

JPA - EclipseLink - How to change default schema

javaoraclejpaschemaeclipselink

提问by mrzmont

I'm programming a web application using weblogic and oracle. the datasource is configured through JNDI, with a restricted database user who can DML into tables, but can't DDL. As you may guess, that user isn't the owner of those tables, but he's granted access.

我正在使用 weblogic 和 oracle 编写一个 web 应用程序。数据源是通过 JNDI 配置的,具有可以 DML 到表中,但不能 DDL 的受限数据库用户。您可能会猜到,该用户不是这些表的所有者,但他被授予访问权限。

Let's say he is GUEST_USER

假设他是 GUEST_USER

The application is using JPA + EclipseLink, and have lots of entities already defined. I don't want to write in each an every entity class the attribute to change schema. I've tried a SessionCustomizer, with this code.

该应用程序使用 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");
    }
}

It seems that there's something uninitiallized, I'm getting a null pointer exception, I'm not even sure if this is the way to change the schema for the connections before they are used. Any samples or ideas?

似乎有一些未初始化的东西,我收到了一个空指针异常,我什至不确定这是否是在使用连接之前更改连接架构的方法。任何样本或想法?

Thanks in advance for your help!

在此先感谢您的帮助!

采纳答案by Mike

If all of the entities use the same schema you can use an xml mapping file to define a default schema.

如果所有实体都使用相同的架构,您可以使用 xml 映射文件来定义默认架构。

Something like this should work (example is for JPA 2.0, change the schemaLocation for 1.0)

这样的事情应该可以工作(示例适用于 JPA 2.0,将 schemaLocation 更改为 1.0)

orm.xml:

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:

持久性.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>

回答by Ati

You can do it programatically. You can configure the default schema value for each session.

您可以以编程方式进行。您可以为每个会话配置默认架构值。

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

Then set the session customizer to entity manager factory properties:

然后将会话定制器设置为实体管理器工厂属性:

PersistenceUnitProperties.SESSION_CUSTOMIZER 

e.g.

例如

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

回答by Chris

I use EJBright before querying the database, so by using InterceptorsI'm able to set the schema in the EJB context by looking the current authenticated user.

我在查询数据库之前就使用EJB,因此通过使用拦截器,我可以通过查看当前经过身份验证的用户在 EJB 上下文中设置模式。

Then when I build the entity manager I can set the right schema. In this way, by not specifying the schema before the table name, PostgreSQL will look at the search_pathfor determining which schema to query.

然后当我构建实体管理器时,我可以设置正确的模式。这样,通过不在表名之前指定模式,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();
      }
    } 

Then when you build the entity manager, you can set the schema you want.

然后当你构建实体管理器时,你可以设置你想要的模式。