[英]Hibernate UUID with PostgreSQL and SQL Server
我有一個應用程序,我想在PostgreSQL和SQL Server上運行。 我想使用java.util.UUID作為ID。
我已經在SQL Server中定義了我的列
id UNIQUEIDENTIFIER ROWGUIDCOL NOT NULL UNIQUE
我已經在PostgreSQL中定義了我的列
id UUID NOT NULL
列在我的JPA實體中定義為
@Id
@Column(name = "id")
public UUID getId() {
return id;
}
這適用於PostgreSQL,因為它將UUID傳遞給PostgreSQL JDBC驅動程序。 這種方式適用於SQL Server,因為Hibernate在將UUID發送到SQL Server之前將其轉換為二進制形式。 不幸的是,二進制格式略有不同 ,導致GUID的字符串表示(例如,當使用SSMS查看它們時)不同,這至少令人困惑。
通過將列的類型更改為uuid-char,可以在SQL Server中解決此問題
@Id
@Type(type = "uuid-char")
@Column(name = "id")
public UUID getId() {
return id;
}
然而它在PostgreSQL中不再起作用,因為在Postgres中沒有從varchar到uuid的隱式映射。
有些人建議改變發電機以產生guid。 這在Postgres中不起作用,因為在PostgreSQL94Dialect中不支持它。
為這兩個數據庫制作這個詞最優雅的解決方案是什么? 我正在考慮使用從UUID到二進制的自定義轉換來創建我自己的SQLServer方言,但我不確定是否可行。
我有類似的要求,但我也想使用Hibernate DDL生成並確保SQL Server生成了uniqueidentifier類型,並且還希望支持hsqldb進行單元測試。 要在SQL Server中使用UUID,您肯定希望通過字符串而非二進制,因為SQL Server中的二進制表示是針對與UUID不同的GUID。 請參閱Java Hibernate和SQL Server中的UUID的不同表示形式
您可以使用以下命令創建正確的映射並為SQL Server生成正確的sql:
@Type(type = "uuid-char")
@Column(columnDefinition="uniqueidentifier")
public UUID getUuid()
這只是按原樣運行,但不幸的是,Hibernate沒有辦法為不同的數據庫設置不同的columnDefinitions,因此除了SQL Server之外,這將失敗。
所以,你必須走很遠的路。 這就是Hibernate 4.3的全部內容:
public class SQLServer2008UnicodeDialect extends SQLServer2008Dialect
{
public SQLServer2008UnicodeDialect()
{
// the const is from the MS JDBC driver, the value is -145
registerColumnType( microsoft.sql.Types.GUID, "uniqueidentifier" );
// etc. Bonus hint: I also remap all the varchar types to nvarchar while I'm at it, like so:
registerColumnType( Types.CLOB, "nvarchar(MAX)" );
registerColumnType( Types.LONGVARCHAR, "nvarchar(MAX)" );
registerColumnType( Types.LONGNVARCHAR, "nvarchar(MAX)" );
registerColumnType( Types.VARCHAR, "nvarchar(MAX)" );
registerColumnType( Types.VARCHAR, 8000, "nvarchar($l)" );
}
}
DatabaseType是我已經根據系統配置設置的枚舉,使用方言類或字符串或其他來修改它。
這是對https://zorq.net/b/2012/04/21/switching-hibernates-uuid-type-mapping-per-database/中描述的內容的修改。
public enum DatabaseType
{
hsqldb,
sqlserver,
mysql,
postgres
}
public class UUIDCustomType extends AbstractSingleColumnStandardBasicType<UUID> implements LiteralType<UUID>
{
private static final long serialVersionUID = 1L;
private static SqlTypeDescriptor SQL_DESCRIPTOR;
private static JavaTypeDescriptor<UUID> TYPE_DESCRIPTOR;
public static void init( DatabaseType databaseType )
{
if ( databaseType == DatabaseType.sqlserver )
{
SQL_DESCRIPTOR = SqlServerUUIDTypeDescriptor.INSTANCE;
}
else if ( databaseType == DatabaseType.postgres )
{
SQL_DESCRIPTOR = PostgresUUIDType.PostgresUUIDSqlTypeDescriptor.INSTANCE;
}
else
{
SQL_DESCRIPTOR = VarcharTypeDescriptor.INSTANCE;
}
TYPE_DESCRIPTOR = UUIDTypeDescriptor.INSTANCE;
}
public UUIDCustomType()
{
super( SQL_DESCRIPTOR, TYPE_DESCRIPTOR );
}
@Override
public String getName()
{
return "uuid-custom";
}
@Override
public String objectToSQLString( UUID value, Dialect dialect ) throws Exception
{
return StringType.INSTANCE.objectToSQLString( value.toString(), dialect );
}
public static class SqlServerUUIDTypeDescriptor extends VarcharTypeDescriptor
{
private static final long serialVersionUID = 1L;
public static final SqlServerUUIDTypeDescriptor INSTANCE = new SqlServerUUIDTypeDescriptor();
public SqlServerUUIDTypeDescriptor()
{
}
@Override
public int getSqlType()
{
return microsoft.sql.Types.GUID;
}
}
}
@TypeDefs( {
@TypeDef( name = "uuid-custom", typeClass = UUIDCustomType.class, defaultForType = UUID.class )
} )
public class BaseEntityWithId {
警告:實際上並沒有使用postgres進行測試,但是對於Hibernate 4.3上的hsqldb和sql server非常有用。
我最后編寫了自己的Dialect和BasicType,默認情況下將Java類型java.util.UUID鏈接到uuid-char。
本課程的靈感來自PostgreSQLDialect
public class MySQLServerDialect extends SQLServer2012Dialect {
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
typeContributions.contributeType( SQLServerUUIDType.INSTANCE );
}
}
本課程的靈感來自UUIDCharType
public class SQLServerUUIDType extends AbstractSingleColumnStandardBasicType<UUID> implements LiteralType<UUID> {
public static final SQLServerUUIDType INSTANCE = new SQLServerUUIDType();
public SQLServerUUIDType() {
super( VarcharTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE );
}
@Override
protected boolean registerUnderJavaType() {
return true;
}
public String getName() {
return "my-uuid";
}
public String objectToSQLString(UUID value, Dialect dialect) throws Exception {
return StringType.INSTANCE.objectToSQLString( value.toString(), dialect );
}
}
我不認為這是最優雅的解決方案,但它現在有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.