복붙노트

[SQL] 64 기수 문자열로 저장 UUID

SQL

64 기수 문자열로 저장 UUID

나는 데이터베이스 키로 UUID를 사용하여 실험을하고있다. 난 여전히 UUID 표현 인간의 읽을 수를 유지하면서, 가능한 바이트의 최소 금액을 먹고 싶어.

나는 22 바이트 64 기수를 사용하여 내 목적을 위해 저장하는 불필요한 것 같다 일부 후행 "=="제거에 내려받은 것을 생각한다. 이 방법에 어떤 결함이 있습니까?

기본적으로 내 테스트 코드는 22 바이트 문자열 아래로 UUID를 얻기 위해 변환의 무리를 수행 한 다음 다시 UUID로 변환합니다.

import java.io.IOException;
import java.util.UUID;

public class UUIDTest {

    public static void main(String[] args){
        UUID uuid = UUID.randomUUID();
        System.out.println("UUID String: " + uuid.toString());
        System.out.println("Number of Bytes: " + uuid.toString().getBytes().length);
        System.out.println();

        byte[] uuidArr = asByteArray(uuid);
        System.out.print("UUID Byte Array: ");
        for(byte b: uuidArr){
            System.out.print(b +" ");
        }
        System.out.println();
        System.out.println("Number of Bytes: " + uuidArr.length);
        System.out.println();


        try {
            // Convert a byte array to base64 string
            String s = new sun.misc.BASE64Encoder().encode(uuidArr);
            System.out.println("UUID Base64 String: " +s);
            System.out.println("Number of Bytes: " + s.getBytes().length);
            System.out.println();


            String trimmed = s.split("=")[0];
            System.out.println("UUID Base64 String Trimmed: " +trimmed);
            System.out.println("Number of Bytes: " + trimmed.getBytes().length);
            System.out.println();

            // Convert base64 string to a byte array
            byte[] backArr = new sun.misc.BASE64Decoder().decodeBuffer(trimmed);
            System.out.print("Back to UUID Byte Array: ");
            for(byte b: backArr){
                System.out.print(b +" ");
            }
            System.out.println();
            System.out.println("Number of Bytes: " + backArr.length);

            byte[] fixedArr = new byte[16];
            for(int i= 0; i<16; i++){
                fixedArr[i] = backArr[i];
            }
            System.out.println();
            System.out.print("Fixed UUID Byte Array: ");
            for(byte b: fixedArr){
                System.out.print(b +" ");
            }
            System.out.println();
            System.out.println("Number of Bytes: " + fixedArr.length);

            System.out.println();
            UUID newUUID = toUUID(fixedArr);
            System.out.println("UUID String: " + newUUID.toString());
            System.out.println("Number of Bytes: " + newUUID.toString().getBytes().length);
            System.out.println();

            System.out.println("Equal to Start UUID? "+newUUID.equals(uuid));
            if(!newUUID.equals(uuid)){
                System.exit(0);
            }


        } catch (IOException e) {
        }

    }


    public static byte[] asByteArray(UUID uuid) {

        long msb = uuid.getMostSignificantBits();
        long lsb = uuid.getLeastSignificantBits();
        byte[] buffer = new byte[16];

        for (int i = 0; i < 8; i++) {
            buffer[i] = (byte) (msb >>> 8 * (7 - i));
        }
        for (int i = 8; i < 16; i++) {
            buffer[i] = (byte) (lsb >>> 8 * (7 - i));
        }

        return buffer;

    }

    public static UUID toUUID(byte[] byteArray) {

        long msb = 0;
        long lsb = 0;
        for (int i = 0; i < 8; i++)
            msb = (msb << 8) | (byteArray[i] & 0xff);
        for (int i = 8; i < 16; i++)
            lsb = (lsb << 8) | (byteArray[i] & 0xff);
        UUID result = new UUID(msb, lsb);

        return result;
    }

}

산출:

UUID String: cdaed56d-8712-414d-b346-01905d0026fe
Number of Bytes: 36

UUID Byte Array: -51 -82 -43 109 -121 18 65 77 -77 70 1 -112 93 0 38 -2 
Number of Bytes: 16

UUID Base64 String: za7VbYcSQU2zRgGQXQAm/g==
Number of Bytes: 24

UUID Base64 String Trimmed: za7VbYcSQU2zRgGQXQAm/g
Number of Bytes: 22

Back to UUID Byte Array: -51 -82 -43 109 -121 18 65 77 -77 70 1 -112 93 0 38 -2 0 38 
Number of Bytes: 18

