MySQL로 버전 관리 시스템 구현


15

나는 이것이 여기여기 에서 요청되었다는 것을 알고 있지만 가능한 다른 구현과 같은 아이디어를 가지고 있으며 도움이 필요합니다.

처음에는 blogstories이 구조로 내 테이블을 가지고있었습니다 .

| Column    | Type        | Description                                    |
|-----------|-------------|------------------------------------------------|
| uid       | varchar(15) | 15 characters unique generated id              |
| title     | varchar(60) | story title                                    |
| content   | longtext    | story content                                  |
| author    | varchar(10) | id of the user that originally wrote the story |
| timestamp | int         | integer generated with microtime()             |

블로그의 모든 스토리에 대해 일부 버전 관리 시스템을 구현하기로 결정한 후 가장 먼저 떠오르는 것은 편집 을위한 다른 테이블을 만드는 것입니다 . 그 후, 편집 대신 버전 을 유지하도록 기존 테이블을 수정할 수 있다고 생각했습니다 . 이것은 내 마음에 온 구조입니다.

| Column        | Type          | Description                                       |
|------------   |-------------  |------------------------------------------------   |
| story_id      | varchar(15)   | 15 characters unique generated id                 |
| version_id    | varchar(5)    | 5 characters unique generated id                  |
| editor_id     | varchar(10)   | id of the user that commited                      |
| author_id     | varchar(10)   | id of the user that originally wrote the story    |
| timestamp     | int           | integer generated with microtime()                |
| title         | varchar(60)   | current story title                               |
| content       | longtext      | current story text                                |
| coverimg      | varchar(20)   | cover image name                                  |

내가 여기 온 이유 :

  • uid초기 테이블 의 필드는 테이블에서 고유했습니다. 이제는 story_id더 이상 고유하지 않습니다. 어떻게 처리해야합니까? (저는 story_id = x최신 버전을 다루고 찾을 수 있다고 생각 했지만 리소스를 많이 소비하는 것으로 보이므로 조언을 부탁드립니다.)
  • author_id필드 값은 테이블의 각 행마다 반복됩니다. 어디에 어떻게 보관해야합니까?

편집하다

고유 코드 생성 프로세스는 다음과 CreateUniqueCode같습니다.

trait UIDFactory {
  public function CryptoRand(int $min, int $max): int {
    $range = $max - $min;
    if ($range < 1) return $min;
    $log = ceil(log($range, 2));
    $bytes = (int) ($log / 8) + 1;
    $bits = (int) $log + 1;
    $filter = (int) (1 << $bits) - 1;
    do {
        $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
        $rnd = $rnd & $filter;
    } while ($rnd >= $range);
    return $min + $rnd;
  }
  public function CreateUID(int $length): string {
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    $max = strlen($codeAlphabet) - 1;
    for ($i=0; $i < $length; $i++) {
        $token .= $codeAlphabet[$this->CryptoRand(0, $max)];
    }
    return $token;
  }
}

코드로 작성 해킹 , 원래에 의해 PHP로 작성된 @Scott 자신의 대답 .

필드 author_id와는 editor_id 할 수 있습니다 편집 사람의 이야기에 충분한 권한이있는 사용자가 있기 때문에, 다른.

답변:


23

선물 특성으로 알려진 주제와 관련된 - 어떤 시나리오 분석 시간 데이터베이스 - 개념의 관점에서를, 하나는 결정할 수 : (a)는 "현재 ' 스토리 버전 블로그 와 (b)는"과거 " 블로그 스토리 버전을 매우 비록 서로 다른 유형의 엔티티입니다.

또한 논리적 추상화 레벨에서 작업 할 때 고유 한 종류의 사실 (행으로 표시됨)을 고유 한 테이블에 보유해야합니다. 고려중인 경우, 상당히 유사하더라도 (i)“현재” 버전 에 대한 사실은 (ii)“과거” 버전에 대한 사실과 다릅니다 .

따라서 두 테이블을 사용하여 상황을 관리하는 것이 좋습니다.

  • "현재"또는 "현재"전용으로 전용 한 버전블로그 이야기 하고,

  • 하나는 모든 "이전"또는 "과거" 버전에 대해 별도이지만 다른 하나와 연결되어 있습니다 .

각각 (1) 약간 다른 수의 열과 (2) 다른 제약 조건 그룹이 있습니다.

