【问题标题】:Proper use of org.joda.time.contrib.hibernate.PersistentDateTime with webapp configured for different timezone than db正确使用 org.joda.time.contrib.hibernate.PersistentDateTime 和 webapp 配置为与 db 不同的时区
【发布时间】:2011-11-17 13:52:16
【问题描述】:

我相信这已经被多次遇到过,并且在其他地方也有过报道。提前为这篇冗长的帖子道歉,但我想在前面提供尽可能多的细节。

我有一台在一个时区(在我的情况下为 -07:00)运行 JVM 的工作站。我有一个配置为以 UTC 保存日期值的 Oracle 数据库。

我正在尝试使用具有自定义 Hibernate 类型的 jodatime 扩展 http://www.joda.org/joda-time-hibernate/,其中之一是 PersistentDateTime。

这是我的 .hbm.xml 中的一个示例。

<hibernate-mapping>
<class name="com.spp.mui.domain.MktBidHourly" table="MKTBIDHOURLY">
    <comment>Entity to represent the hourly participant bids</comment>
    <id name="bidId" type="big_decimal">
        <column name="BIDID" precision="22" scale="0" />
        <generator class="foreign">
            <param name="property">mktBid</param>
        </generator>
    </id>
    <one-to-one name="mktBid" class="com.spp.mui.domain.MktAbstractBid" constrained="true"></one-to-one>

    <property name="period" type="org.joda.time.contrib.hibernate.PersistentDateTime">
        <column name="PERIOD" length="7">
            <comment>Identifies the Period for which the bid applies.</comment>
        </column>
    </property>
    <property name="bidCurveId" type="big_decimal">
        <column name="BIDCURVEID" precision="22" scale="0">
            <comment>A database-generated unique identifier for the bid curve</comment>
        </column>
    </property>
</class>

注意 MktBidHourly 中的期间字段。

因此,在为我的一个 DAO(使用 Spring)执行单元测试之前,我使用 Toad(用于 Oracle)之类的工具来插入一些数据,这些数据将在测试中被查询,例如

插入 MKTBIDHOURLY 值 (33, (select to_timestamp('2011-08-03 13:00', 'YYYY-MM-DD HH24:MI') 来自双), 298384);

我的 DAO 中的 Hibernate 查询看起来有点像这样

public static final String QRY_FIND_BIDS =
        "from MktBid bid where bid.priceNodeId in (:priceNodeIdList) and bid.mktBidHourly.period in (:periodsList) and bid.mktBidType = (:bidType) and bid.participantId = (:participantId)";

 Query q = getSession().createQuery(MktQueries.QRY_FIND_BIDS);
        q.setParameterList("priceNodeIdList", priceNodeIds);
        q.setParameterList("periodsList", periods);
        q.setEntity("bidType", bidType);
        q.setBigDecimal("participantId", participantId);
        realBids = q.list();

这是测试方法

@Test
public void testFindVirtualBids() throws ParseException {
    List<MktVirtualBid> candidateBids = new ArrayList<MktVirtualBid>();
    MktBidType bidType = new MktBidType(MktBid.VIRTUAL_BID);
    candidateBids.add(data.createMktVirtualBid(new BigDecimal(LOCATION_ID_1), false, timeDispatcher.getDateTimeFromXMLDateTime("2011-08-03T13:00:00-07:00"), new BigDecimal(CURVE_ID_1)));
    candidateBids.add(data.createMktVirtualBid(new BigDecimal(LOCATION_ID_2), false, timeDispatcher.getDateTimeFromXMLDateTime("2011-08-04T13:00:00-07:00"), new BigDecimal(CURVE_ID_2)));
    List<MktVirtualBid> foundBids = dao.findVirtualBids(bidType, new BigDecimal(PARTICIPANT_ID), candidateBids);
    Assert.assertEquals(2, foundBids.size());
}

注意 timeDispatcher 方法正在使用

ISODateTimeFormat.dateTimeParser().withZone(DateTimeZone.getDefault())

作为格式化程序,然后

parseDateTime(xmlDateTime).withZone(DateTimeZone.UTC)

获取日期时间。

这是测试运行的一些示例输出(抱歉格式不佳)

