如何管理H2数据库上的XmlType

发布于 2024-10-31 21:40:20 字数 2125 浏览 0 评论 0原文

我使用 H2 数据库进行单元测试。 在我的应用程序中,我有一个名为 FooXml 的实体对象,其定义如下:

@Entity
@Table(name = "T_FOOXML")
@SequenceGenerator(allocationSize = 1, name = "S_FOOXML", sequenceName = "S_FOOXML")
@NamedQueries( ... )
@Cache(usage = CacheConcurrencyStrategy.NONE)
public class FooXml implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "S_FOOXML")
    @Column(name = "FOOXML_ID")
    private Integer id;

    @Type(type = "my.app.common.HibernateXMLType")
    @Column(name = "FOOXML_CONTENT")
    @Basic(fetch = FetchType.LAZY)
    private String xmlContent;

    ...

}

因此,为了从数据库读取/写入 XML 内容,我创建了自己的 XMLType,my.app。 common.HibernateXMLType,它实现了org.hibernate.usertype.UserType。 方法 nullSafeSetnullSafeGet 在那里定义。

现在,我想使用 H2 内存数据库进行测试,并且一些测试正在使用这个 FooXml 类。 由于 H2 不支持 Oracle XmlType,因此我必须自定义 my.app.common.HibernateXMLType。 例如,我添加了该部分:

public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
    ...
    // Case where H2 Database is used as the dataSource...
    if (st.getConnection() instanceof org.h2.jdbc.JdbcConnection) {
        // Set the XML as a String...
        st.setObject(index, (String) value);
    } else {
        // Case of "normal" behavior (outside tests context)
        ...
    }
}

我对这种方法有几个顾虑:

  • 我在应用程序的生产代码中添加了直接链接到测试目的的代码(即不在测试代码中);
  • 由于此类依赖于 org.h2.jdbc.JdbcConnection,因此我必须在 WAR 包中添加 h2-database 依赖项。

问题

  • 这是解决我的问题的最佳方法,还是有更好的方法?
  • 有没有办法告诉 Hibernate 使用另一种类型(my.app.common.HibernateXMLTypeForH2 而不是 my.app.common.HibernateXMLType)来进行测试?

ps : 在 H2 数据库中创建表的脚本如下:

create table T_FOO_XML (
    FOOXML_ID NUMBER(9, 0) not null,
    FOOXML_CONTENT CLOB(400000)
);

技术细节:<中使用 H2 数据库 v1.3.153、JUnit 4.8.1、Java 1.6、Hibernate 3.2.2、Oracle 10g em>无测试环境。

I use H2 Database for my unit tests.
In my application, I have an Entity object called FooXml defined like that:

@Entity
@Table(name = "T_FOOXML")
@SequenceGenerator(allocationSize = 1, name = "S_FOOXML", sequenceName = "S_FOOXML")
@NamedQueries( ... )
@Cache(usage = CacheConcurrencyStrategy.NONE)
public class FooXml implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "S_FOOXML")
    @Column(name = "FOOXML_ID")
    private Integer id;

    @Type(type = "my.app.common.HibernateXMLType")
    @Column(name = "FOOXML_CONTENT")
    @Basic(fetch = FetchType.LAZY)
    private String xmlContent;

    ...

}

So in order to read / write the XML content from the Database, I have created my own XMLType, my.app.common.HibernateXMLType, which implements org.hibernate.usertype.UserType.
The methods nullSafeSet and nullSafeGet are defined there.

Now, I want to use a H2 in-memory Database for my tests, and some tests are using this FooXml class.
As H2 does not support The Oracle XmlType, I have to customize my my.app.common.HibernateXMLType.
For example, I added that part:

public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
    ...
    // Case where H2 Database is used as the dataSource...
    if (st.getConnection() instanceof org.h2.jdbc.JdbcConnection) {
        // Set the XML as a String...
        st.setObject(index, (String) value);
    } else {
        // Case of "normal" behavior (outside tests context)
        ...
    }
}

I have several concerns with this approach:

  • I add code that is directly linked to tests purpose in the production code of the application (i.e. not in the test code);
  • As this class depends on org.h2.jdbc.JdbcConnection, I have to add the h2-database dependency in my WAR package.

Questions:

  • Is it the best approach to solve my problem, or is there a better way of doing that?
  • Is there a way to tell Hibernate to use another Type (my.app.common.HibernateXMLTypeForH2 instead of my.app.common.HibernateXMLType) for tests purpose?

ps : The script for creating my table in H2 database is the following:

create table T_FOO_XML (
    FOOXML_ID NUMBER(9, 0) not null,
    FOOXML_CONTENT CLOB(400000)
);

Technical details: H2 Database v1.3.153, JUnit 4.8.1, Java 1.6, Hibernate 3.2.2, Oracle 10g is used in none-test environments.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

死开点丶别碍眼 2024-11-07 21:40:20

我添加了直接链接到的代码
测试生产目的
代码...

在某种程度上,是的,因为你使用 H2 进行测试。但是,您可能会争辩说,您使应用程序更加独立于数据库,并且仅使用 H2 进行测试只是巧合。稍后,您可以使用 H2 作为产品试用版附带的数据库。或者稍后您可以支持除 Oracle 和 H2 之外的其他数据库。

h2-数据库依赖

为了避免对 H2 的编译时依赖,您可以使用:

String url = st.getConnection().getMetaData().getURL();
boolean isH2 = url.startsWith("jdbc:h2:");
if (isH2) {
    ...
}

还有其他方法,例如 getMetaData().getDatabaseProductName().equals("H2") - 基本上与String 而不是 Class 对象。当然,这在编译时并不安全,另一方面,H2 将来可能会返回不同的连接类,因此 JdbcConnection 也不稳定。

I add code that is directly linked to
tests purpose in the production
code...

In a way, yes, because you use H2 for testing. However, you could argue you make your application more database independent, and using H2 for testing only is only a coincidence. Later on, you could use H2 as the database shipped with the trial version of your product. Or you could support other databases in addition to Oracle and H2 later on.

h2-database dependency

To avoid the compile-time dependency on H2, you could use:

String url = st.getConnection().getMetaData().getURL();
boolean isH2 = url.startsWith("jdbc:h2:");
if (isH2) {
    ...
}

There are other ways, for example getMetaData().getDatabaseProductName().equals("H2") - basically compare with a String instead of Class objects. Of course that's not as compile-time safe, on the other hand H2 might return a different connection class in the future, so JdbcConnection is also unstable.

奶气 2024-11-07 21:40:20
public class Oracle10gDialectWithXMLType extends Oracle10gDialect {
    public Oracle10gDialectWithXMLType() {
        registerHibernateType(XMLType._SQL_TYPECODE, "XMLTYPE");
        registerColumnType(XMLType._SQL_TYPECODE, "XMLTYPE");
    }
}

并将其添加为属性中的方言。

public class Oracle10gDialectWithXMLType extends Oracle10gDialect {
    public Oracle10gDialectWithXMLType() {
        registerHibernateType(XMLType._SQL_TYPECODE, "XMLTYPE");
        registerColumnType(XMLType._SQL_TYPECODE, "XMLTYPE");
    }
}

and add it as ur dialect in properties.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文