MVCC 데이터베이스 설계를 가장 잘 처리할 수 있는 ORM 프레임워크는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/46709

  •  09-06-2019
  •  | 
  •  

문제

MVCC(다중 버전 동시성 제어)를 사용하도록 데이터베이스를 설계할 때 "IsLatest"와 같은 부울 필드 또는 정수 "VersionId"를 사용하여 테이블을 생성하고 업데이트를 수행하지 않으며 상황이 변경될 때만 새 레코드를 삽입합니다.

MVCC는 자세한 기록이 필요한 애플리케이션에 대한 자동 감사를 제공하고 업데이트 잠금과 ​​관련하여 데이터베이스에 대한 부담을 덜어줍니다.단점은 최신 버전을 얻는 데 필요한 추가 조항으로 인해 데이터 크기가 훨씬 커지고 선택 속도가 느려진다는 것입니다.또한 외래 키를 더욱 복잡하게 만듭니다.

(참고로 저는 ~ 아니다 SQL Server의 스냅샷 격리 수준과 같은 RDBMS의 기본 MVCC 지원에 대해 이야기합니다.)

이 내용은 Stack Overflow의 다른 게시물에서 논의되었습니다.[할 일 - 링크]

널리 사용되는 엔터티/ORM 프레임워크(Linq에서 Sql, ADO.NET EF, Hibernate 등) 중 어떤 것이 이러한 유형의 디자인을 완벽하게 지원할 수 있는지 궁금합니다.이는 일반적인 ActiveRecord 디자인 패턴에 대한 주요 변경 사항이므로 현재 나와 있는 대부분의 도구가 데이터 모델을 사용하여 이 경로를 선택하는 사람에게 도움이 될 수 있는지 확실하지 않습니다.나는 MVCC를 지원하기 위해 외래 키를 데이터 모델링하는 가장 좋은 방법조차 확신하지 못하기 때문에 외래 키를 처리하는 방법에 특히 관심이 있습니다.

도움이 되었습니까?

해결책

데이터 작업을 처리하기 위해 저장된 프로세스와 뷰를 사용하여 순수하게 DB에 MVCC 계층을 구현하는 것을 고려할 수 있습니다.그런 다음 저장된 프로세스에 매핑할 수 있는 ORM에 합리적인 API를 제공할 수 있고 DB가 데이터 무결성 문제를 처리하도록 할 수 있습니다(이를 위한 빌드이기 때문에).이런 식으로 진행했다면 IBatis 또는 IBatis.net과 같은 보다 순수한 매핑 솔루션을 살펴보고 싶을 수도 있습니다.

다른 팁

비슷한 방식으로 데이터베이스를 설계했습니다(INSERT만 사용, UPDATE는 사용하지 않고 DELETE는 사용하지 않음).

거의 모든 SELECT 쿼리는 각 테이블의 현재 행(가장 높은 개정 번호)에 대한 뷰에 대한 것이었습니다.

뷰는 이런 느낌이었는데...

SELECT
    dbo.tblBook.BookId,
    dbo.tblBook.RevisionId,
    dbo.tblBook.Title,
    dbo.tblBook.AuthorId,
    dbo.tblBook.Price,
    dbo.tblBook.Deleted
FROM
    dbo.tblBook INNER JOIN
    (
        SELECT
            BookId,
            MAX(RevisionId) AS RevisionId
        FROM
            dbo.tblBook
        GROUP BY
            BookId
    ) AS CurrentBookRevision ON
    dbo.tblBook.BookId = CurrentBookRevision.BookId AND
    dbo.tblBook.RevisionId = CurrentBookRevision.RevisionId
WHERE
    dbo.tblBook.Deleted = 0

그리고 내 삽입(및 업데이트 및 삭제)은 모두 저장 프로시저(테이블당 하나)에 의해 처리되었습니다.

저장 프로시저는 다음과 같았습니다.

ALTER procedure [dbo].[sp_Book_CreateUpdateDelete]
    @BookId      uniqueidentifier,
    @RevisionId  bigint,
    @Title       varchar(256),
    @AuthorId    uniqueidentifier,
    @Price       smallmoney,
    @Deleted     bit