개념적 계층으로 돌아가서 비즈니스 환경에서 작성자편집자사용자 가 수행 할 수있는 역할 로 묘사 될 수있는 개념 이며, 이러한 중요한 측면은 데이터 파생 (논리 수준 조작 조작을 통해) 에 따라 다릅니다. 및 해석 (에 의해 실시 블로그 사례 하나 개 이상의 응용 프로그램의 도움으로, 전산 정보 시스템의 외부 수준에서, 독자와 작가).

이러한 모든 요소와 기타 관련 사항을 다음과 같이 자세히 설명하겠습니다.

비즈니스 규칙

귀하의 요구 사항에 대한 나의 이해에 따르면, 다음과 같은 비즈니스 규칙 공식 (관련 엔티티 유형 및 해당 상호 관계의 종류로 정리)은 해당 개념 스키마 를 설정하는 데 특히 도움이됩니다 .

  • 사용자는 제로 하나 또는-많은 기록 BlogStories을
  • BlogStory은 제로 일 또는 일대 보유 BlogStoryVersions을
  • 사용자가 제로 일 또는 일대 다 쓴 BlogStoryVersions을

설명 IDEF1X 다이어그램

따라서 그래픽 디바이스 인하여 내 제안을 상세히 설명하기 위해, I 샘플 IDEF1X 작성한 관련된 것 이상으로 비지니스 규칙 제형 및 다른 특징으로부터 도출된다 다이어그램. 그것은에 나타낸다 도 1 :

그림 1-블로그 스토리 버전 IDEF1X 다이어그램

BlogStoryBlogStoryVersion 이 두 개의 다른 엔티티 유형으로 개념화됩니까?

때문에:

  • BlogStoryVersion의 경우 (즉, "과거"한) 항상 값 보유 UpdatedDateTime에 잠시 속성을 BlogStory 발생이 (즉, "현재"사람이) 결코를 보유하지 않습니다.

  • 또한 해당 유형의 엔티티는 BlogStoryNumber ( BlogStory 발생의 경우) 및 BlogStoryNumberCreatedDateTime ( BlogStoryVersion 인스턴스 의 경우)이라는 두 가지 고유 한 특성 세트 값으로 고유하게 식별됩니다 .


정보 모델링을위한 통합 정의 ( IDEF1X는 )이 설립되었다 매우 추천 할 데이터 모델링 기술이다 표준 미국 12 월 1993 년 국립 표준 기술 연구소 (NIST). 그것은 초기의 이론적 자료에 근거은에 의해 작성된 유일한 발신자 관계형 모델 즉, 박사 EF 커드 ; 온 개체 - 관계 에 의해 개발 된 데이터의보기 박사 PP 첸 ; 또한 Robert G. Brown이 만든 논리 데이터베이스 디자인 기술에 대해서도 설명합니다.


예시적인 논리적 SQL-DDL 레이아웃

그런 다음 이전에 제시 한 개념적 분석을 기반으로 아래에서 논리적 수준 설계를 선언했습니다.

-- You should determine which are the most fitting 
-- data types and sizes for all your table columns 
-- depending on your business context characteristics.

-- Also you should make accurate tests to define the most
-- convenient index strategies at the physical level.

-- As one would expect, you are free to make use of 
-- your preferred (or required) naming conventions.    

CREATE TABLE UserProfile (
    UserId          INT      NOT NULL,
    FirstName       CHAR(30) NOT NULL,
    LastName        CHAR(30) NOT NULL,
    BirthDate       DATETIME NOT NULL,
    GenderCode      CHAR(3)  NOT NULL,
    UserName        CHAR(20) NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT UserProfile_PK  PRIMARY KEY (UserId),
    CONSTRAINT UserProfile_AK1 UNIQUE ( -- Composite ALTERNATE KEY.
        FirstName,
        LastName,
        BirthDate,
        GenderCode
    ), 
    CONSTRAINT UserProfile_AK2 UNIQUE (UserName) -- ALTERNATE KEY.
);

