Bre*_*man 5 java sql-server postgresql uuid hibernate
我有一个应用程序,我想在 PostgreSQL 和 SQL Server 上运行。我想使用 java.util.UUID 作为 ID。
我已将 SQL Server 中的列定义为
id UNIQUEIDENTIFIER ROWGUIDCOL NOT NULL UNIQUE
Run Code Online (Sandbox Code Playgroud)
我已将 PostgreSQL 中的列定义为
id UUID NOT NULL
Run Code Online (Sandbox Code Playgroud)
这些列在我的 JPA 实体中定义为
@Id
@Column(name = "id")
public UUID getId() {
return id;
}
Run Code Online (Sandbox Code Playgroud)
这适用于 PostgreSQL,因为它将 UUID 传递给 PostgreSQL JDBC 驱动程序。这种方式适用于 SQL Server,因为 Hibernate 在将 UUID 发送到 SQL Server 之前将其转换为其二进制形式。不幸的是,二进制格式略有不同,导致 GUID 的字符串表示(例如,使用 SSMS 查看它们时)不同,这至少是令人困惑的。
这可以在 SQL Server 中通过将列的类型更改为 uuid-char 来解决
@Id
@Type(type = "uuid-char")
@Column(name = "id")
public UUID getId() {
return id;
}
Run Code Online (Sandbox Code Playgroud)
然而,它在 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()
Run Code Online (Sandbox Code Playgroud)
这只是按原样工作,但不幸的是,Hibernate 中无法为不同的数据库提供不同的列定义,因此这在除 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)" );
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
@TypeDefs( {
@TypeDef( name = "uuid-custom", typeClass = UUIDCustomType.class, defaultForType = UUID.class )
} )
public class BaseEntityWithId {
Run Code Online (Sandbox Code Playgroud)
警告:实际上没有使用 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 );
}
}
Run Code Online (Sandbox Code Playgroud)
该类的灵感来自于 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 );
}
}
Run Code Online (Sandbox Code Playgroud)
我不认为这是最优雅的解决方案,但它目前有效。
| 归档时间: |
|
| 查看次数: |
4286 次 |
| 最近记录: |