as
    insert into tblBook
        (
            BookId,
            RevisionId,
            Title,
            AuthorId,
            Price,
            Deleted
        )
    values
        (
            @BookId,
            @RevisionId,
            @Title,
            @AuthorId,
            @Price,
            @Deleted
        )

개정 번호는 Visual Basic 코드에서 트랜잭션별로 처리되었습니다.

Shared Sub Save(ByVal UserId As Guid, ByVal Explanation As String, ByVal Commands As Collections.Generic.Queue(Of SqlCommand))
    Dim Connection As SqlConnection = New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("Connection").ConnectionString)
    Connection.Open()
    Dim Transaction As SqlTransaction = Connection.BeginTransaction
    Try
        Dim RevisionId As Integer = Nothing
        Dim RevisionCommand As SqlCommand = New SqlCommand("sp_Revision_Create", Connection)
        RevisionCommand.CommandType = CommandType.StoredProcedure
        RevisionCommand.Parameters.AddWithValue("@RevisionId", 0)
        RevisionCommand.Parameters(0).SqlDbType = SqlDbType.BigInt
        RevisionCommand.Parameters(0).Direction = ParameterDirection.Output
        RevisionCommand.Parameters.AddWithValue("@UserId", UserId)
        RevisionCommand.Parameters.AddWithValue("@Explanation", Explanation)
        RevisionCommand.Transaction = Transaction
        LogDatabaseActivity(RevisionCommand)
        If RevisionCommand.ExecuteNonQuery() = 1 Then 'rows inserted
            RevisionId = CInt(RevisionCommand.Parameters(0).Value) 'generated key
        Else
            Throw New Exception("Zero rows affected.")
        End If
        For Each Command As SqlCommand In Commands
            Command.Connection = Connection
            Command.Transaction = Transaction
            Command.CommandType = CommandType.StoredProcedure
            Command.Parameters.AddWithValue("@RevisionId", RevisionId)
            LogDatabaseActivity(Command)
            If Command.ExecuteNonQuery() < 1 Then 'rows inserted
                Throw New Exception("Zero rows affected.")
            End If
        Next
        Transaction.Commit()
    Catch ex As Exception
        Transaction.Rollback()
        Throw New Exception("Rolled back transaction", ex)
    Finally
        Connection.Close()
    End Try
End Sub

각 테이블에 대해 생성자, 인스턴스 속성 및 메서드, 생성-업데이트-삭제 명령, 다양한 찾기 기능 및 IComparable 정렬 기능이 포함된 개체를 만들었습니다.엄청난 양의 코드였습니다.

VB 개체에 대한 일대일 DB 테이블...

Public Class Book
    Implements iComparable

#Region " Constructors "

    Private _BookId As Guid
    Private _RevisionId As Integer
    Private _Title As String
    Private _AuthorId As Guid
    Private _Price As Decimal
    Private _Deleted As Boolean

    ...

    Sub New(ByVal BookRow As DataRow)
        Try
            _BookId = New Guid(BookRow("BookId").ToString)
            _RevisionId = CInt(BookRow("RevisionId"))
            _Title = CStr(BookRow("Title"))
            _AuthorId = New Guid(BookRow("AuthorId").ToString)
            _Price = CDec(BookRow("Price"))
        Catch ex As Exception
            'TO DO: log exception
            Throw New Exception("DataRow does not contain valid Book data.", ex)
        End Try
    End Sub

#End Region

...

#Region " Create, Update & Delete "

    Function Save() As SqlCommand
        If _BookId = Guid.Empty Then
            _BookId = Guid.NewGuid()
        End If
        Dim Command As SqlCommand = New SqlCommand("sp_Book_CreateUpdateDelete")
        Command.Parameters.AddWithValue("@BookId", _BookId)
        Command.Parameters.AddWithValue("@Title", _Title)
        Command.Parameters.AddWithValue("@AuthorId", _AuthorId)
        Command.Parameters.AddWithValue("@Price", _Price)
        Command.Parameters.AddWithValue("@Deleted", _Deleted)
        Return Command
    End Function

    Shared Function Delete(ByVal BookId As Guid) As SqlCommand
        Dim Doomed As Book = FindByBookId(BookId)
        Doomed.Deleted = True
        Return Doomed.Save()
    End Function

    ...

#End Region

...