CREATE TABLE BlogStory (
    BlogStoryNumber INT      NOT NULL,
    Title           CHAR(60) NOT NULL,
    Content         TEXT     NOT NULL,
    CoverImageName  CHAR(30) NOT NULL,
    IsActive        BIT(1)   NOT NULL,
    AuthorId        INT      NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT BlogStory_PK              PRIMARY KEY (BlogStoryNumber),
    CONSTRAINT BlogStory_AK              UNIQUE      (Title), -- ALTERNATE KEY.
    CONSTRAINT BlogStoryToUserProfile_FK FOREIGN KEY (AuthorId)
        REFERENCES UserProfile (UserId)
);

CREATE TABLE BlogStoryVersion  (
    BlogStoryNumber INT      NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    Title           CHAR(60) NOT NULL,
    Content         TEXT     NOT NULL,
    CoverImageName  CHAR(30) NOT NULL,
    IsActive        BIT(1)   NOT NULL,
    AuthorId        INT      NOT NULL,
    UpdatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT BlogStoryVersion_PK              PRIMARY KEY (BlogStoryNumber, CreatedDateTime), -- Composite PK.
    CONSTRAINT BlogStoryVersionToBlogStory_FK   FOREIGN KEY (BlogStoryNumber)
        REFERENCES BlogStory (BlogStoryNumber),
    CONSTRAINT BlogStoryVersionToUserProfile_FK FOREIGN KEY (AuthorId)
        REFERENCES UserProfile (UserId),
    CONSTRAINT DatesSuccession_CK               CHECK       (UpdatedDateTime > CreatedDateTime) --Let us hope that MySQL will finally enforce CHECK constraints in a near future version.
);

MySQL 5.6에서 실행 되는이 SQL Fiddle에서 테스트 되었습니다 .

BlogStory테이블

데모 디자인에서 볼 수 있듯이 BlogStoryPRINTARY KEY (PK 간결) 열을 INT 데이터 유형으로 정의했습니다. 이와 관련하여 모든 행 삽입에서 이러한 열에 숫자 값을 생성하고 지정하는 기본 제공 자동 프로세스를 수정하려고 할 수 있습니다. 이 값 집합에서 간헐적으로 공백을 남기지 않으려면 MySQL 환경에서 일반적으로 사용되는 AUTO_INCREMENT 속성을 사용할 수 있습니다.

모든 개별 BlogStory.CreatedDateTime데이터 포인트를 입력 할 때 NOW () 함수를 사용할 수 있습니다. NOW () 함수 는 정확한 INSERT 조작 순간에 데이터베이스 서버에서 현재 날짜 및 시간 값을 리턴합니다 . 나 에게이 연습은 외부 루틴을 사용하는 것보다 결정적으로 더 적합하고 오류가 덜 발생합니다.

(현재 제거 된) 주석에서 설명한대로 BlogStory.Title중복 값 을 유지할 가능성을 피하려면 이 열에 대해 UNIQUE 제약 조건 을 설정해야합니다 . 주어진 제목 이 여러 개의 (또는 모든) "과거" BlogStoryVersions에 의해 공유 될 수 있기 때문에 열에 대해 UNIQUE 제약 조건을 설정 하지 않아야 합니다 BlogStoryVersion.Title.

“소프트”또는“논리적”DELETE 기능을 제공해야하는 경우를 대비 하여 BIT (1)BlogStory.IsActive 유형 의 열 ( TINYINT 도 사용 가능)을 포함 시켰습니다 .

BlogStoryVersion테이블 에 대한 세부 사항

한편, BlogStoryVersion테이블 의 PK는 물론 (a) BlogStoryNumber와 (b)로 명명 된 열로 구성되며 CreatedDateTime, 물론 BlogStory행이 INSERT를 거친 정확한 순간을 표시합니다 .

BlogStoryVersion.BlogStoryNumber는 PK의 일부일뿐 아니라이 두 테이블의 행 사이에 참조 무결성BlogStory.BlogStoryNumber 을 강제하는 구성 인을 참조하는 FORKNK (FK)로 제한됩니다 . 이와 관련 하여 FK로 설정하면이 열에 INSERT 된 값이 관련 상대방 에 이미 포함 된 값에서 "인출"되어야하므로 자동 생성 a를 구현할 필요가 없습니다 .BlogStoryVersion.BlogStoryNumberBlogStory.BlogStoryNumber

BlogStoryVersion.UpdatedDateTime열이 예상대로 유지해야하는 시점에 BlogStory로우가 추가, 결과적으로 수정 된 BlogStoryVersion테이블. 따라서이 상황에서도 NOW () 함수를 사용할 수 있습니다.

