【问题标题】:Hibernate selects identity column values before every insertHibernate 在每次插入之前选择标识列值
【发布时间】:2019-06-14 22:22:10
【问题描述】:

我正在尝试向数据库中插入 30 行,ID 生成策略是IDENTITY,并且我的数据库 (Exasol) 支持它。在每次插入之前,Hibernate 从数据库中选择标识值,如下所示(来自 Hibernate 日志):

Hibernate:
    SELECT
            COLUMN_IDENTITY 
        FROM
            EXA_ALL_COLUMNS 
        WHERE
            COLUMN_NAME='ENTRY_ID' 
            AND COLUMN_SCHEMA='TEST' 
            AND COLUMN_TABLE='CAMPAIGN'
Hibernate: 
    insert 
    into
        ecombi_mdm_test.CSV_ADCAMPAIGN
        (bla1, bla2, bla3, bla4, bla5, bla6, bla7, bla8, bla9, bla10, bla11, bla12, bla13, bla14, bla15, bla16, bla17, bla18, bla19, bla20, bla21, bla22, bla23, bla24, bla25, bla26, bla27, bla28, bla29, bla30) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
    SELECT
            COLUMN_IDENTITY 
        FROM
            EXA_ALL_COLUMNS 
        WHERE
            COLUMN_NAME='ENTRY_ID' 
            AND COLUMN_SCHEMA='TEST' 
            AND COLUMN_TABLE='CAMPAIGN'
Hibernate: 
    insert 
    into
        ecombi_mdm_test.CSV_ADCAMPAIGN
        (bla1, bla2, bla3, bla4, bla5, bla6, bla7, bla8, bla9, bla10, bla11, bla12, bla13, bla14, bla15, bla16, bla17, bla18, bla19, bla20, bla21, bla22, bla23, bla24, bla25, bla26, bla27, bla28, bla29, bla30) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

...还有 28 个。最终,我用了 9 秒插入了 30 行。

这是我配置数据源的方式:

        configuration = new Configuration();
        configuration.setProperty("hibernate.connection.driver_class", properties.getProperty(...);
        configuration.setProperty("hibernate.connection.url", properties.getProperty(...);
        configuration.setProperty("hibernate.connection.username", properties.getProperty(...);
        configuration.setProperty("hibernate.connection.password", properties.getProperty(...);
        configuration.setProperty("hibernate.dialect", properties.getProperty(com.bla.exasol.ExasolDialect);
        configuration.setProperty("hibernate.show_sql", "true");
        configuration.setProperty("hibernate.format_sql", "true");
        configuration.setProperty("hibernate.default_schema", properties.getProperty(...);
        configuration.addAnnotatedClass(Some.class);

        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
        SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);

这是来自我的 DAO 课程:

Session session = MultiTenantDBAccess.getSessionFactory().openSession();
Transaction transaction = null;

try {
    transaction = session.beginTransaction();
    for (T o : oList) {
        session.persist(o);
    }
    transaction.commit();
} catch (HibernateException e) {
    transaction.rollback();
    e.printStackTrace();
} finally {
    session.close();
}

这是我的数据库的自定义身份支持类:

public class ExasolIdentityColumnSupport extends IdentityColumnSupportImpl {

    @Override
    public String appendIdentitySelectToInsert(String arg0) {
        return arg0;
    }

    @Override
    public String getIdentityColumnString(int type) throws MappingException {
        return type==Types.BIGINT ?
                "decimal(36, 0) identity not null" :
                "decimal(19, 0) identity not null";
    }

    @Override
    public String getIdentitySelectString(String table, String column, int type) throws MappingException {
        return "SELECT COLUMN_IDENTITY FROM EXA_ALL_COLUMNS WHERE COLUMN_NAME='"+column.toUpperCase()+"' AND COLUMN_SCHEMA='"+table.substring(0, table.indexOf(".")).toUpperCase()+"' AND COLUMN_TABLE='"+(table.substring(table.indexOf(".")+1)).toUpperCase()+"'";
    }

    @Override
    public boolean hasDataTypeInIdentityColumn() {
        return false;
    }

    @Override
    public boolean supportsIdentityColumns() {
        return true;
    }

    public boolean supportsInsertSelectIdentity() {
        return false;
    }

}

问题是我使用的数据库不支持InsertSelectIdentity吗?不能只是 Hibernate 在每次插入之前不检查 id 值就向 DB 发送 30 个查询吗?在这种情况下,我不能通过 Hibernate 获得比每 9 秒 30 行更好的性能吗?

【问题讨论】:

    标签: java hibernate sql-insert


    【解决方案1】:

    对 OLTP 工作负载使用列分析 DMBS 不是一个好主意:选择、插入或更新单行。

    您可以使用 MySQL / PostgreSQL / etc. 来存储作业状态和一般的 ORM 悲伤。并且仅将 Exasol 用于大数据批处理和大型导入。

    【讨论】:

    • 显然,我们并不主要将 Exasol 用于此类小型数据库事务,它只是一个补充功能。
    【解决方案2】:

    id 是必需的,因为实体存储在 Session 中,使用 id 作为键。

    如果数据库支持使用序列,唯一的规避方法是使用数据库序列。

    【讨论】:

    • 所以这不是特定于数据库的问题?我的意思是,如果你不使用序列,它总是每 9 秒大约 30 行?
    • 查看其他依赖 JDBC 使用 GENERATED_KEYS 获取 id 的方言的 IdentitySupport 实现。也许这个数据库也可以做到这一点。
    • 好的,通过序列(如here 所述),我能够从 9 秒提高到 5 秒,但仍然很慢。
    猜你喜欢
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-22
    相关资源
    最近更新 更多