首先,大多數人的印象裏,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 }