'.NET'에 해당되는 글 2건

  1. 2017.07.29 json string을 object로 역직렬화
  2. 2017.06.04 .NET IsolationLevel에 대한 고찰 5

이번 글에 대한 제목을 정하기가 어렵네요.

상황 설명을 해보자면 DB테이블에 nvarchar 타입에 json 포맷으로 된 값이 있고 이 값을 API로 전달해주면 됩니다.

리턴되는 데이터는 아래와 같습니다.


 "{ \"Key\": 1 " }"

리턴되는 타입이 string이고 그 안에 키 또는 string 값에 "문자를 필요로 하기 때문에 \문자로 string안에 string을 구분해주고 있는 것입니다.

이렇게 리턴을 하였을 경우에도 JSON.NET에서는 클래스(object)로 역직렬화가 가능합니다. 하지만 다른 언어의 다른 json 직렬화 라이브러리의 경우에는 에러가 발생하기도 하며 API 명세서에 노출하기에도 깔끔하지 못해보입니다.


최초 DB에서 받아오는 json string에 대해서 클래스(object)를 만들면 간단하게 해결됩니다. 하지만 여기서는 json string에 대한 포맷이 주기적으로 변경될 수도 있고 그에 따른 변경사항에 대해서 약결합을 만들어야 하는 상황입니다.

다음으로 생각해볼 수 있는 건 API에서 string이 아닌 타입으로 넘기면 되지 않을까 싶었고 검색을 해보았습니다.


https://stackoverflow.com/questions/22906010/deserialize-dynamic-json-string-using-newtonsoft-json-net


ExpandoObject 라는 System.Dynamic 네임스페이스의 클래스가 있었네요. JSON.NET으로 아래와 같이 역직렬화를 해주고 있습니다.


var converter = new ExpandoObjectConverter();

dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(string, converter);

=> JSON.NET에서 ExpandoObjectConverter를 제공해주고 있습니다. 해결은 아주 간단하게 되었고 ExpandoObject를 살펴보니 IDictionary<string, object>를 상속받고 있습니다. 아하~ json string을 아래처럼 Dictionary로 만들어주고 리턴을 해도 되겠군요.


Dictionary<string object> dic = new Dictionary<string object>();

dic.Add("Key", 1);

=> 그렇다면 Dictionary가 아닌 ExpandoObject 사용하는 것에 대한 장점은 무엇일까요?

1. 복잡한 json string일 경우(특히 계층 관계)

2. ExpandoObject가 INotifyPropertyChanged 인터페이스를 상속받고 있는 걸로 봐서는 프로퍼티 변경에 대한 통지(알림)를 받을 수 있네요

3. 이벤트도 추가할 수 있습니다.


해결은 간단하게 되었고 직렬화에 대한 이해도 살짝 올라갔네요. ㅎㅎ

Posted by resisa
,

또?! 오랜만입니다 ㅎㅎ 지인이 애드센스 등록을 하셔서 저도 시도를 해보았더니 콘텐츠 부족으로 실패하여 이렇게 새로운 글을 쓰고 있습니다.

어떤 내용을 쓸까 고민을 하다가 블로그를 정리하면서 예전에 썼던 글 중에 그 당시 궁금했던 내용에 대한 답변을 해보고자 합니다.
(벌써 7년이 지났다니 시간이 참 빠릅니다;;)

TransactionScope 그리고 Stored Procedure (2010. 07. 25)
출처: http://resisa.tistory.com/110 [심플하게~]

(중략)...

1. 한 가지 의문점은 SP안에서는 트랜잭션의 Scope 범위(TransactionScopeOption) 지정하는 부분은 없어보이지만 IsolationLevel 대해서는 지정을   있습니다또한 TransactionScope에서도 IsolationLevel 대해서 지정할  있습니다그래서 IsolationLevel 따른 LTM SQLTransaction 관계가 어떻게 될지도 살짝 궁금해집니다. 하지만 실질적으로 이러한 것을 프로젝트에서 정확하게 알고 사용하는 개발자가 얼마나 될지도 의문이며 IsolationLevel 트랜잭션 사이의 잠금(lock) 대한 것이기 때문에 2. 성능보다는 안전성을 중요시하는 우리 나라의 대부분의 프로젝트에서는 ReadCommitted 사용하는 것이 개발자의 정신건강에 이로워 보입니다. ^^

