【问题标题】:JPA 2.0 insufficient privileges when performing insert from transaction从事务执行插入时 JPA 2.0 权限不足
【发布时间】:2012-01-03 16:15:32
【问题描述】:

经过多次搜索和试验,我被困住了......我有两个类,一个是 ExpectedSecurityReturn,另一个是 ForecastReturnType。 ForecastReturnType 是 ExpectedSecurityReturn 的成员,但不应在持久化数据时插入。我不断获得“权限不足”,但我知道用户确实拥有对表 expected_security_return 的删除/插入权限,因为我使用 JDBC 和 JPA 进行了测试,删除工作正常。因此,我认为这与我的课程有关。

@Table(name = "EXPECTED_SECURITY_RETURNS")
@Entity
@IdClass(ExpectedSecurityReturn.ExpectedSecurityReturnPK.class)
public class ExpectedSecurityReturn {

@Id
@Column(name = "REP_SEC_ID")
private Integer repSecId;

@Id
@Column(name = "AS_OF_DATE")
private Date date;

@Id
@ManyToOne(optional = false)
@JoinColumn(name = "RETURN_TYPE_ID", referencedColumnName = "RETURN_TYPE_ID", insertable=false)
private ForecastReturnType returnType;

@Column(name="CURR_TOUSD_RET")  // local currency to usd 
private Double currencyToUsdReturn;
}

主键类,其中包括 ForecastReturnType:

    // ------------------------------
// PK
// ------------------------------
public static class ExpectedSecurityReturnPK implements Serializable {

    private static final long serialVersionUID = 1325372032981567439L;

    public ExpectedSecurityReturnPK() {
    }

    public ExpectedSecurityReturnPK(final Integer repSecId,
            final Date asOfDate, ForecastReturnType returnType) {
        if (repSecId == null)
            throw new IllegalArgumentException("null rep sec id");
        if (asOfDate == null)
            throw new IllegalArgumentException("null asOfDate");
        if (returnType == null)
            throw new IllegalArgumentException("null returnType");

        this.repSecId = repSecId;
        this.date = new Date(asOfDate.getTime());
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        final ExpectedSecurityReturnPK that = (ExpectedSecurityReturnPK) o;

        if (repSecId != that.repSecId)
            return false;
        if (!date.equals(that.date))
            return false;
        if (!returnType.equals(that.returnType))
            return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = repSecId;
        result = 31 * result + date.hashCode();
        result = 31 * result + returnType.getForecastTypeId();
        return result;
    }

    private int repSecId;
    private Date date;
    private ForecastReturnType returnType;
}

和 ForecastReturnType:

@Table(name="EXPECTED_SEC_RET_TYPE_DECODE")
@Entity
public class ForecastReturnType {

@Id
@Column(name="RETURN_TYPE_ID")
private int forecastTypeId;

@Column(name="SHORT_NAME")
private String shortName;

@Column(name="LONG_NAME")
private String longName;

@OneToMany(fetch=FetchType.LAZY, mappedBy="returnType")
Collection<ExpectedSecurityReturn> expectedSecurityReturns;
}

谁能帮我弄清楚我做错了什么?我尝试了很多事情都没有成功......我认为罪魁祸首是 ExpectedSecurityReturn.returnType 因为我知道用户没有权限。

基本上,我需要插入/保留 ExpectedSecurityReturn 实例。

【问题讨论】:

  • 在日志中查找 JPA 实现并告诉人们正在调用什么 SQL,以及异常的详细信息(及其堆栈跟踪)
  • 其次,如果你使用的是 PostgreSQL,你可以改变 postgresql.conf(通常在 /var/pgsql 中)并在服务器上启用日志记录,寻找日志记录部分,通常有大量的 cmets 来帮助.如果您使用 MySQL,您可以在 my.cnf(通常在 /etc)中添加日志记录以记录所有查询,如果您使用 Oracle,您应该在 V$SQL 中看到它。我不太了解 MSSQL,不知道您是否可以记录所有查询,但我认为您可以通过 SQL Studio 获取数据库锁定的历史记录。
  • 我看不出sql语句有什么问题,所以我认为它与包括外键在内的主键有关。不知何故,它需要对返回类型表拥有足够的权限)。插入SQL为:插入EXPECTED_SECURITY_RETURNS (CURR_TOUSD_RET, EXCESS_TOSECTOR_RET, EXCESS_TOTREAS_RET, LOCAL_RET, TREASURY_CARRY_RET, TREASURY_RET, AS_OF_DATE, REP_SEC_ID, RETURN_TYPE_ID)值(?, ?, ?, ?, ?, ?, ?, ?, ?)

标签: java jpa insert persistence jpa-2.0


