JPA使用pg資料庫時,bool欄位不能跨庫遷移的解決方案

漫漫人生路总会错几步發表於2024-05-13

首先,大多數人的印象裡,hibernate作為一個笨重學習成本高的近乎全自動的框架它的優點就是可以支援很多資料庫,但是最近研究發現,java中的boolean型別的欄位,在mariadb/mysql 中為bit 0/1,在sqlserver/oracle中為bit 0/1 numeric(1,0) check * in (0,1),然而在PG資料庫中卻是bool,因為pg就是支援boolean到bool的對映

所以,java中的boolean 在除PG的資料庫之外的幾個常見資料庫中儲存的都是 0/1,這就導致了資料遷移時會出現不相容的問題。

在GPT的幫助下,經研究hibernate的資料庫方言發現,可以透過修改官方的方言以達到實現相容的目的。

相關程式碼如下:

 1 package com.example.demo.jpa.dialect;
 2 
 3 import java.sql.Types;
 4 
 5 import org.hibernate.boot.model.TypeContributions;
 6 import org.hibernate.dialect.PostgreSQLDialect;
 7 import org.hibernate.service.ServiceRegistry;
 8 import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
 9 import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
10 
11 /***
12  * 將java中的bool 處理成pg中的numeric(1,0)
13  * 
14  *
15  */
16 public class PgDialect extends PostgreSQLDialect {
17 
18     @Override
19     public int getPreferredSqlTypeCodeForBoolean() {
20         return Types.NUMERIC;
21     }
22 
23     @Override
24     public String toBooleanValueString(boolean bool) {
25         // 將布林值對映為 numeric(1, 0)
26         return bool ? "1" : "0";
27     }
28 
29     @Override
30     public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
31         super.contributeTypes(typeContributions, serviceRegistry);
32         // 把java中的Boolean轉為0/1 把資料庫中的0/1 轉為Boolean
33         typeContributions.getTypeConfiguration().getJavaTypeRegistry().addDescriptor(new PgBooleanJavaType());
34         final DdlTypeRegistry ddlTypeRegistry = typeContributions.getTypeConfiguration().getDdlTypeRegistry();
35         ddlTypeRegistry.addDescriptor(new DdlTypeImpl(Types.BOOLEAN, "numeric(1,0) ", this));
36     }
37 
38 }

 1 package com.example.demo.jpa.dialect;
 2 
 3 import java.math.BigDecimal;
 4 import java.util.Objects;
 5 
 6 import org.hibernate.type.descriptor.WrapperOptions;
 7 import org.hibernate.type.descriptor.java.BooleanJavaType;
 8 
 9 /**
10  * 當從資料庫的欄位型別為Boolean時,如何與java中的boolean互相對映
11  *
12  */
13 public class PgBooleanJavaType extends BooleanJavaType {
14 
15     private static final long serialVersionUID = 1L;
16 
17     @SuppressWarnings("unchecked")
18     @Override
19     public <X> X unwrap(Boolean value, Class<X> type, WrapperOptions options) {
20         if (value == null) {
21             return null;
22         } else if (BigDecimal.class.isAssignableFrom(type)) {
23             return (X) (Objects.equals(true, value) ? new BigDecimal(1) : new BigDecimal(0));
24         } else if (Boolean.class.equals(type)) {
25             return (X) value;
26         } else if (Byte.class.equals(type)) {
27             return (X) toByte(value);
28         }
29         if (Short.class.equals(type)) {
30             return (X) toShort(value);
31         } else if (Integer.class.equals(type)) {
32             return (X) toInteger(value);
33         } else if (Long.class.equals(type)) {
34             return (X) toLong(value);
35         } else if (Character.class.equals(type)) {
36             return (X) Character.valueOf(value ? '1' : '0');
37         } else if (String.class.equals(type)) {
38             return (X) (value ? "1" : "0");
39         }
40         throw unknownUnwrap(type);
41     }
42 
43 }

相關文章