Fixed UUID Byte Array: -51 -82 -43 109 -121 18 65 77 -77 70 1 -112 93 0 38 -2 
Number of Bytes: 16

UUID String: cdaed56d-8712-414d-b346-01905d0026fe
Number of Bytes: 36

Equal to Start UUID? true

해결법

  1. ==============================

    1.당신은 안전하게 응용 프로그램에서 패딩을 "=="드롭 할 수 있습니다. 당신이 바이트베이스 (64) 텍스트 등을 디코딩한다면, 대부분의 도서관은있을 것으로 예상,하지만 당신은 단지 키로 결과 문자열을 사용하고 있기 때문에, 그것은 문제가되지 않습니다.

    당신은 안전하게 응용 프로그램에서 패딩을 "=="드롭 할 수 있습니다. 당신이 바이트베이스 (64) 텍스트 등을 디코딩한다면, 대부분의 도서관은있을 것으로 예상,하지만 당신은 단지 키로 결과 문자열을 사용하고 있기 때문에, 그것은 문제가되지 않습니다.

    I와 같은 자료-64 제한된 문자가 덜 횡설수설 같은 외모를 설정할 수 있지만 자료-85는 또한 거기에 있기 때문이다. 당신은 20 자까지의 텍스트를 얻을 수 있도록 그것은 더 많은 문자 및 코드 (5 개) 문자로 4 바이트를 사용합니다.

  2. ==============================

    2.나는 또한 비슷한 일을하려고했다. 나는 형태의 UUID를 사용하는 Java 응용 프로그램과 함께하고 있어요 6fcb514b-b878-4c9d-95b7-8dc3a7ce6fd8 (자바의 표준 UUID lib 디렉토리에 생성되는). 내 경우에는 내가 이하 30 자이 UUID를 얻을 수있을 필요가 있었다. 나는 Base64로를 사용하고이 내 편리한 기능입니다. 이 솔루션은 바로 나에게 분명 아니었다 잘만 그들은 누군가를 위해 도움이 될 것입니다.

    나는 또한 비슷한 일을하려고했다. 나는 형태의 UUID를 사용하는 Java 응용 프로그램과 함께하고 있어요 6fcb514b-b878-4c9d-95b7-8dc3a7ce6fd8 (자바의 표준 UUID lib 디렉토리에 생성되는). 내 경우에는 내가 이하 30 자이 UUID를 얻을 수있을 필요가 있었다. 나는 Base64로를 사용하고이 내 편리한 기능입니다. 이 솔루션은 바로 나에게 분명 아니었다 잘만 그들은 누군가를 위해 도움이 될 것입니다.

    용법:

    String uuid_str = "6fcb514b-b878-4c9d-95b7-8dc3a7ce6fd8";
    String uuid_as_64 = uuidToBase64(uuid_str);
    System.out.println("as base64: "+uuid_as_64);
    System.out.println("as uuid: "+uuidFromBase64(uuid_as_64));
    

    산출:

    as base64: b8tRS7h4TJ2Vt43Dp85v2A
    as uuid  : 6fcb514b-b878-4c9d-95b7-8dc3a7ce6fd8
    

    기능 :

    import org.apache.commons.codec.binary.Base64;
    
    private static String uuidToBase64(String str) {
        Base64 base64 = new Base64();
        UUID uuid = UUID.fromString(str);
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(uuid.getMostSignificantBits());
        bb.putLong(uuid.getLeastSignificantBits());
        return base64.encodeBase64URLSafeString(bb.array());
    }
    private static String uuidFromBase64(String str) {
        Base64 base64 = new Base64(); 
        byte[] bytes = base64.decodeBase64(str);
        ByteBuffer bb = ByteBuffer.wrap(bytes);
        UUID uuid = new UUID(bb.getLong(), bb.getLong());
        return uuid.toString();
    }
    
  3. ==============================

    3.나는 거의 정확히하고있어 응용 프로그램이 있습니다. UUID는 22 문자 인코딩. 그것은 잘 작동합니다. 그러나, 나는이 방법을하고있어 주된 이유는 ID가 웹 응용 프로그램의 URI에 노출되어 있으며, 36 개 문자 뭔가 정말 아주 큰하는 URI에 나타납니다. 22 자 좀 긴 여전히, 그러나 우리는 할 수 있도록.

    나는 거의 정확히하고있어 응용 프로그램이 있습니다. UUID는 22 문자 인코딩. 그것은 잘 작동합니다. 그러나, 나는이 방법을하고있어 주된 이유는 ID가 웹 응용 프로그램의 URI에 노출되어 있으며, 36 개 문자 뭔가 정말 아주 큰하는 URI에 나타납니다. 22 자 좀 긴 여전히, 그러나 우리는 할 수 있도록.

    다음은이의 루비 코드는 다음과 같습니다

      # Make an array of 64 URL-safe characters
      CHARS64 = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["-", "_"]
      # Return a 22 byte URL-safe string, encoded six bits at a time using 64 characters
      def to_s22
        integer = self.to_i # UUID as a raw integer
        rval = ""
        22.times do
          c = (integer & 0x3F)
          rval += CHARS64[c]
          integer = integer >> 6
        end
        return rval.reverse
      end
    

    그것은 바로 그들이 URI 경로 구성 요소에서 나타나는 경우 이스케이프해야 base64로 사용하는 문자 때문에 인코딩 base64로 같은 아니에요. 자바 구현은 더 많은 가능성이 대신에 정말 큰 정수의 원시 바이트의 배열을 가지고있어 이후 전혀 다른 될 가능성이 높습니다.

  4. ==============================

    4.여기 내 코드는 길이가 22 자입니다 (및 UUID와 같은 고유성을 가질 수) URL 안전 고유의 문자열을 생산하는 org.apache.commons.codec.binary.Base64를 사용합니다.

    여기 내 코드는 길이가 22 자입니다 (및 UUID와 같은 고유성을 가질 수) URL 안전 고유의 문자열을 생산하는 org.apache.commons.codec.binary.Base64를 사용합니다.

    private static Base64 BASE64 = new Base64(true);
    public static String generateKey(){
        UUID uuid = UUID.randomUUID();
        byte[] uuidArray = KeyGenerator.toByteArray(uuid);
        byte[] encodedArray = BASE64.encode(uuidArray);
        String returnValue = new String(encodedArray);
        returnValue = StringUtils.removeEnd(returnValue, "\r\n");
        return returnValue;
    }
    public static UUID convertKey(String key){
        UUID returnValue = null;
        if(StringUtils.isNotBlank(key)){
            // Convert base64 string to a byte array
            byte[] decodedArray = BASE64.decode(key);
            returnValue = KeyGenerator.fromByteArray(decodedArray);
        }
        return returnValue;
    }
    private static byte[] toByteArray(UUID uuid) {
        byte[] byteArray = new byte[(Long.SIZE / Byte.SIZE) * 2];
        ByteBuffer buffer = ByteBuffer.wrap(byteArray);
        LongBuffer longBuffer = buffer.asLongBuffer();
        longBuffer.put(new long[] { uuid.getMostSignificantBits(), uuid.getLeastSignificantBits() });
        return byteArray;
    }
    private static UUID fromByteArray(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        LongBuffer longBuffer = buffer.asLongBuffer();
        return new UUID(longBuffer.get(0), longBuffer.get(1));
    }
    
  5. ==============================

    5.당신은 당신이 사용하고있는 DBMS 무슨 말을하지 않습니다,하지만 당신은 공간을 절약에 대해 우려하는 경우 RAW가 가장 좋은 방법이 될 것으로 보인다. 당신은 모든 쿼리에 대한 변환을 기억해야합니다, 또는 당신은 큰 성능 저하 위험이 있습니다.

    당신은 당신이 사용하고있는 DBMS 무슨 말을하지 않습니다,하지만 당신은 공간을 절약에 대해 우려하는 경우 RAW가 가장 좋은 방법이 될 것으로 보인다. 당신은 모든 쿼리에 대한 변환을 기억해야합니다, 또는 당신은 큰 성능 저하 위험이 있습니다.

    입니다 당신이 살고있는 곳을 정말 비싼 것을 바이트 :하지만 물어 봐야?

  6. ==============================

    6.여기 JDK8 도입 java.util.Base64와 예이다 :

    여기 JDK8 도입 java.util.Base64와 예이다 :

    import java.nio.ByteBuffer;
    import java.util.Base64;
    import java.util.Base64.Encoder;
    import java.util.UUID;
    
    public class Uuid64 {
    
      private static final Encoder BASE64_URL_ENCODER = Base64.getUrlEncoder().withoutPadding();
    
      public static void main(String[] args) {
        // String uuidStr = UUID.randomUUID().toString();
        String uuidStr = "eb55c9cc-1fc1-43da-9adb-d9c66bb259ad";
        String uuid64 = uuidHexToUuid64(uuidStr);
        System.out.println(uuid64); //=> 61XJzB_BQ9qa29nGa7JZrQ
        System.out.println(uuid64.length()); //=> 22
        String uuidHex = uuid64ToUuidHex(uuid64);
        System.out.println(uuidHex); //=> eb55c9cc-1fc1-43da-9adb-d9c66bb259ad
      }
    
      public static String uuidHexToUuid64(String uuidStr) {
        UUID uuid = UUID.fromString(uuidStr);
        byte[] bytes = uuidToBytes(uuid);
        return BASE64_URL_ENCODER.encodeToString(bytes);
      }
    
      public static String uuid64ToUuidHex(String uuid64) {
        byte[] decoded = Base64.getUrlDecoder().decode(uuid64);
        UUID uuid = uuidFromBytes(decoded);
        return uuid.toString();
      }
    
      public static byte[] uuidToBytes(UUID uuid) {
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(uuid.getMostSignificantBits());
        bb.putLong(uuid.getLeastSignificantBits());
        return bb.array();
      }
    
      public static UUID uuidFromBytes(byte[] decoded) {
        ByteBuffer bb = ByteBuffer.wrap(decoded);
        long mostSigBits = bb.getLong();
        long leastSigBits = bb.getLong();
        return new UUID(mostSigBits, leastSigBits);
      }
    }
    

    Base64로 인코딩 된 UUID는 URL의 안전하고 패딩하지 않고있다.

  7. ==============================

    7.// GitHub의하십시오 Clojure의 라이브러리 구현이 UUID를의 컴팩트 한 26 문자의 URL 안전 표시 (HTTPS가 : 이것은 당신이 (가 Base64로하지 않습니다)를 요구하지만, 가치 때문에 유연성의,보고 정확히 아니다 .COM / tonsky / 컴팩트의 UUID).

    // GitHub의하십시오 Clojure의 라이브러리 구현이 UUID를의 컴팩트 한 26 문자의 URL 안전 표시 (HTTPS가 : 이것은 당신이 (가 Base64로하지 않습니다)를 요구하지만, 가치 때문에 유연성의,보고 정확히 아니다 .COM / tonsky / 컴팩트의 UUID).

    일부 하이라이트 :

    이들은 오히려 좋은 속성입니다. 나는 데이터베이스 키와 사용자가 볼 수있는 식별자 모두 내 응용 프로그램에서이 인코딩을 사용하고, 그리고 그것은 매우 잘 작동합니다.

  8. ==============================

    8.아래는 내가 UUID (빗 스타일)에 사용하는 것입니다. 그것은 64 기수에 대한 UUID 문자열 또는 UUID 형식을 변환하는 코드가 포함되어 있습니다. 내가 어떤 등호를 처리하지 않도록 나는, 64 비트 당을 수행합니다

    아래는 내가 UUID (빗 스타일)에 사용하는 것입니다. 그것은 64 기수에 대한 UUID 문자열 또는 UUID 형식을 변환하는 코드가 포함되어 있습니다. 내가 어떤 등호를 처리하지 않도록 나는, 64 비트 당을 수행합니다

    import java.util.Calendar;
    import java.util.UUID;
    import org.apache.commons.codec.binary.Base64;
    
    public class UUIDUtil{
        public static UUID combUUID(){
            private UUID srcUUID = UUID.randomUUID();
            private java.sql.Timestamp ts = new java.sql.Timestamp(Calendar.getInstance().getTime().getTime());
    
            long upper16OfLowerUUID = this.zeroLower48BitsOfLong( srcUUID.getLeastSignificantBits() );
            long lower48Time = UUIDUtil.zeroUpper16BitsOfLong( ts );
            long lowerLongForNewUUID = upper16OfLowerUUID | lower48Time;
            return new UUID( srcUUID.getMostSignificantBits(), lowerLongForNewUUID );
        }   
        public static base64URLSafeOfUUIDObject( UUID uuid ){
            byte[] bytes = ByteBuffer.allocate(16).putLong(0, uuid.getLeastSignificantBits()).putLong(8, uuid.getMostSignificantBits()).array();
            return Base64.encodeBase64URLSafeString( bytes );
        }
        public static base64URLSafeOfUUIDString( String uuidString ){
        UUID uuid = UUID.fromString( uuidString );
            return UUIDUtil.base64URLSafeOfUUIDObject( uuid );
        }
        private static long zeroLower48BitsOfLong( long longVar ){
            long upper16BitMask =  -281474976710656L;
            return longVar & upper16BitMask;
        }
        private static void zeroUpper16BitsOfLong( long longVar ){
            long lower48BitMask =  281474976710656L-1L;
            return longVar & lower48BitMask;
        }
    }
    
  9. from https://stackoverflow.com/questions/772802/storing-uuid-as-base64-string by cc-by-sa and MIT license