我有一个使用Hibernate(通过JPA)的长期运行(但相当简单)的应用程序.它经历了相当剧烈的放缓.我已经能够缩小到需要偶尔entityManager.clear()
打电话.当Hibernate的实体管理器跟踪100,000个实体时,它比仅跟踪几个实体的速度慢约100倍(见下面的结果). 我的问题是:为什么 Hiberate在追踪很多实体的时候会这么慢?还有其他方法吗?
!更新:我已经能够将其缩小到Hibernate的自动刷新代码.!
具体到org.hibernate.event.internal.AbstractFlushingEventListener
's flushEntities()
方法(至少在Hibernate 4.1.1.Final中).在其中有一个循环遍历持久化上下文中的所有实体,执行一些广泛的检查来清除它们中的每一个(即使在我的示例中已经刷新了所有实体!).
因此,部分回答我的问题的第二部分,可以通过FlushModeType.COMMIT
在查询上设置刷新模式来解决性能问题(请参阅下面的更新结果).例如
Place place = em.createQuery("from Place where name = :name", Place.class)
.setParameter("name", name)
.setFlushMode(FlushModeType.COMMIT) // <-- yay!
.getSingleResult();
Run Code Online (Sandbox Code Playgroud)
...但这似乎是一个相当丑陋的解决方案 - 传递责任,知道是否将事物刷新到查询方法而不是将其保留在更新方法中.它也意味着我要么必须在所有查询方法上将flush模式设置为COMMIT,要么更有可能在EntityManager上设置它.
这让我想知道:这是预期的行为吗?我是否在刷新或者如何定义实体时出错?或者这是Hibernate的限制(或可能是错误)?
我用来隔离问题的示例代码如下:
@Entity @Table(name="place") @Immutable
public class Place {
private Long _id;
private String _name;
@Id @GeneratedValue
public Long getId() { return _id; }
public void setId(Long id) { _id = id; }
@Basic(optional=false) @Column(name="name", length=700,
updatable=false, nullable=false, unique=true, …
Run Code Online (Sandbox Code Playgroud) 我正在尝试sscanf
用于简单的测试和转换,但我遇到了一个问题,它忽略了字符串中的尾随垃圾.我的示例代码是:
char *arg = "some user input argument";
int val = 0;
if (sscanf(arg, "simple:%d", &val) == 1) {
opt = SIMPLE;
} else if (strcmp(arg, "none") == 0) {
opt = NONE;
} else {
// ERROR!!!
}
Run Code Online (Sandbox Code Playgroud)
这适用于预期的输入,例如:
arg = "simple:2" --> opt = SIMPLE val = 2
arg = "none" --> opt = NONE val = 0
Run Code Online (Sandbox Code Playgroud)
但我的问题是,在"简单"值之后的尾随字符会被默默忽略
ACTUAL : arg = "simple:2GARBAGE" --> opt = SIMPLE val = 2
DESIRED: arg = …
Run Code Online (Sandbox Code Playgroud)