문제

여기를 포함하여 객체 관계 매핑이 잘 논의되었습니다. 나는 몇 가지 접근 방식과 함정과 타협에 대한 경험이 있습니다. 진정한 해상도는 OO 또는 관계형 모델 자체를 변경 해야하는 것처럼 보입니다.

기능적 언어를 사용하는 경우 동일한 문제가 나타나나요? 이 두 패러다임은 OO와 RDBM보다 더 잘 맞아야합니다. RDBM의 세트에서 사고라는 생각은 기능적 접근이 약속하는 것처럼 보이는 자동 병렬성과 맞물린 것 같습니다.

누구든지 흥미로운 의견이나 통찰력이 있습니까? 업계의 플레이 상태는 무엇입니까?

도움이 되었습니까?

해결책

관계형 데이터베이스를 확장하는 데있어 어려운 문제는 확장 트랜잭션, 데이터 유형 불일치, 자동화 된 쿼리 번역 및 n+1 선택 그것은 관계 시스템을 떠나는 근본적인 문제이며, 제 생각에는 수신 프로그래밍 패러다임을 변경하여 변하지 않습니다.

다른 팁

ORM의 목적은 무엇입니까?

ORM을 사용하는 주요 목적은 네트워크 모델 (객체 방향, 그래프 등)과 관계형 모델을 브리지하는 것입니다. 그리고 두 모델의 주요 차이점은 놀랍게도 간단합니다. 부모가 자녀 (네트워크 모델)를 가리키거나 어린이가 부모 (관계형 모델)를 가리키는 지 여부입니다.

이 단순함을 염두에두고 믿습니다 "임피던스 불일치"와 같은 것은 없습니다. 두 모델 사이. 사람들이 일반적으로 발생하는 문제는 순전히 구현이 다르며 클라이언트와 서버간에 더 나은 데이터 전송 프로토콜이있는 경우 해결할 수 있어야합니다.

SQL은 ORM에 대한 문제를 어떻게 해결할 수 있습니까?

특히, 세 번째 선언 다음을 포함하여 다양한 데이터베이스에서 구현 된 중첩 컬렉션을 허용하여 SQL 언어 및 관계형 대수의 단점을 해결하려고합니다.

  • Oracle (아마도 가장 정교한 구현)
  • Postgresql (어느 정도)
  • 정보
  • SQL Server, MySQL 등 (XML 또는 JSON을 통한 "에뮬레이션")

내 생각에, 모든 데이터베이스가 SQL 표준을 구현 한 경우 MULTISET() 연산자 (예 : Oracle), 사람들은 더 이상 맵핑에 ORM을 사용하지 않을 것입니다 (아마도 객체 그래프 지속성에 대한 경우)는 데이터베이스 내에서 중첩 된 컬렉션을 직접 실현할 수 있기 때문에 다음과 같습니다.

SELECT actor_id, first_name, last_name,
  MULTISET (
    SELECT film_id, title
    FROM film AS f
    JOIN film_actor AS fa USING (film_id)
    WHERE fa.actor_id = a.actor_id
  ) AS films
FROM actor AS a

모든 배우와 영화를 비정상적인 결합 결과 (각 영화에 대해 배우가 반복되는 곳)가 아닌 중첩 컬렉션으로 생산할 것입니다.

클라이언트 측의 기능적 패러다임

클라이언트 측의 기능 프로그래밍 언어가 데이터베이스 상호 작용에 더 적합한 지에 대한 질문은 실제로 직교입니다. Orms는 객체 그래프 지속성에 도움이되므로 클라이언트 측 모델이 그래프이고 그래프가 되려면 기능 프로그래밍 언어를 사용하여 그래프를 조작하든 관계없이 ORM이 필요합니다.

그러나 객체 방향은 기능적 프로그래밍 언어에서 관용적이지 않기 때문에 모든 데이터 항목을 객체로 구울 가능성이 적습니다. SQL을 쓰는 사람에게는 임의의 투영 튜플 매우 자연 스럽습니다. SQL은 구조 타이핑을 수용합니다. 각 SQL 쿼리는 이전에 이름을 할당 할 필요없이 자체 행 유형을 정의합니다. 이는 기능적 프로그래머와 매우 잘 공명합니다. 특히 유형 추론이 정교 할 때, SQL 결과를 이전에 정의 된 객체 / 클래스에 매핑 할 생각이 없을 경우.

