2010-03-10 4 views
8

db4o과 같은 객체 데이터베이스를 사용하는 것에 대해 계속 혼란스러워하는 한 가지 방법은 일반적으로 SQL/PL-SQL에 의해 처리되는 복잡한 마이그레이션을 처리하는 방법입니다.db4o와 같은 객체 데이터베이스의 데이터 유지 관리

예를 들어 my_users라는 관계형 데이터베이스에 테이블이 있다고 가정합니다. 처음에는 "full_name"이라는 열이 있었으므로 소프트웨어가이 열을 제거하고 빈 공간에 전체 이름을 나눠서 첫 번째 부분을 "first_name"이라는 열에 넣고 두 번째 열을 열에 넣으려고했습니다 이름은 last_name입니다. SQL에서는 "first_name"및 "second_name"열을 채우고 "full_name"이라는 원래 열을 제거합니다.

db4o와 같은 방법으로 어떻게 처리 할 수 ​​있습니까? first_name과 last_name을 설정하면서 full_name을 null로 설정하고 User.class의 모든 객체를 검색하는 스크립트를 작성하는 Java 프로그램을 작성합니까? 내가 다음 svn 커밋을 할 때 full_name에 해당하는 필드/bean 속성이 없을 것입니다. 이것이 문제가됩니까? "스키마"가 변경되는 프로덕션 응용 프로그램에서 사용하는 것처럼 보입니다. 버전 x에서 버전 x + 1로 데이터를 마이그레이션하는 스크립트를 작성한 다음 버전 x + 2에서 실제로 시도하려는 속성을 제거합니다. 더 이상 내 유형의 일부인 속성을 수정하기 위해 Java 스크립트를 작성할 수 없으므로 버전 x + 1을 제거하십시오.

문제의 일부는 Java 유형 지정과 같은 언어에서 간단한 대소 문자를 구분하지 않는 문자열 기반 이름을 기반으로 참조하는 객체를 RDBMS가 해결한다는 것입니다. 이보다 더 복잡한 것은 getter/setter/field가 런타임에로드 된 클래스의 멤버가 아니므로 동일한 스크립트에 2 가지 버전의 코드가 있어야합니다 (사용자 정의 클래스 로더가 통증처럼 들릴 수 있음). 새 버전의 저장된 클래스가 다른 패키지에 속해 있거나 지저분한 소리가 들리거나 언급 한 x + 1 x + 2 전략을 사용하십시오 (더 많은 계획이 필요합니다). 아마도 db4o 문서에서 수집하지 않은 확실한 해결책이있을 것입니다.

아이디어가 있으십니까? 희망적으로 이것은 약간 이해된다.

답변

10

먼저 db4o는 '단순한'scenarios like adding or removing a field automatically을 처리합니다. 필드를 추가하면 기존의 모든 객체에 기본값이 저장됩니다. 필드를 제거하면 기존 개체의 데이터가 데이터베이스에 남아 있으므로 계속 액세스 할 수 있습니다. 이름 바꾸기 필드 등은 special 'refactoring'-calls입니다.

지금 당신의 시나리오는 당신이 뭔가를 할 것이다 :

  1. 새로운 필드 'FIRST_NAME'과 'second_name'모든 것을
  2. 반복 처리를 추가 필드 'FULL_NAME를'제거 '
  3. 을 Address'가-객체
  4. 'StoredClass'-API를 통해 이전 필드에 액세스
  5. 값을 분할, 변경, 업데이트 등. 새 필드에 새 값을 설정하고 객체를 저장합니다.

'주소'클래스가 있다고 가정 해 보겠습니다. 'full_name'필드가 삭제되었습니다. 이제 우리는 그것을 '성'과 '성'에 복사하지 않아도됩니다. 그러면 다음과 같이 바뀔 수 있습니다. (Java) :

ObjectSet<Address> addresses = db.query(Address.class); 
    StoredField metaInfoOfField = db.ext().storedClass(Address.class).storedField("full_name", String.class); 
    for (Address address : addresses) { 
     String fullName = (String)metaInfoOfField.get(address); 
     String[] splitName = fullName.split(" "); 
     address.setFirstname(splitName[0]); 
     address.setSurname(splitName[1]); 
     db.store(address); 
    } 