간격 간의 이해 BlogStoryVersion.CreatedDateTimeBlogStoryVersion.UpdatedDateTime전체 표현 기간 동안 BlogStory행 "본"또는 "현재"하였다.

Version열에 대한 고려 사항

생각하는 것이 유용 할 수 있습니다 BlogStoryVersion.CreatedDateTime특정 "과거"나타내는 값 보유하고있는 열로 버전BlogStory을 . 사람들이 시간 개념에 더 익숙한 경향이 있다는 점에서 사용자에게 친숙하기 때문에 나는 VersionIdor 보다 훨씬 더 유익하다고 생각합니다 . 예를 들어 블로그 작성자 또는 독자 는 다음과 유사한 방식 으로 BlogStoryVersion 을 참조 할 수 있습니다 .VersionCode

  • "나는 특정보고 싶어 버전BlogStory 식별 번호 1750 되었다 만든 에서 26 August 2015시를 9:30".

저자편집자의 역할 : 데이터 유도 및 해석

이 방법, 당신은 쉽게 "원래"보유하고있는 구별 할 수 AuthorId콘크리트의 BlogStory 은 "최초"를 선택 버전 특정의를 BlogStoryId으로부터 BlogStoryVersion인가 덕분에 테이블 MIN () 함수 로를 BlogStoryVersion.CreatedDateTime.

이런 식으로, 모든 "나중"또는 "성공" 버전 행에 BlogStoryVersion.AuthorId포함 된 각 값 은 당연히 각 버전작성자 식별자를 나타내지 만, 이러한 값은 동시에 역할 침범에 의해 연주 사용자편집기 은 "원래"의 버전BlogStory .

예, 주어진 AuthorId값은 여러 BlogStoryVersion행 으로 공유 될 수 있지만 실제로는 각 버전 에 대해 매우 중요한 정보를 알려주는 정보 이므로 해당 데이텀의 반복은 문제 가 되지 않습니다 .

DATETIME 열의 형식

DATETIME 데이터 유형에 관해서는 그렇습니다.“ MySQLYYYY-MM-DD HH:MM:SSDATETIME 값을 ' '형식으로 검색하여 표시합니다. ' 이지만이 방법으로 관련 데이터를 자신있게 입력 할 수 있으며 쿼리를 수행해야 할 때 내장 된 DATE 및 TIME 함수 를 사용하여 관련 값을 사용자에게 적합한 형식으로 표시하십시오. 또는 애플리케이션 프로그램 코드를 통해 이러한 종류의 데이터 형식을 수행 할 수도 있습니다.

BlogStoryUPDATE 조작의 의미

• 그래도 때마다 BlogStory행에 UPDATE를 앓고, 당신은 확인해야 수정이 발생한 때까지 "현재"했다 대응하는 값은 다음에 삽입되는 BlogStoryVersion테이블. 따라서 단일 ACID 거래 내에서 이러한 작업을 수행 하여 개별 작업 단위로 취급되도록하는 것이 좋습니다 . TRIGGERS를 채용 할 수도 있지만 말을하기에는 어수선한 경향이 있습니다.

VersionId또는 VersionCode열 소개

BlogStoryVersions 를 구별하기 위해 (비즈니스 환경 또는 개인 선호로 인해) BlogStory.VersionId또는 BlogStory.VersionCode열을 통합하도록 선택 하면 다음 가능성을 고려해야합니다.

  1. A VersionCode는 (i) 전체 BlogStory테이블과 (ii)에서 고유해야합니다 BlogStoryVersion.

    따라서 각 값 을 생성하고 할당하려면 신중하게 테스트되고 완전히 신뢰할 수있는 방법 을 구현 해야Code 합니다.

  2. 어쩌면 VersionCode값이 다른 BlogStory행 에서 반복 될 수 는 있지만 결코 같은 행과 중복 되지는 않습니다BlogStoryNumber . 예를 들어 다음과 같은 이점이 있습니다.

    • BlogStoryNumber 3- 버전83o7c5c 동시에,
    • BlogStoryNumber 86- 버전83o7c5c
    • BlogStoryNumber 958- 버전83o7c5c .

