【问题标题】:Is it possible to Create, Delete or Update an Oracle DB user via JPA?是否可以通过 JPA 创建、删除或更新 Oracle DB 用户?
【发布时间】:2016-04-27 00:24:18
【问题描述】:

在第一阶段,我通过 JDBC 管理我的应用程序,因此我负责构建和验证所有 SQL。但我想知道 JPA 是否可以帮助我完成这些任务。

所以,此时我已经有了一个 DbaUser 模型,它是从 OracleDB 上的 DBA_USERS 表生成的,我实际上可以列出所有这些模型。

但是,我正在尝试创建或更新更多内容,但每当我尝试使用

 em.createQuery("CREATE USER C##ANTONIO IDENTIFIED BY Antionio123").executeUpdate();

启动语法异常:The query does not start with a valid identifier, has to be either SELECT, UPDATE or DELETE FROM.

你们能给我多一点启发或指点我一些合适的教程吗?我一直在谷歌上搜索,但在 Oracle DB 系统表上没有任何具体内容。

更新 1(感谢 @JB Nizet)

将查询的执行从 JPQL 替换为 Native SQL 后,出现如下错误:

Query: DataModifyQuery(sql="CREATE USER C? IDENTIFIED BY ANTONIO123").

我已经用“...C\#\#...”替换了带有转义字符“...C##...”的主题标签,但这个问题获得了不同的味道:

Query: DataModifyQuery(sql="CREATE USER C\? IDENTIFIED BY ANTONIO123")

...我真的需要将“##”发送到 Oracle DB。如何强制使用这些特殊字符?

更新 2

所以......在谷歌搜索更多之后,我发现了位置参数,并且我还发现我们不能在 JPA 本地查询中命名参数。在此之后,我尝试过:

em.createNativeQuery("CREATE USER ?1 IDENTIFIED BY ANTONIO123").setParameter(1, "C##ANTONIO").executeUpdate();

哪些触发器:ORA-01935: missing user or role name

Error Code: 1935
Call: CREATE USER ? IDENTIFIED BY ANTONIO123

这告诉我这个绑定不起作用。还有其他方法吗?

提前致以诚挚的问候和感谢,

萨米

【问题讨论】:

  • 你试过em.createNativeQuery("CREATE USER C##ANTONIO IDENTIFIED BY ANTONIO123")em.createNativeQuery("CREATE USER \"C##ANTONIO\" IDENTIFIED BY ANTONIO123")吗?
  • 我认为 DDL 语句不支持绑定变量(CREATE, DROP, ALTER 等)。您登录的用户是否拥有CREATE USER 权限?
  • 尽管这是一个非常有趣的问题,您能否分享一下通过 JPA 创建 USER(尤其是普通用户)的原理......
  • 嗨@MickMnemonic,是的,我当然有!我以 SYSDBA 用户的身份与 SYS 连接,这意味着我当然有权创建它们。实际上,我没有阅读任何有关 DDL 语句和变量绑定的信息,这实际上可能意味着绑定是不可能的。我认为也许 JDBC 将成为它的解决方案!感谢您的帮助!
  • 嗨@MarmiteBomber! “分享理由”是什么意思? (对不起,我从没听过那个表达)。亲切的问候,大卫

标签: java oracle jpa jdbc


【解决方案1】:

createQuery() 需要 JPQL 查询。你通过的不是JPQL。它是 SQL

使用createNativeQuery() 执行SQL。

【讨论】:

  • 嗨,JB!感谢您的快速反馈!我已将 createQuery 替换为 createNativeQuery,如下所示:“CREATE USER C##ANTONIO IDENTIFIED BY ANTONIO123”,但查询已启动:查询:DataModifyQuery(sql="CREATE USER C? IDENTIFIED BY ANTONIO123")。但是,我确实需要查询中的“##”,并且我已经尝试使用转义字符“\\#”,但查询仅启动如下:sql="CREATE USER C\?IDENTIFIED BY Gbs22618")你能帮我解决这个问题吗?亲切的问候,萨米
