sql >> データベース >  >> RDS >> Mysql

Rails 5 Mysql UUID

    私の答えは@santoshの答えの更新です。ここで説明するすべてのベストプラクティスを取り入れています:

    simple_uuidを使用しています 「v1」UUIDを生成できるためgem。 Rubyの組み込みのSecureRandom.uuid v4を生成します。 v1が必要です。これは、UUIDの一部としてタイムスタンプを組み込んでいるためです。上記のリンクを読んで、理解を深めてください。 MySQLのUUID() 関数はv1UUIDを生成します。

    app / models / concerns / binary_uuid_pk.rb

    module BinaryUuidPk
      extend ActiveSupport::Concern
    
      included do
        before_validation :set_id, on: :create
        validates :id, presence: true
      end
    
      def set_id
        uuid_object = SimpleUUID::UUID.new
        uuid_string = ApplicationRecord.rearrange_time_of_uuid( uuid_object.to_guid )
        uuid_binary = ApplicationRecord.id_binary( uuid_string )
        self.id = uuid_binary
      end
    
      def uuid
        self[:uuid] || (id.present? ? ApplicationRecord.format_uuid_with_hyphens( id.unpack('H*').first ).upcase : nil)
      end
    
    
      module ClassMethods
        def format_uuid_with_hyphens( uuid_string_without_hyphens )
          uuid_string_without_hyphens.rjust(32, '0').gsub(/^(.{8})(.{4})(.{4})(.{4})(.{12})$/, '\1-\2-\3-\4-\5')
        end
    
        def rearrange_time_of_uuid( uuid_string )
          uuid_string_without_hyphens = "#{uuid_string[14, 4]}#{uuid_string[9, 4]}#{uuid_string[0, 8]}#{uuid_string[19, 4]}#{uuid_string[24..-1]}"
          ApplicationRecord.format_uuid_with_hyphens( uuid_string_without_hyphens )
        end
    
        def id_binary( uuid_string )
          # Alternate way: Array(uuid_string.downcase.gsub(/[^a-f0-9]/, '')).pack('H*')
          SimpleUUID::UUID.new( uuid_string ).to_s
        end
    
        def id_str( uuid_binary_string )
          SimpleUUID::UUID.new( uuid_binary_string ).to_guid
        end
    
        # Support both binary and text as IDs
        def find( *ids )
          ids = [ids] unless ids.is_a?( Array )
          ids = ids.flatten
    
          array_binary_ids = ids.each_with_object( [] ) do |id, array|
            case id
              when Integer
                raise TypeError, 'Expecting only 36 character UUID strings as primary keys'
              else
                array <<  SimpleUUID::UUID.new( id ).to_s
    
            end
          end
    
          super( array_binary_ids )
        end
      end
    end
    

    app / models / application_record.rb

    ## ApplicationRecord (new parent of all models in Rails 5)
    class ApplicationRecord < ActiveRecord::Base
      self.abstract_class = true
    
      include BinaryUuidPk
    end
    

    これで、すべてのモデルが最適化されたUUID主キーをサポートするようになります。

    サンプルの移行

    class CreateUserProfiles < ActiveRecord::Migration[5.0]
      def change
        create_table :user_profiles, id: false do |t|
          t.binary :id, limit: 16, primary_key: true, null: false
          t.virtual :uuid, type: :string, limit: 36, as: "insert( insert( insert( insert( hex(id),9,0,'-' ), 14,0,'-' ), 19,0,'-' ), 24,0,'-' )"
          t.index :uuid, unique: true
    
          t.string :name, null: false
          t.string :gender, null: false
          t.date :date_of_birth
          t.timestamps null: false
        end
    
        execute <<-SQL
          CREATE TRIGGER before_insert_user_profiles
            BEFORE INSERT ON user_profiles
            FOR EACH ROW
            BEGIN
              IF new.id IS NULL THEN
                SET new.id = UUID_TO_BIN(uuid(), 1);
              END IF;
            END
        SQL
      end
    end
    

    UUID_TO_BIN()を追加します MySQLDBへの機能

    DELIMITER //
    CREATE FUNCTION UUID_TO_BIN(string_uuid BINARY(36), swap_flag INT)
            RETURNS BINARY(16)
            LANGUAGE SQL  DETERMINISTIC  CONTAINS SQL  SQL SECURITY INVOKER
          RETURN
            UNHEX(CONCAT(
                SUBSTR(string_uuid, 15, 4),
                SUBSTR(string_uuid, 10, 4),
                SUBSTR(string_uuid,  1, 8),
                SUBSTR(string_uuid, 20, 4),
                SUBSTR(string_uuid, 25) ));
    //
    DELIMITER ;
    

    上記の関数はMySQL8.0以降に組み込まれています。執筆時点では、8.0はまだGAではありません。そこで、とりあえず関数を追加します。しかし、私は関数のシグネチャをMySQL8.0にあるものと同じに保ちました。したがって、8.0に移行しても、すべての移行とトリガーは引き続き機能します。



    1. sqldeveloperの挿入ステートメントからBLOB列に挿入するにはどうすればよいですか?

    2. Googleドキュメントをデータベースとして使用していますか?

    3. MySQLとJava-最後に挿入された値のIDを取得します(JDBC)

    4. ダウンタイムなしでMySQLをAmazonEC2からオンプレミスデータセンターに移行する方法