sql >> Databasteknik >  >> RDS >> PostgreSQL

Viloläge UUID med PostgreSQL och SQL Server

Jag hade liknande krav, men jag ville också använda Hibernate DDL-generering och se till att SQL Server genererade en unik identifieringstyp, och ville även stödja hsqldb för enhetstestning. För att använda UUID i SQL Server vill du definitivt gå igenom strängar som inte är binära , eftersom den binära representationen i SQL Server är för en GUID som skiljer sig från en UUID. Se till exempel Olika representation av UUID i Java Hibernate och SQL Server

Du kan skapa rätt mappning och skapa rätt sql för SQL Server med:

@Type(type = "uuid-char")
@Column(columnDefinition="uniqueidentifier")
public UUID getUuid()

Och detta fungerar bara som det är, men tyvärr finns det inget sätt i Hibernate att ha olika kolumndefinitioner för olika databaser, så detta kommer att misslyckas på något annat än SQL Server.

Så du måste gå den långa vägen runt. Detta är allt för Hibernate 4.3:

  1. Registrera en ny GUID sql-typ i en åsidosatt SQLServerDialect, och använd denna dialekt istället för basen

    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)" );
        }
     }
  1. Skapa en wrapper UUIDCustomType som beter sig liknande den inbyggda UUIDCharType men delegerar beroende på databastyp. Du måste anropa init(databaseType) före Hibernate-konfiguration. Kanske den anpassade dialekten skulle kunna göra det, men jag kallar detta i min Spring-appstart.

DatabaseType var en enum jag redan hade som är inställd baserat på systemkonfiguration, ändra den efter smak med hjälp av en dialektklass eller sträng eller vad som helst.

Det här är en variant på vad som beskrivs på 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;
        }
    }
}
  1. Registrera den anpassade typen på en plats som Hibernate kommer att hämta (jag har en gemensam basklass för alla enheter). Jag registrerar den med defaultForType =UUID.class så att alla UUID använder den, vilket innebär att jag inte behöver kommentera UUID-egenskaper alls.

    @TypeDefs( {
            @TypeDef( name = "uuid-custom", typeClass = UUIDCustomType.class, defaultForType = UUID.class )
    } )
    public class BaseEntityWithId { 

Varning:faktiskt inte testad med postgres, men fungerar utmärkt för hsqldb och sql-server på Hibernate 4.3.



  1. Ta bort dubbletter av rader från en liten tabell

  2. Lär dig databasdesign med SQL Server Management Studio (SSMS) – Del 2

  3. JSON_INSERT() vs JSON_SET() vs JSON_REPLACE() i SQLite

  4. Varför ska jag använda int istället för en byte eller short i C#