java - 任何 JPA 实现(或更广泛的 Java ORM 实现)是否支持可更新游标

标签 java hibernate orm eclipselink ibatis

我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求:

  • 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。
  • 允许在行(实体)中进行迭代,并在对当前实体进行更改后保留当前实体。

我想要执行复杂的批处理操作(实际上我正在逐行比较和协调文件中的已知良好数据与数据库中的数据)。如果更简单,我只需使用 JDBC 并执行一些 SQL;但在这种情况下,我确实从直接从 bean 到数据库中获益。

在 SQL 中,我可以使用可更新游标来有效地实现我的目标。

作为引用,我正在嵌入式 Java H2 环境中测试所有这些。

JPA 查询

我的第一次天真的尝试是调用 Query.getResultList()它返回实体 bean 很好,但它们“断开连接”。如果我调用 persistenceUnitUtil.getIdentifier(myEntity) ,那么它会提示它不是实体类型。

hibernate

然后我研究了支持ScrollableResults的Hibernate 。该界面允许我通过名称获取各个列值,但不能获取实体。

EclipseLink

接下来是 EclipseLink,它支持 ScrollableCursor 。我对这个抱有很好的希望,将其用于:

Query query = entityManager.createQuery(jpaQuery);
query.setHint("eclipselink.cursor", true);
CursoredStream cursoredStream = (CursoredStream)query.getSingleResult();

不幸的是cursoredStream.next();再次返回实体的“断开连接”版本。因此,我看不到写回实体的方法。

结论

我目前正在研究至少将实体的 @Id 作为查询的一部分传递回来的方法(不幸的是,我希望保持工具的灵 active ,有时我将字符串作为键,有时将复合键对象)。这至少允许我迭代行,然后单独查找并保留每个实体。

但是,我更喜欢的是有一个游标支持的迭代器,它可以为我获取一个 JPA 连接的实体,并允许我对其进行更改并保留它。

如果这不是 ORM 工具之一的已知功能,我可能不得不放弃并求助于老式的 JDBC。

最佳答案

伪代码(C#)

void Execute(ISession session, string filepath)
{
    int page = 0;
    int pagesize = 5000;
    int batchindex = int.MaxValue;
    List<Entity> batch = new List<Entity>();

    TextReader file = new StreamReader(filepath)

    string line;
    while ((line = file.ReadLine) != null)
    {
        if (batchindex > batch.Count)
        {
            session.Flush();
            session.Clear();
            batch = session.CreateCriteria<Entity>()
                .AddOrder(Order.Asc(<same order as in file>))
                .SetFirstResult(page * pagesize)
                .SetMaxResults(pagesize)
                .List<Entity>();
            page++;
            batchindex = 0;
        }
        if (database has more rows than the file
        while (!LineIsForEntity(batch[batchindex], line))
        {
            batchindex++;
            // same if (batchindex > batch.Count) as above
        }

        UpdateEntity(batch[batchindex], line);
    }
    session.Flush();
    session.Clear();
}

根据数据类型和上下文,可能会有更好的代码。

更新:使用 C# 进行随机访问,在使用 (N)Hibernate 时应该高效

const int pagesize = 2000;
var nextbatch = Enumerable.Repeat(0, pagesize)
    .Select(_ => file.ReadLine())
    .TakeWhile(line => line != null);

string[] batch;
while ((batch = nextbatch.ToArray()).Length > 0)
{
    // ignore results, we only want the entities in cache
    session.QueryOver<Entity>()
        .WhereRestrictionOn(e => e.Id).In(batch.Select(line => ExtractId(line)).ToList())
        .List();

    foreach(string line in batch)
    {
        Update(session.Get<Entity>(ExtractId(line)), line);
    }
    session.Flush();
    session.Clear();
}

正如评论中所述,将 session 的使用替换为entityManager,将C# 结构替换为Java。如果实体是独立的,您甚至可以使用多个线程、 session 并行化 while。

关于java - 任何 JPA 实现(或更广泛的 Java ORM 实现)是否支持可更新游标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12960545/

相关文章:

java - 使用 Maven 的 Web 服务客户端 - SSL 证书

java - hibernate : "Instantiating explicit connection provider"非常慢

mysql - (Hibernate,mysql)由: java. sql.SQLException引起:字段 'id'没有默认值

需要 .NET ORM 帮助

entity-framework - .NET 2.0 是否有类似 Entity Framework 的 ORM? (数据库优先!)

c# - 为什么 linq-2-sql 会创建额外的不必要的对象?

java servlet url 映射不起作用

java - 如何在 Java 中创建对象数组的 ArrayList?

java - 将数据保存在数据库或 session 中

java - 使用代理的惰性一对一不起作用