16:22:31,729 DEBUG [AbstractBatcher] 即将打开 PreparedStatement(打开 PreparedStatements:0,全局:0)
16:22:31,732 调试 [SQL]
选择
mktbid0_.BIDID 为 BIDID5_,
mktbid0_.BIDTYPE 为 BIDTYPE5_,
mktbid0_.PARTICIPANTID 为 PARTICIP3_5_,
mktbid0_.PNODEID 为 PNODEID5_,
mktbid0_.USEBIDSLOPE 作为 USEBIDSL5_5_
来自
DEVMOI2.MKTBID mktbid0_,
DEVMOI2.MKTBIDHOURLY mktbidhour1_
在哪里
mktbid0_.BIDID=mktbidhour1_.BIDID
和 (
mktbid0_.PNODEID 在 (
? , ?
)
)
和 (
mktbidhour1_.PERIOD in (
? , ?
)
)
和 mktbid0_.BIDTYPE=?
和 mktbid0_.PARTICIPANTID=?休眠:
选择
mktbid0_.BIDID 为 BIDID5_,
mktbid0_.BIDTYPE 为 BIDTYPE5_,
mktbid0_.PARTICIPANTID 为 PARTICIP3_5_,
mktbid0_.PNODEID 为 PNODEID5_,
mktbid0_.USEBIDSLOPE 作为 USEBIDSL5_5_
来自
DEVMOI2.MKTBID mktbid0_,
DEVMOI2.MKTBIDHOURLY mktbidhour1_
在哪里
mktbid0_.BIDID=mktbidhour1_.BIDID
和 (
mktbid0_.PNODEID 在 (
? , ?
)
)
和 (
mktbidhour1_.PERIOD in (
? , ?
)
)
和 mktbid0_.BIDTYPE=?
和 mktbid0_.PARTICIPANTID=?
16:22:31,733 TRACE [AbstractBatcher] 准备声明
16:22:31,798 TRACE [BasicBinder] 绑定参数 [1] 作为 [NUMERIC] - 262235
16:22:31,798 TRACE [BasicBinder] 绑定参数 [2] 作为 [NUMERIC] - 262234
16:22:31,799 TRACE [BasicBinder] 绑定参数 [3] 作为 [TIMESTAMP] - 2011 年 8 月 3 日星期三 13:00:00 PDT
16:22:31,799 TRACE [BasicBinder] 绑定参数 [4] 作为 [TIMESTAMP] - 2011 年 8 月 4 日星期四 13:00:00 PDT
16:22:31,801 TRACE [BasicBinder] 绑定参数 [5] 作为 [VARCHAR] - D
16:22:31,801 TRACE [BasicBinder] 绑定参数 [6] 作为 [NUMERIC] - 260699

然后测试失败

结果:

失败的测试:
testFindVirtualBids(com.spp.mui.persistence.hibernate.MktBidDAOTest):预期: 但为:

测试运行:2,失败:1,错误:0,跳过:0

为什么我的测试断言没有通过?

【问题讨论】:

  • 我应该补充一点,当我尝试运行 Hibernate 发出的查询时,用 Toad 之类的工具替换参数值会得到结果。

标签: oracle hibernate spring timezone jodatime


【解决方案1】:

我自己解决了这个问题。我如何插入日期的棘手部分。我选择了另一条路线,不幸的是我无法分享代码。可以说我开发了一个测试基类,其中包含用于加载 CSV 文件的例程。它利用了 Spring 的 TestContext 框架,特别是一个 @BeforeTransaction 注释方法,它委托给助手处理各种字符串类型(例如,日期、数字、字节 [] 等)。

格式化程序基本正确。对于那些好奇的人timeDispatcher的方法impl看起来是这样的......

 public DateTime getDateTimeFromXMLDateTime(String xmlDateTime) {  
    if(xmlDateTime == null || "".equals(xmlDateTime)) {  
        return null;  
    } else {  
        return isoParser.parseDateTime(xmlDateTime).withZone(gmtTZ);  
    }  
}  

在哪里

isoParser = ISODateTimeFormat.dateTimeParser(DateTimeZone.getDefault());  

gmtTZ = DateTimeZone.UTC;  

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 2023-02-21
    • 2013-11-05
    • 2020-10-17
    相关资源
    最近更新 更多