【解决方案1】:

嗯,有几件事。

我强烈建议不要尝试这样做。你可能会浪费你的生命去弄清楚 JPA 注释和像这样似乎永远不会正常工作的奇怪问题。您还会发现,不同的 JPA 提供程序在涉及到像这样的更复杂的结构时会表现出略微不同,并且对于继承来说是双重的。

您最好在 EXPECTED_SECURITY_RETURNS 上创建一个唯一键,并且只需使用它,它就会让您的 Java 生活变得更加轻松。

如果您必须做这样的事情,我并不惊讶 JPA 不愿意让主键组件成为另一个实体对象。虽然这在 RDBMS 中当然很有可能,但看起来像这样的小事情会绊倒 JPA。

我还会检查您的 JPA impl 将输出的查询日志(对于大多数 JPA 提供程序,当然是 Ecpiselink 和 Hibernate,它在持久性定义中相当容易配置)。我敢打赌它正在尝试在 EXPECTED_SEC_RET_TYPE_DECODE 上运行更新,如果没有,它可能正在尝试获取锁(表、行或其他取决于您的 DBMS)。如果用户无权对该表执行锁定或更新,根据具体实现,查询可能会因权限问题而失败。

JPA 想要在该表上持有锁是合理的,因为在事务期间,EXPECTED_SEC_RET_TYPE_DECODE 中引用的条目可能会发生更改,因此它必须确保在更新时不会更改/inserting 在另一张桌子上。最后我检查了一下,没有办法告诉 JPA 这个表本质上是静态的。如果您使用的是 Hibernate,您可能会尝试使用 @ReadOnly 注释,但在过去,我尝试过的很少能解决这样的问题。

如果您确实找到了更好的解决方案,请随时发布,以便我们其他人学习!!

【讨论】:

  • 感谢您的帖子。我会看看并弄清楚下一步该做什么。解决此冲突后,我将再次发布。你会认为 JPA 可以解决这个问题,因为复合 PK 在表格设计中非常常见。我认为您对与 EXPECTED_SEC_RET_TYPE_DECODE 相关的问题是正确的。这也是我的想法。我可能会尝试用 int 替换 ExpectedSecurityReturn.returnType(因为 ForecastReturnType 的 PK 是 int)并忘记对象本身(ForecastReturnType)。
  • 它们相当普遍,我同意。链接表是最常见的品种,JPA 对带有@JoinTable 注释的表格做得很好。通常,通过向本质上是带有元数据的连接表添加新的主键列所做出的牺牲并不大。约束分支很小,因为两个(或更多)外键都映射到外键约束中,您可以在 SQL 中创建唯一索引来模拟主键行为。 PostgreSQL 就是以这种方式使用唯一索引,所以就它而言,没有区别,因为无论如何都有一个内部行 id。
  • 延迟加载与急切加载会出现一个问题。如果有太多的表具有复合主键,那么对于 ORM 来说就变得非常危险。为了验证完整性,有时可能必须获取大量表信息,尤其是在复合主键由外键组成的情况下。一对多关联也会出现类似的情况。当您在任何一个中遍历对象图时,糟糕的 ORM 根本无法知道您对该数据的意图,因此无法将获取过程优化为合理的查询,从而使您的网络链接崩溃。
  • 我对 exp 进行了更改。 return 对象认为它可以解决问题,例如 ForecastReturnType 对象是 @Transient 并添加和 int returnTypeId 认为它会使事情变得更容易并解决问题。它没。我仍然收到相同的“权限不足错误”。
【解决方案2】:

我同意 PlexQ 的观点,即派生身份和复合键是 JPA 中相当复杂的部分。

但是,JPA 2.0 规范包含一组很好的示例来说明这些主题,并且这些示例大多适用于不同的 JPA 实现。

对于您的案例规范,建议您在@IdClass 中放入一个名称为@ManyToOne 字段和类型为@Id 引用实体字段的字段:

@Entity
public class Employee {
    @Id long empId;
    String empName;
    ...
}

public class DependentId {
    String name; // matches name of @Id attribute
    long emp; // matches name of @Id attribute and type of Employee PK
}

@Entity
@IdClass(DependentId.class)
public class Dependent {
    @Id String name;
    // id attribute mapped by join column default
    @Id @ManyToOne Employee emp;
    ...

}

另请参阅:

【讨论】:

    【解决方案3】:

    经过大量的尝试和错误,我终于发现错误是合法的,我确实没有足够的(即插入)权限,只能删除!!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-26
      • 2015-12-09
      • 2017-09-24
      • 1970-01-01
      • 2011-02-27
      • 2020-09-26
      相关资源
      最近更新 更多