[英]Do any of the JPA implementations (or wider Java ORM implementations) support updatable Cursors
我希望Java可用的一种对象/关系映射(ORM)工具能够满足以下要求:
我想逐行执行复杂的批处理操作(实际上,我正在将文件中的已知良好数据与数据库中的数据进行比较和协调)。 如果更简单,我将诉诸于使用JDBC并执行一些SQL。 但是在这种情况下,我确实确实从直接从Bean转到数据库中获得了好处。
在SQL中,我可以使用可更新的游标来有效实现目标。
作为参考,我正在嵌入式Java H2环境中测试所有这些。
我的第一个天真尝试是调用Query.getResultList() ,该方法返回的实体bean很好,但是它们是“断开连接的”。 如果我调用persistenceUnitUtil.getIdentifier(myEntity)
则它抱怨它不是实体类型。
然后,我研究了支持ScrollableResults的 Hibernate。 该接口允许我按名称而不是实体来获取各个列的值。
接下来是支持ScrollableCursor的 EclipseLink。 为此,我寄予了良好的希望:
Query query = entityManager.createQuery(jpaQuery);
query.setHint("eclipselink.cursor", true);
CursoredStream cursoredStream = (CursoredStream)query.getSingleResult();
不幸的是cursoredStream.next();
再次返回实体的“断开连接”版本。 因此,我看不到写回实体的方法。
我目前正在研究至少将实体的@Id作为查询的一部分传递回去的方法(不幸的是,我想保持工具的灵活性,有时我将字符串作为键,有时将字符串作为组合键对象)。 至少这将允许我遍历各行,然后查找并分别持久保存每个实体。
但是,我更希望有一个游标支持的迭代器,该迭代器可以获取与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();
}
如评论中所述,在实体管理器中替换使用会话,在Java中替换C#构造。 如果实体是独立的,您甚至可以将while与多个线程,会话并行化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.