후자의 가능성은 또 다른 대안을 엽니 다.

  1. 유지 VersionNumber에 대한 것은 BlogStories, 그래서이있을 수 있습니다 :

    • BlogStoryNumber- 23버전1, 2, 3… ;
    • BlogStoryNumber- 650버전1, 2, 3… ;
    • BlogStoryNumber- 2254버전1, 2, 3… ;
    • 기타

단일 테이블에 "원본"및 "후속"버전 유지

모든 BlogStoryVersion동일한 개별 기본 테이블 에 유지하는 것이 가능하지만 두 가지 구별되는 (개념적) 유형의 사실을 혼합하므로 바람직하지 않은 부작용이 있으므로 수행하지 않는 것이 좋습니다.

  • 데이터 제약 및 조작 (논리 수준에서)
  • 관련 처리 및 저장 (물리적 계층)

그러나 해당 행동 과정을 따르기로 선택한 경우에도 위에서 설명한 여러 가지 아이디어를 활용할 수 있습니다.

  • 복합 지능 컬럼 (이루어진 PK BlogStoryNumber) 및 DATETIME 컬럼 ( CreatedDateTime);
  • 적절한 프로세스를 최적화하기위한 서버 기능 의 사용
  • 저자편집자 유도 역할 .

이러한 접근 방식을 진행함으로써 “최신” 버전 이 추가 되 자마자 BlogStoryNumber값이 복제 되고 평가할 수있는 옵션 (이전 섹션에서 언급 한 것과 매우 유사 함)이 PK를 설정한다는 것을 알 수 있습니다. 열로 구성 하고 , 이러한 방식으로는 유일하게 각 식별 할 수있을 것입니다 버전BlogStory을 . 그리고 당신은의 조합으로 시도 할 수 및 도.BlogStoryBlogStoryNumberVersionCodeBlogStoryNumberVersionNumber

비슷한 시나리오

관련 데이터베이스에서 일시적인 기능을 사용하여 비슷한 시나리오를 처리 할 수 있도록 제안 하기 때문에이 도움말 질문 에 대한 답변을 찾을 수 있습니다 .


2

하나의 옵션은 Version Normal Form (vnf)을 사용하는 것입니다. 장점은 다음과 같습니다.

  • 현재 데이터와 모든 과거 데이터는 동일한 테이블에 있습니다.
  • 동일한 날짜가 현재 날짜 또는 특정 날짜의 최신 데이터를 검색하는 데 사용됩니다.
  • 버전이 지정된 데이터에 대한 외래 키 참조는 버전이없는 데이터의 경우와 동일하게 작동합니다.

버전 화 된 데이터는 키의 유효 날짜 (변경 날짜)를 만들어 고유하게 식별되므로 별도의 version_id 필드는 필요하지 않습니다.

다음 은 매우 유사한 유형의 엔티티에 대한 설명입니다.

자세한 내용은 여기 슬라이드 프레젠테이션 및 완성되지 않은 문서 에서 확인할 수 있습니다.


1

당신의 관계

(story_id, version_id, editor_id, author_id, 타임 스탬프, 제목, 컨텐츠, coverimg)

세 번째 정규 형식이 아닙니다. 스토리의 모든 버전에 대해 author_id는 동일합니다. 이를 극복하기 위해서는 두 가지 관계가 필요합니다

(story_id, author_id)
(story_id, version_id, editor_id, 타임 스탬프, 제목, 내용, coverimg)

첫 번째 관계 story_id의 핵심은 두 번째 관계의 핵심이 결합 된 키 (story_id, version_id)입니다. 당신이 결합 된 키 좋아하지 않는 경우에만 사용할 수 있습니다 version_id키로


2
이것은 내 문제를 해결하는 것 같지 않고 단지 강조합니다
Victor

따라서 쿼리에 응답하지 않습니다. ' author_id 필드 값이 테이블의 각 행마다 반복됩니다. 어디에서 어떻게 보관해야 합니까?
miracle173

2
나는 당신의 대답이 무엇인지 이해하지 못합니다. 내가 영어를 모국어가 아니기 때문일 수 있으므로 좀 더 간단한 단어로 설명해 주시겠습니까?
Victor

즉, author_id 번호의 반복을 피하고 (story_id가 두 행에 대해 같으면 author_id도 같음) 내 게시물에 설명 된 것처럼 테이블을 두 테이블로 분할해야합니다. 따라서 author_id의 반복을 피할 수 있습니다.
miracle173
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.