Java 사용의 예 주크 이 블로그 게시물에서 될 수 있습니다 :

// Higher order, SQL query producing function:
public static ResultQuery<Record2<String, String>> actors(Function<Actor, Condition> p) {
    return ctx.select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
              .from(ACTOR)
              .where(p.apply(ACTOR)));
}

이 접근법은 SQL 언어가 일부 ORM에 의해 추상화되었거나 SQL의 자연스러운 "문자열 기반"특성이 사용 된 경우보다 SQL 문의 구성 성을 훨씬 더 잘 조성합니다. 위의 기능은 이제 다음과 같이 사용할 수 있습니다.

// Get only actors whose first name starts with "A"
for (Record rec : actors(a -> a.FIRST_NAME.like("A%")))
    System.out.println(rec);

SQL에 대한 FRM 추상화

일부 FRM은 일반적으로 이러한 이유로 SQL 언어에 대해 추상화하려고합니다.

  • 그들은 SQL이 충분히 합성 할 수 없다고 주장합니다 (Jooq는 이것을 반증합니다. 제대로하기가 매우 어렵습니다).
  • 그들은 API 사용자가 "기본"컬렉션 API에 더 익숙하다고 주장합니다. JOIN 번역됩니다 flatMap() 그리고 WHERE 번역됩니다 filter(), 등.

귀하의 질문에 답변합니다

FRM은 ORM보다 "쉬운"것이 아니며 다른 문제를 해결합니다. 실제로, FRM은 선언적 프로그래밍 언어 자체 인 SQL (기능 프로그래밍과 크게 다르지 않음)이 다른 기능 클라이언트 프로그래밍 언어와 매우 일치하기 때문에 실제로 문제를 해결하지 못합니다. 따라서 FRM은 단순히 SQL, 외부 DSL 및 클라이언트 언어 사이의 간격을 연결합니다.

(나는 회사에서 일하고 있습니다 주크,이 답변은 편향되어 있습니다)

그것은 당신의 필요에 따라 다릅니다

  1. 데이터 구조에 집중하려면 JPA/Hibernate와 같은 ORM을 사용하십시오.
  2. 치료에 대해 밝히고 싶다면 FRM 라이브러리를 살펴보십시오 : Querydsl 또는 Jooq.
  3. SQL 요청을 특정 데이터베이스에 조정 해야하는 경우 JDBC 및 기본 SQL 요청을 사용하십시오.

다양한 "관계형 매핑"기술의 강력한 것은 휴대 성입니다. 애플리케이션이 대부분의 산성 데이터베이스에서 실행되도록합니다. 그렇지 않으면 SQL 요청을 수동으로 작성할 때 다양한 SQL 방언 간의 차이에 대처할 수 있습니다.

물론 SQL92 표준으로 자신을 제한 한 다음 기능 프로그래밍을 수행하거나 ORM 프레임 워크를 사용하여 기능적 프로그래밍의 일부 개념을 재사용 할 수 있습니다.

ORM Strenghs는 병목 현상으로 작용할 수있는 세션 객체를 통해 구축됩니다.

  1. 기본 데이터베이스 트랜잭션이 실행되는 한 객체의 수명주기를 관리합니다.
  2. Java 객체와 데이터베이스 행 사이에 일대일 매핑을 유지합니다 (내부 캐시를 사용하여 중복 객체를 피하십시오).
  3. 협회 업데이트 및 고아 객체를 자동으로 감지하여 삭제합니다.
  4. 그것은 낙관적이거나 비관적 인 잠금으로 동시 문제를 처리합니다.