#Region " Finders "

    Shared Function FindByBookId(ByVal BookId As Guid, Optional ByVal TryDeleted As Boolean = False) As Book
        Dim Command As SqlCommand
        If TryDeleted Then
            Command = New SqlCommand("sp_Book_FindByBookIdTryDeleted")
        Else
            Command = New SqlCommand("sp_Book_FindByBookId")
        End If
        Command.Parameters.AddWithValue("@BookId", BookId)
        If Database.Find(Command).Rows.Count > 0 Then
            Return New Book(Database.Find(Command).Rows(0))
        Else
            Return Nothing
        End If
    End Function

이러한 시스템은 각 행의 모든 ​​이전 버전을 보존하지만 관리하기가 매우 어려울 수 있습니다.

장점:

  • 전체 기록 보존
  • 저장 프로시저 수가 적음

단점:

  • 데이터 무결성을 위해 비데이터베이스 애플리케이션에 의존
  • 작성해야 할 엄청난 양의 코드
  • 데이터베이스 내에서 외래 키가 관리되지 않습니다(자동 Linq-SQL 스타일 객체 생성은 이제 안녕).
  • 나는 아직도 과거 버전을 보존한 모든 것을 검색할 수 있는 좋은 사용자 인터페이스를 찾지 못했습니다.

결론:

  • 사용하기 쉬운 즉시 사용 가능한 ORM 솔루션이 없었다면 새 프로젝트에서 그런 문제를 겪지 않았을 것입니다.

Microsoft Entity Framework가 이러한 데이터베이스 설계를 잘 처리할 수 있는지 궁금합니다.

Jeff와 나머지 Stack Overflow 팀은 Stack Overflow를 개발하는 동안 비슷한 문제를 처리해야 했을 것입니다.편집된 질문과 답변의 이전 버전은 저장되고 검색 가능합니다.

나는 Jeff가 그의 팀이 Linq를 SQL 및 MS SQL Server에 사용했다고 말했습니다.

이러한 문제를 어떻게 처리했는지 궁금합니다.

내가 아는 한, ORM 프레임워크는 CRUD 코드를 생성하려고 하므로 MVCC 옵션을 구현하도록 명시적으로 설계되어야 합니다.나는 즉시 그렇게 하는 사람을 모릅니다.

엔터티 프레임워크 관점에서 볼 때 CSLA는 지속성을 전혀 구현하지 않습니다. 단지 필요한 지속성을 구현하는 데 사용하는 "데이터 어댑터" 인터페이스를 정의할 뿐입니다.따라서 MVCC 데이터베이스 아키텍처와 함께 사용되는 CSLA 엔터티에 대한 CRUD 논리를 자동 생성하도록 코드 생성(CodeSmith 등) 템플릿을 설정할 수 있습니다.

이 접근 방식은 CSLA뿐만 아니라 모든 엔터티 프레임워크에서 작동할 가능성이 높지만 CSLA에서는 매우 "깨끗한" 구현이 될 것입니다.

Envers 프로젝트를 확인하세요. JPA/Hibernate 애플리케이션과 잘 작동하고 기본적으로 그렇게 합니다. 다른 테이블에 있는 각 엔터티의 다양한 버전을 추적하고 SVN과 유사한 가능성을 제공합니다("2008-11에 사용되는 Person 버전을 알려주세요. -05...")

http://www.jboss.org/envers/

/옌스

나는 항상 업데이트 및 삭제 시 db 트리거를 사용하여 해당 행을 TableName_Audit 테이블로 푸시할 것이라고 생각했습니다.

이는 ORM과 함께 작동하고 기록을 제공하며 해당 테이블에서 선택된 성능을 저하시키지 않습니다.좋은 생각인가요? 아니면 제가 뭔가를 놓치고 있는 걸까요?

우리가 하는 일은 일반 ORM(hibernate)을 사용하고 트리거 대신 뷰 +를 사용하여 MVCC를 처리하는 것입니다.

따라서 일반 테이블처럼 보이는 v_emp 뷰가 있습니다. 여기에 삽입하고 업데이트할 수 있습니다. 하지만 이렇게 하면 트리거가 실제로 기본 테이블에 올바른 데이터를 삽입하는 작업을 처리합니다.

아니다..나는 이 방법을 싫어합니다. :) 저는 Tim이 제안한 대로 저장 프로시저 API를 사용하겠습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top