为什么Hibernate将joda.money.Money视为VARBINARY?

问题描述

首先,我将向您解释我要去做的事情,而不是我为到达那里所做的事情。

我有一个Amazon RDS实例,并且正在使用Spring + JPA与之交互。在该数据库中,有一个称为“产品”的表。以前,我只是将存储的货币用作数据库中的INT,存储分并在Java中进行转换,效果很好。我一直在尝试使用数据库中的DECIMAL(13,2)类型作为货币,并在Java端使用joda.money.Money稍微清理一下代码。餐桌产品的“货币”列的定义如下所示:

@Column(name = "prodprice",columnDeFinition = "DECIMAL(13,2)")
@Type(type = "org.joda.money.Money",parameters = {@org.hibernate.annotations.Parameter(name = "currencyCode",value = "CAD")})
private Money prodPrice;

我还有另一个名为flower的实体,其货币是这样定义的

@JsonSerialize(using = MoneySerializer.class)
@JsonDeserialize(using = MoneyDeserializer.class)
@Column(name = "priceperpound")
@Type(type = "org.joda.money.Money",value = "CAD")})
private Money pricePerPound;

此实体通过此方法传递给Spring

@PostMapping("/inventory/addproduct/flower")
@Transactional
public ResponseEntity<?> addFlower(
    @RequestBody flower newFlower,@RequestParam String prodName,@RequestParam Integer qtyOnHand,@RequestParam BigDecimal prodPrice,@RequestParam String prodDescription)
{
    Integer newProductID = addNewProduct(prodName,qtyOnHand,Money.of(CurrencyUnit.CAD,prodPrice),prodDescription);
    newFlower.setProdID(newProductID);
    saveEntity(newFlower);
    return ResponseEntity.ok(String.format("Product Added.\n ID : %s",newProductID));
}

问题在于,休眠时在生成插入语句时将产品实体中的Money实例视为VARBINARY而不是DECIMAL。我通过调试准备好的语句发现了这一点。该语句显示为:

    insert 
into
    product
    (proddescription,prodname,prodprice,prodqtyonhand) 
values
    (?,?,?)
2020-09-16 16:18:26.172 TRACE 16576 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder      : 
binding parameter [1] as [VARCHAR] - [Decimal Flower Test]
2020-09-16 16:18:26.173 TRACE 16576 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder      : 
binding parameter [2] as [VARCHAR] - [test3]
2020-09-16 16:18:26.174 TRACE 16576 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder      : 
binding parameter [3] as [VARBINARY] - [CAD 10.25]
2020-09-16 16:18:26.175 TRACE 16576 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder      : 
binding parameter [4] as [INTEGER] - [58]
2020-09-16 16:18:26.359  WARN 16576 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.sqlExceptionHelper   : 
sql Error: 1264,sqlState: 22001
2020-09-16 16:18:26.360 ERROR 16576 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.sqlExceptionHelper   : 
Data truncation: Out of range value for column 'prodPrice' at row 1

我一步步完成了序列化器类,在花实体中处理Money类似乎没有问题。

我尝试过的事情: 将在花实体中找到的相同注释添加到产品实体, 通过尝试使用double来更改从@RequestParam创建Money实例的方式,甚至可以从String(Money.parse(prodPrice))解析Money。最后,休眠似乎总是将货币单位放在实际值的前面,这就是为什么休眠将其视为VARBINARY的原因。令我特别想到的是

o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARBINARY] - [CAD 10.25]

因为它声明的是10.25加元,而不是10.25加元

以前,我也尝试过为休眠设置自己的自定义类型,但我不想走这条路。在这一点上,我对joda.money的信任远胜于我。我应该指出,这是我与Spring JPA进行深度合作的第一次尝试,但我仍然耳熟能详。我使用的MoneySerializer和MoneyDeserializer来自gist.github,您可以通过搜索找到它 gist.github.com上的MoneyDeserializer.java, 两者均由stickfigure发布。

下面是一些有用的摘要

-application.properties

spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:MysqL://DELETEDFORSecurity
spring.datasource.username=DELETEDFORSecurity
spring.datasource.password=DELETEDFORSecurity
logging.level.org.hibernate.sql=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
spring.jpa.properties.hibernate.format_sql=true

-pom.xml依赖项

<dependencies>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.2</version>
    <exclusions>
        <exclusion>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.11.2</version>
</dependency>

    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.11.2</version>

    </dependency>

<dependency>
    <groupId>org.joda</groupId>
    <artifactId>joda-money</artifactId>
    <version>1.0.1</version>
</dependency>
<dependency>
    <groupId>org.joda</groupId>
    <artifactId>joda-convert</artifactId>
    <version>2.2.1</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.6</version>
    </dependency>

    <dependency>
        <groupId>MysqL</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
    <dependency>
        <groupId>org.json</groupId>
        <artifactId>json</artifactId>
        <version>20180130</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <version>2.3.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0</version>
    </dependency>


    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

-方法addNewProduct

private Integer addNewProduct(String productName,Integer qtyOnHand,Money prodPrice,String prodDesc)
{
    Product newProd = buildNewProduct(productName,prodPrice,prodDesc);
    saveEntity(newProd);
    return newProd.getProdID();
}

-方法buildNewProduct

private Product buildNewProduct(String productName,String prodDesc)
{
    return new Product(productName,prodDesc);
}

-方法saveEntity

private void saveEntity(Object obj)
{
    entityManager.persist(obj);
}

如何使用JPA和joda.money将这个值作为DECIMAL(13,2)存储到数据库中? 更好的问题:我在做什么错,从根本上我会误解什么,这个想法有多愚蠢?有更好的方法吗?

代码没有任何生产能力,我只是想学习。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)