예전에 썼던 글에 은근히 잘못된 내용이 있습니다;;  이유는 이해부족 입니다;;
저는 새로운 기술을 습득하는 과정에서 '정의'를 자신의 방식으로 표현하고 증명하는 과정을 반복합니다. '정의'와 '증명'을 잘못하면 위와 같이 잘못된 글이 나오기도 하지만 경험이 붙으면 증명하는 시간이 짧아지고 단순 실수도 줄어 이해하는 시간이 짧아지고 자신의 표현 방식으로 인하여 오랫동안 기억되는 장점이 있는 방식이라고 생각됩니다. 그럼 잘못된 부분부터 수정해보겠습니다.

=> 1번에서는 개념에 대해서 잘못 설명하고 있습니다. TransactionScopeOption은 TransactionScope클래스의 파라미터로 DB(SP)에는 없는 속성입니다.

=> 2번 대부분의 프로젝트에서 ReadCommitted로 설정할 것이라는 이유는 MSSQL의 기본 IsolationLevel이 ReadCommitted이기 때문입니다. 이 당시에는 IsolationLevel에 대한 이론적인 것만 알고 있었기 때문에 이런 결론을 냈었는데 업그레이드된?! 지금은 대부분의 프로젝트에서는 ReadUncommitted를 사용할 것이라고 생각합니다. 왜냐하면 ReadCommitted로 설정을 하면 DeadLock이 발생하는 구간이 많이 있을 수 있습니다. 그렇기 때문에 직접적으로 ReadUncommitted를 지정하지 않았더라도 이와 동일한 WITH(NOLOCK) 힌트를 많이 사용했을 것이라고 추측됩니다.

그럼 본론으로 들어가서 노란색 부분에 대한 이야기를 풀어보겠습니다.

먼저 트랜잭션을 아래와 같이 2가지 형태로 구분합니다.
1. 로컬 트랜잭션(SQL Transaction)
2. 분산 트랜잭션(DTC Transaction)

1. 로컬 트랜잭션을 세부화 하면 아래와 같이 나눌 수 있습니다.
1.1. TM(Transaction Manager)이 관여하는 SQL Transaction
1.2 TM이 관여하지 않는 SQL Transaction

개념적인 측면에서는 TM의 관여 여부로 나눌 수 있으며 개발적인 측면에서는 프로그램에서 트랜잭션을 관리하는지 DB에서 즉 SP에서 트랜잭션을 관리 여부로 나눌 수 있습니다.

다시 노란색 부분을 보면 SP에서 트랜잭션을 관리하는 부분들이 프로그램에서 트랜잭션을 관리하는 것과 합쳐졌을 경우에 트랜잭션 관리(Connection, IsolationLevel)에 대한 궁금증이였습니다.

프로그램에서 트랜잭션 관리를 하는 방법은 아래와 같습니다.
1. ADO.NET(System.Data.SqlClient.SqlConnection)를 사용하여 직접 BeginTransaction()를 호출하여 사용
2. System.Transactions.TransactionScope를 사용

트랜잭션을 관리하는 1번, 2번 방법의 공통점은 프로그램에서 트랜잭션을 관리하기 때문에 TM이 트랜잭션을  관리한다는 점입니다. 차이점이 바로 이 글의 핵심이 되는 답변으로 IsolationLevel과 관련되어 있습니다. TransactionScope에 IsolationLevel을 지정하여 사용할 때 SP의 IsolationLevel을 변경할 수 없다는 것입니다. IsolationLevel에 대한 위의 네임스페이스를 살펴보면 아래와 같습니다.

1. System.Data.SqlClient.SqlConnection - System.Data.IsolationLevel
2. System.Transactions.TransactionScope - System.Transactions.IsolationLevel

조심스럽게 예측해보면 TransactionScope의 트랜잭션은 DB 트랜잭션이라기보다는 프로그램에서 발생하는 트랜잭션(여기서는 DB 트랜잭션을 포함하는 상위의 트랜잭션의 개념으로 이해)이라고 할 수 있고 IsolationLevel은 트랜잭션 사이의 격리성이기 때문에 프로그램에서 발생하는 트랜잭션에 대한 격리성이지 DB 트랜잭션에 대한 격리성이 아니기 때문에 DB(SP) IsolationLevel을 변경할 수 없는 것입니다.

결론을 맺으면 프로그램에서 DB(SP) 트랜잭션 관리(IsolationLevel)를 하고 싶으면 SqlConnection을 사용하여 직접 트랜잭션을 발생(BeginTransaction())시켜야하며 TransactionScope을 통해서는 DB(SP) IsolationLevel까지는 관리할 수 없다는 것입니다.

Posted by resisa
,