使用休眠第二级缓存和HSQL的插入/更新率令人失望



我需要能够以每秒5,000次以上的速度写入我的数据库。目前,我无法管理超过该数字的10%。

我正在使用Spring来配置我的数据源(HSQL(和Hibernate作为我的Jpa提供者。

我的实体都是平面的(没有复杂的对象树(,我使用了Hibernate二级缓存(EhCache(,并将并发策略设置为ConcurrencyStrategy.READ-WRITE。

这是我的数据源 bean 的 Spring 上下文:

 <bean id="commandsTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="commandEmf"/>
<tx:annotation-driven transaction-manager="commandsTransactionManager" />
<!-- Commmands Data Source Configuration -->
<bean id="commandsDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc-commands.driverClassName}"/>
    <property name="url" value="${jdbc-commands.url}"/>
    <property name="username" value="${jdbc-commands.username}"/>
    <property name="password" value="${jdbc-commands.password}"/>
    <property name="initialSize" value="10"/>
    <property name="maxActive" value="100"/>
    <property name="maxWait" value="-1"/>
</bean>
 <bean name="lazyConnectionDataSourceProxy" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
    <property name="targetDataSource" ref="commandsDataSource" />
</bean>
<!-- Commands Container Managed JPA Entity Manager Factory -->
<bean id="commandEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="commandsDataSource"/>
    <property name="persistenceUnitName" value="commands"/>
    <property name="jpaPropertyMap" ref="jpaPropertyMap"/>
    <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
                    p:showSql="false"  p:generateDdl="true" p:database="HSQL" p:databasePlatform="org.hibernate.dialect.HSQLDialect">
            </bean>
    </property>
</bean>
<util:map id="jpaPropertyMap" key-type="java.lang.String" value-type="java.lang.Object">
     <entry key="hibernate.hbm2ddl.auto" value="${jdbc-commands.ddlmode}" />
      <entry key="hibernate.cache.use_second_level_cache" value="true" />
      <entry key="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory"/>
</util:map>

下面是我的一个实体类的示例。"AbstractAnnotatedAggregateRoot"是来自Axon框架的抽象实体类,它提供了聚合和存储库实现框架。聚合本质上是必须实现自己的 Jpa 以实现持久性的实体。

@Entity
@Table(name = "users")
@Cache(region="usersCache", usage= CacheConcurrencyStrategy.READ_WRITE)
public class User extends AbstractAnnotatedAggregateRoot {
    private static final long serialVersionUID = -6536766172448063298L;
    private String username;
    private String password;
    private Integer subscription;
    private String firstName;
    private String lastName;
    private Calendar subscriptionDate;
    private Date lastAccessTime;
    public User(){}
    public User(StringAggregateIdentifier email){
        super(email);
        registerEvent(new UserCreatedEvent(email.asString()));
    }
    @Column(unique = true)
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
        registerEvent(new UserNameUpdatedEvent(this.username));
    }
    @Column(nullable = false)
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
        registerEvent(new UserPasswordUpdatedEvent(this.password));
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
        registerEvent(new UserFirstNameUpdatedEvent(this.firstName));
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
        registerEvent(new UserLastNameUpdatedEvent(this.lastName));
    }
    public String getEmail() {
        return getIdentifier().asString();
    }
    @Temporal(TemporalType.DATE)
    public Calendar getSubscriptionDate() {
        return subscriptionDate;
    }
    public void setSubscriptionDate(Calendar subscriptionDate) {
        this.subscriptionDate = subscriptionDate;
        registerEvent(new UserSubscriptionDateUpdatedEvent(this.subscriptionDate));
    }
    @Temporal(TemporalType.TIMESTAMP)
    public Date getLastAccessTime() {
        return lastAccessTime;
    }
    public void setLastAccessTime(Date lastAccessTime) {
        this.lastAccessTime = lastAccessTime;
        registerEvent(new UserLastAccessTimeUpdatedEvent(this.lastAccessTime));
    }
    public Integer getSubscription() {
        return subscription;
    }
    public void setSubscription(Integer subscription) {
        this.subscription = subscription;
        registerEvent(new UserSubscriptionUpdatedEvent(this.subscription));
    }
}

为了完整起见,这是我的 EhCache.xml 文件中的缓存区域配置:

  <cache name="usersCache" maxElementsInMemory="10000"
  maxElementsOnDisk="10000" eternal="false" overflowToDisk="false"
  diskSpoolBufferSizeMB="20" timeToIdleSeconds="300"
  timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU"
  statistics = "true">
  </cache>

在 Axon 框架中,我调度命令来尝试更改聚合的状态。这些命令在由 Spring 的 PlatformTransactionManager 管理的事务范围内。

命令

调度同步发生,我需要每秒处理 5,000 个命令。每个命令将从缓存中获取聚合,更改其上的值,然后在调度下一个命令之前保留更改。问题完全出在获取/更新/插入行的时间,考虑到 HYSQL 和 H2 等吹嘘的插入速率,我认为这会快得多。

任何提高我一个数量级的速度的想法将不胜感激。

谢谢

如果此实体是典型的数据(即没有长字符串的几列(,并且数据库操作是 UPDATE,则数据库性能应与此处描述的相当,后者每秒执行 5000 个事务(多个更新,每个事务一个选择和一个插入(基于磁盘的表。

http://hsqldb.org/web/hsqlPerformanceTests.html

数据库在一个表中有 4000000 条记录。对于较大的表,性能会下降,尤其是在数据库大小超过使用 Java nio 内存映射文件的预设限制时。

您还应该检查 .script 文件中的数据库架构,并查看是否创建了不必要的索引,这可能会减慢速度。

我认为您的数据库和 JDBC 以及单个插入语句可以做的事情已经到了极限。休眠不是问题,缓存也不是问题。但是您的数据库可能无法处理更多通过 JDBC 的插入。

但是,如果您设法使用批量插入操作,则可以获得更快的速度。对于体积,我的意思是样式insert into your_table select ... from ....从表中读取数据,修改一点,然后插入结果。那里可能会批量插入。

最新更新