그럼에도 불구하고, 그 강점은 또한 약점입니다.

  1. 세션은 객체를 비교할 수 있어야하므로 Equals/Hashcode 메소드를 구현해야합니다. 그러나 객체 평등은 데이터베이스 ID가 아닌 "비즈니스 키"에 루팅되어야합니다 (새로운 과도 객체에는 데이터베이스 ID가 없습니다!). 그러나 일부 재 구선 개념에는 비즈니스 평등이 없습니다 (예 : 운영). 일반적인 해결 방법은 데이터베이스 관리자를 화나게하는 경향이있는지도에 의존합니다.

  2. 세션은 관계가 변경되어야하지만 매핑 규칙은 비즈니스 알고리즘에 적합하지 않은 컬렉션의 사용을 강요합니다. 때때로 당신은 해시 맵을 사용하고 싶지만 ORM은 키가 다른 빛 대신 또 다른 "풍부 도메인 객체"가되기 위해 열쇠를 요구합니다 ... 그러면 키로 작용하는 리치 도메인 객체에서 객체 평등을 구현해야합니다 ... 그러나이 객체는 비즈니스 세계에 상대가 없기 때문에 할 수는 없습니다. 따라서 반복 해야하는 간단한 목록으로 돌아갑니다 (및 성능 문제).

  3. ORM API는 때때로 실제 사용에 부적합합니다. 예를 들어, 실제 웹 애플리케이션은 데이터를 가져올 때 "클로스"를 추가하여 세션 격리를 시행하려고 시도합니다. "Session.get (ID)"로 충분하지 않으며 더 복잡한 DSL로 전환해야합니다 ( HSQL, Criteria API) 또는 기본 SQL로 돌아갑니다.

  4. 데이터베이스 개체는 다른 프레임 워크 전용 (OXM Frameworks = Object/XML 매핑)에 전용 된 다른 객체와 충돌합니다. 예를 들어, 귀하의 REST 서비스가 Jackson Library를 사용하여 비즈니스 객체를 직렬화하는 경우. 그러나이 잭슨은 정확히 최대 절전 모드에지도를 맵핑합니다. 그런 다음 둘 다 병합되고 API와 데이터베이스 간의 강한 커플 링이 나타나거나 번역을 구현해야하며 ORM에서 저장 한 모든 코드가 손실됩니다 ...

다른 한편으로, FRM은 "Object Relational Mapping"(ORM)과 기본 SQL 쿼리 (JDBC 포함) 사이의 상충 관계입니다.

FRM과 ORM의 차이점을 설명하는 가장 좋은 방법은 DDD 접근법을 채택하는 것으로 구성됩니다.

  • 객체 관계형 매핑은 데이터베이스 거래 중에 주 상태가 변하는 Java 클래스 인 "Rich Domain Object"의 사용을 권한을 부여합니다.
  • 기능적 관계 매핑은 불변이 불가능한 "불량 도메인 객체"에 의존합니다 (따라서 콘텐츠를 변경하려면 매번 새로운 것을 복제해야합니다).

그것은 ORM 세션에 제한된 제약 조건을 공개하고 SQL을 통해 DSL에서 대부분의 시간에 의존하지만 반면에 트랜잭션 세부 사항, 동시성 문제를 조사해야합니다.

List<Person> persons = queryFactory.selectFrom(person)
  .where(
    person.firstName.eq("John"),
    person.lastName.eq("Doe"))
  .fetch();

관계형 매핑에 대한 기능은 oo 로의 RDBM보다 생성하고 사용하기가 더 쉬워야한다고 생각합니다. 데이터베이스 만 쿼리하는 한 나는 당신이 좋은 방법으로 부작용없이 데이터베이스 업데이트를 수행 할 수있는 방법을 실제로 보지 못합니다.

내가 보는 주요 문제는 성능입니다. 오늘날 RDM은 기능 쿼리와 함께 사용되도록 설계되지 않았으며 아마도 몇 가지 경우가 잘되지 않을 것입니다.

나는 기능적 관계 매핑을하지 않았다. 그 자체, 그러나 기능 프로그래밍 기술을 사용하여 RDBM에 대한 액세스를 가속화했습니다.

데이터 세트로 시작하고 복잡한 계산을 수행하고 결과를 저장하는 것이 일반적입니다. 예를 들어 결과는 원본의 하위 집합입니다. 명령 적 접근법은 초기 데이터 세트를 추가 널 열로 저장하고 계산을 수행 한 다음 계산 된 값으로 레코드를 업데이트하도록 지시합니다.

합리적으로 보입니다. 그러나 그 문제는 매우 느리게 될 수 있다는 것입니다. 계산이 업데이트 쿼리 자체 외에 다른 SQL 문이 필요한 경우, 심지어 응용 프로그램 코드에서 수행 해야하는 경우 문자 그대로 결과를 올바른 행에 저장하기 위해 계산 후 변경 한 레코드를 검색해야합니다. .