【解决方案2】:

另一种选择是在数据库中创建一个存储过程,然后从 JPA 调用存储过程,因此您无需担心警告和语法。

例如,假设 JPA 提供者是 EclipseLink

数据库存储过程

  CREATE OR REPLACE PROCEDURE p_user_creation (p_username   IN     VARCHAR2,
                                             p_password   IN     VARCHAR2,
                                             p_return        OUT NUMBER)
IS
   v_syntax   VARCHAR2 (256);
BEGIN
   IF (p_username IS NOT NULL)
   THEN
      v_syntax :=
            'CREATE USER '''
         || p_username
         || ''' IDENTIFIED BY '''
         || p_password
         || '''';

      EXECUTE IMMEDIATE v_syntax;

      p_return := 0;
   END IF;
EXCEPTION
   WHEN OTHERS
   THEN
      raise_application_error (-20002, 'An error has occurred!');
END;

Java 代码 sn-p 调用存储过程

  try {
   Integer returnValue = null;

   StoredProcedureQuery storedProcedureQuery =
    getEntityManager().createStoredProcedureQuery("p_user_creation");

   storedProcedureQuery.registerStoredProcedureParameter("p_username", String.class, ParameterMode.IN);
   storedProcedureQuery.registerStoredProcedureParameter("p_password", String.class, ParameterMode.IN);
   storedProcedureQuery.registerStoredProcedureParameter("p_return", Integer.class, ParameterMode.OUT);

   storedProcedureQuery.setParameter("p_username", "SCOTT");
   storedProcedureQuery.setParameter("p_password", "tiger");

   storedProcedureQuery.execute();

   returnValue = (Integer) storedProcedureQuery.getOutputParameterValue("p_return");
  } catch (Exception e) {
   log.error("Error " + e.getMessage());
  } 

【讨论】:

    【解决方案3】:

    要创建common user(以 C## 为前缀),您(即您的 JPA 连接池用户)需要一个 specific priviledges

    CREATE ROLE and 
    SET CONTAINER
    

    这些不是授予 JPA 连接的典型权限,所以我猜你会因为创建新的普通用户而失败。

    此外,您需要连接到根容器

    进一步的例子是从 Groovy 调用的普通 JDBC,如果你获得了 DB 连接,应该很容易将它传递给 JPA。

    def stmt = con.prepareStatement("SELECT SYS_CONTEXT('USERENV', 'CON_NAME') CON_NAME FROM   dual")
    
    def rs = stmt.executeQuery()
    while(rs.next())
     {
       println "container name=  ${rs.getString('CON_NAME')}"
     }
    

    给予

    container name=  CDB$ROOT
    

    请注意,如果您连接到本地数据库,则在尝试创建前缀为 C## 的用户时会出错

     ORA-65094: invalid local user or role name
    

    如果两个条件都满足,就可以创建/删除普通用户:

    String cu = "create user \"C##TEST\" identified by password123 profile \"DEFAULT\" account unlock"
    con.createStatement().execute(cu)
    

    分别

    cu = "drop  user \"C##TEST\""
    con.createStatement().execute(cu)
    

    最后应该声明,这个练习只是为了完整性。我没有看到 JPA 池连接被授予此类权限并连接根容器的真实用例。数据库维护通常不使用 JPA。

    【讨论】:

    • 嗨马麦酱!我很确定特权不是问题,因为我使用 SYS 作为 SYSDBA 连接到 ODB,所以我完全能够做到!感谢您的快速回复!亲切的问候,大卫奎瓦斯
    • @Sammy,根据docs,“在非 CDB 中,用户名不能以 C## 或 c## 开头。”您确定您已连接到多租户容器数据库 (CDB)?
    • 嗨@MickMnemonic,是的,我目前已连接到CDB。但是 JPA 应该可以双向工作......对吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    相关资源
    最近更新 更多