제안한 것처럼 각 버전 - 범프에 대해 마이그레이션 코드를 작성합니다. 필드가 더 이상 클래스의 일부가 아니므로 위와 같이 'StoredField'-API를 사용하여 필드에 액세스해야합니다.

ObjectContainer.ext().storedClasses()으로 모든 '저장된'클래스의 목록을 가져올 수 있습니다. StoredClass.getStoredFields()을 사용하면 모든 상점 필드의 목록을 가져올 수 있으며 더 이상 필드가 클래스에 존재하지 않습니다. 클래스가 더 이상 존재하지 않으면 객체를 가져 와서 'GenericObject'클래스를 통해 액세스 할 수 있습니다.

업데이트 : 데이터베이스를 여러 버전 단계로 마이그레이션해야하는 복잡한 시나리오의 경우.

예를 들어 버전 v3에서는 주소 개체가 완전히 다르게 보입니다. 그래서 v1에서 v2 로의 'migration-script'는 더 이상 필드를 필요로하지 않습니다 (필자의 예에서는 firstname과 surename). 나는 이것을 처리 할 수있는 여러 가지 가능성이 있다고 생각한다.

  1. (이 아이디어에는 Java가 사용됩니다. 물론 .NET에는 이에 상응하는 것이 있습니다). 마이그레이션 단계를 Groovy-script으로 만들 수 있습니다. 그래서 각 스크립트는 다른 스크립트와 간섭하지 않습니다. 그런 다음 마이그레이션에 필요한 클래스를 '클래스'로 정의합니다. 따라서 각 마이그레이션에는 고유 한 마이그레이션 클래스가 있습니다. aliases을 사용하면 Groovy 마이그레이션 클래스를 실제 Java 클래스에 바인딩 할 수 있습니다.
  2. 복잡한 시나리오에 대한 리팩토링 클래스 만들기. 또한이 클래스를 aliases으로 바인딩하십시오.
2

나는 내 인생에서 너무 많은 데이터를 리팩토링하지 않았기 때문에 여기에서 약간의 야생 촬영을하고 있습니다.

당신이 이상한 비교를하고 있습니다 : db를 '핫 마이 그 레이션'하기를 원한다면, 아마도 x+1, x+2 버전 관리 방법을 사용해야 할 것입니다. 내가 DB 전문가가 아니기 때문에 SQL로 이것을 수행하는 방법을 알지 못한다.

'콜드'를 마이그레이션하는 경우 이전 데이터에서 새 개체를 인스턴스화하고 새 개체를 저장하고 저장소의 각 개체에 대해 이전 개체를 삭제하면됩니다. db4o reference을 참조하십시오.

솔직히 : RDBMS의 동일한 프로세스는 조작을 실제로 수행하기 위해 제한 조건 검사 (가능하면 트리거 등)를 비활성화해야하기 때문에 복잡합니다. 예를 들어 제공 한 예제가 아닐 수도 있습니다. 그러나 대부분의 현실 세계의 경우. 결국, 문자열 분할은 거의 이득이 없을 정도로 쉽습니다.

가 SQL에서 나는 단순히 간단한 문자열 분할 작업으로, "FIRST_NAME"와 "second_name"열

을 채울 것입니다, 당신은 단순히 그렇게 할 수 있습니다. 하지만 일반적인 리팩토링 시나리오에서는 SQL로 쉽게 표현되지 않거나 복잡한 계산 또는 외부 데이터 소스가 필요할 수도있는 크고 복잡한 규칙 세트를 기반으로 오브젝트를 재구성하고 있습니다.

이렇게하려면 코드도 작성해야합니다.

결국 두 프로세스에서 너무 많은 차이점을 볼 수 없습니다. 실시간 데이터는 항상주의해야하며 두 경우 모두 확실히 백업 할 것입니다. 리팩토링은 재미 있지만 지속성은 까다롭기 때문에 어떤 경우에도 동기화가 어려워집니다.