결과를위한 새 테이블을 만들면이 문제를 해결할 수 있습니다. 이렇게하면 업데이트 대신 항상 삽입 할 수 있습니다. 당신은 다른 테이블을 가지고 키를 복제하지만 더 이상 널을 저장하는 열에 공간을 낭비 할 필요는 없습니다. 당신은 가지고있는 것만 저장합니다. 그런 다음 최종 선택에서 결과에 참여하십시오.

I (AB)는 이런 식으로 RDBMS를 사용했고 결국 대부분 이렇게 보이는 SQL 문을 작성했습니다 ...

create table temp_foo_1 as select ...;
create table temp_foo_2 as select ...;
...
create table foo_results as
  select * from temp_foo_n inner join temp_foo_1 ... inner join temp_foo_2 ...;

이것이 본질적으로하는 일은 많은 불변의 바인딩을 만드는 것입니다. 그러나 좋은 점은 한 번에 전체 세트에서 작업 할 수 있다는 것입니다. Matlab과 같은 행렬로 작업 할 수있는 언어를 상기시킵니다.

나는 이것이 또한 병렬성을 훨씬 쉽게 허용 할 것이라고 생각합니다.

여분의 특전은이 방법으로 생성 된 테이블의 열 유형은 선택한 열에서 추론되므로 지정할 필요가 없다는 것입니다.

SAM이 언급했듯이 DB를 업데이트해야한다면 OO 세계와 동일한 동시성 문제에 직면해야한다고 생각합니다. 프로그램의 기능적 특성은 RDBMS의 데이터, 트랜잭션 등으로 인해 객체 특성보다 조금 더 문제가 될 수 있습니다.

그러나 독서의 경우 기능적 언어는 일부 문제 영역에서 더 자연 스러울 수 있습니다 (DB와 상관없이 보이는 것처럼)

기능적 <-> RDBMS 매핑은 oo <-> rdmbs 매핑과 큰 차이가 없어야합니다. 그러나 새로운 DB 스키마가있는 프로그램을 개발하거나 레거시 DB 스키마 등에 대해 무언가를 수행하려는 경우 어떤 종류의 데이터 유형을 사용하고 싶은지에 달려 있다고 생각합니다.

예를 들어, 연관에 대한 게으른 페치 등은 아마도 게으른 평가 관련 개념으로 상당히 멋지게 구현 될 수 있습니다. (oo로도 잘 할 수 있지만)

편집 : 인터넷 검색으로 찾았습니다 haskelldb (Haskell 용 SQL 라이브러리) - 시도해 볼 가치가 있습니까?

데이터베이스 및 기능 프로그래밍은 융합 될 수 있습니다.

예를 들어:

Clojure는 관계형 데이터베이스 이론을 기반으로 한 기능적 프로그래밍 언어입니다.

               Clojure -> DBMS, Super Foxpro
                   STM -> Transaction,MVCC
Persistent Collections -> db, table, col
              hash-map -> indexed data
                 Watch -> trigger, log
                  Spec -> constraint
              Core API -> SQL, Built-in function
              function -> Stored Procedure
             Meta Data -> System Table

참고 : 최신 Spec2에서 사양은 RMDB와 비슷합니다. 보다: Spec-Alpha2 Wiki : 스키마 및 선택

나는 옹호 : NOSQL과 RMDB 장점의 조합을 달성하기 위해 해시 맵 위에 관계형 데이터 모델을 구축합니다. 이것은 실제로 posgtresql의 역 구현입니다.

오리 타이핑 : 오리처럼 보이고 오리처럼 보이는 경우 오리 여야합니다.

Clojure의 RMDB와 같은 Clojure의 데이터 모델 인 경우 Clojure의 RMDB 및 RMDB와 같은 Clojure의 데이터 조작과 같은 Clojure의 시설은 Clojure가 RMDB 여야합니다.

Clojure는 관계형 데이터베이스 이론을 기반으로 한 기능적 프로그래밍 언어입니다.

모든 것이 RMDB입니다

해시 맵 (NOSQL)을 기반으로 관계 데이터 모델 및 프로그래밍 구현

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