如何在HSQLDB资源数据库中创建大对象(CLOB)?

时间:2016-09-12 04:17:10

标签: jpa hsqldb clob

我创建了一个预装了数据的HSQLDB(版本2.3.3)数据库,并将其捆绑为资源(db.properties和db.script),供自动化测试使用,我不需要生成的数据。将测试保存回磁盘。这适用于我拥有的大多数JPA实体(所有CRUD操作都按预期工作)。但是,我有两个实体,其中包含一个用'@Lob'注释的列,我无法创建新实体,因为HSQLDB无法说'表数据是只读'。

我已经阅读了有关Large Objects的文档,但没有描述使用资源数据库时的行为。我猜测HSQLDB正在尝试创建'db.lobs',但它不能,因为有效的files_readonly = true。

有没有人知道是否可以使用HSQLDB资源数据库创建一个带有“大对象”列的实体?

堆栈跟踪是:

<div class="Block">
  Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Aenean lacinia bibendum nulla sed consectetur.
  <br><br>
  Nullam id dolor id nibh ultricies vehicula ut id elit. Donec ullamcorper nulla non metus auctor fringilla. Aenean lacinia bibendum nulla sed consectetur. Maecenas faucibus mollis interdum. Donec id elit non mi porta gravida at eget metus. Vestibulum id ligula porta felis euismod semper. Vestibulum id ligula porta felis euismod semper.
  <img src="https://3.bp.blogspot.com/-W__wiaHUjwI/Vt3Grd8df0I/AAAAAAAAA78/7xqUNj8ujtY/s1600/image02.png" class="Image" />
</div>

我正在运行的代码如下所示:

WARN 12-09-2016 00:57:26 - SQL Error: -458, SQLState: S1000
ERROR 12-09-2016 00:57:26 - org.hsqldb.HsqlException: The table data is read only
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1338)
    ..app classes...
Caused by: org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:211)
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:62)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3124)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3581)
    at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:104)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:465)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:351)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1258)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1335)
    ... 29 more
Caused by: java.sql.SQLException: org.hsqldb.HsqlException: The table data is read only
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(Unknown Source)
    at org.hsqldb.jdbc.JDBCPreparedStatement.executeUpdate(Unknown Source)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:147)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
    ... 39 more
Caused by: org.hsqldb.HsqlException: org.hsqldb.HsqlException: The table data is read only
    at org.hsqldb.error.Error.error(Unknown Source)
    at org.hsqldb.SessionData.allocateLobForResult(Unknown Source)
    at org.hsqldb.Session.allocateResultLob(Unknown Source)
    at org.hsqldb.jdbc.JDBCPreparedStatement.performPreExecute(Unknown Source)
    ... 43 more
Caused by: org.hsqldb.HsqlException: The table data is read only
    at org.hsqldb.error.Error.error(Unknown Source)
    at org.hsqldb.error.Error.error(Unknown Source)
    at org.hsqldb.persist.LobManager.setCharsForNewClob(Unknown Source)
    ... 46 more

java.lang.RuntimeException: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute statement

MyDatabase只是获取数据库连接的包装器。如果我使用'jdbc:hsqldb:mem:...',测试工作正常(createMyDatabase()方法使用我需要的数据加载内存数据库)。但是,如果我用使用'jdbc:hsqldb:res:...'的注释掉的行替换它,那么测试失败并且HSQLDB报告异常'表数据是只读的'。

将Hibernate置于DEBUG模式会显示以下内容:

    @Test
public void testCreateUserSettings() throws Exception {

    MyDatabase db = MyDatabaseFactory.createMyDatabase("jdbc:hsqldb:mem:db1;sql.syntax_ora=true", new Properties());
    //MyDatabase db = MyDatabaseFactory.getMyDatabase("jdbc:hsqldb:res:/my-db-base");

    Properties properties = new Properties();
    properties.putAll(db.getConnectionProperties());
    properties.setProperty("javax.persistence.provider", "org.hibernate.jpa.HibernatePersistenceProvider");

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("InMemorySeederPU", properties);
    EntityManager em = emf.createEntityManager();

    try {
        Date now = new Date();
        String defaultData = "{\"key\": \"value\"}";
        String defaultId = UUID.randomUUID().toString();
        String userId = "uA1";

        UserSetting setting = new UserSetting();
        setting.setIdObject(defaultId);
        setting.setDateCreate(now);
        setting.setDateUpdate(now);
        setting.setDateArrive(now);
        setting.setIdDatabase("A");
        setting.setIdUserCreate(userId);
        setting.setIdUserUpdate(userId);
        setting.setIdOwner(userId);
        setting.setNamespace(defaultId);
        setting.setEntityVersion(1L);
        setting.setData(defaultData);
        setting.setEtag(DigestUtils.md5Hex(defaultData));

        em.getTransaction().begin();
        em.persist(setting);
        em.flush();
        em.getTransaction().commit();

        UserSetting setting2 = em.find(UserSetting.class, defaultId);
        Assert.assertEquals(setting2, setting);
    }
    finally {
        em.close();
    }

}

提前致谢,

2 个答案:

答案 0 :(得分:1)

根据HSQLDB manual

  

res:catalog包含一个小的只读数据库的文件   可以存储在Java资源(如ZIP或JAR存档)中   并作为Java应用程序的一部分进行分发。

因此,您无法将数据插入此类数据库,并且需要例外

答案 1 :(得分:0)

来自RES and Files Readonly Databases部分:

  

还有另一个选项允许MEMORY表可写,但不会在SHUTDOWN中保持更改。此选项使用属性,值对,files_readonly = true激活,可以将其添加到数据库的.properties文件中,也可以包含在与数据库的第一个连接的URL中。

     

res:catalog,是类路径上的一组数据库文件(在   jar或类文件)。使用URL打开数据库   jdbc的形式:hsqldb:res:。这些数据库是   始终files_readonly并具有与files_readonly相同的限制   档案:目录。

     

这些目录中的CACHED表和LOBS是只读的。它不是   可以在这些目录中创建新的LOB,但您可以使用   新行中的现有LOB