java 사용자 정보를 데이터베이스에 병렬적으로 쓰는 몇 가지 방법

이런 상황이 존재한다고 가정하다
여러 사용자가 데이터베이스에 대해 쓰기를 하는데 우리의 업무 논리에 의하면 모든 사용자는 한 번만 쓸 수 있고 대부분의 사용자도 한 번만 요청을 보낼 수 있다.

public void write(Uers u){ 
 // do something 
} 
그러나 한 가지 상황(1%의 경우)은 어떤 사용자는 두 번, 심지어 여러 번 요청을 보내기도 한다(데이터베이스 제한 때문에 메인 키에 글을 쓰기가 불편하다).
만약 이 특수한 사용자가 보낸 두 번의 요청 시간 간격이 비교적 크다면 간단하다. 다시 쓸 때마다 데이터베이스에 써서 이 사람이 쓴 적이 있는지 없는지, 이미 쓴 적이 있다면 이 요청을 버려라.

public void write(Uers u){ 
 if(!checkIfExistUser(u)){ 
   // do something 
  } 
} 
그러나 가장 큰 문제는 사용자가 거의 순식간에 두 개의 쓰기 동작을 보냈다는 것이다.
그리고 우리의dosomething이 비교적 시간을 소모한다고 가정하면 위의 전략은 실패할 수 있다.
왜 실패했어?설명 안 해도 되죠?
그럼 어떡하지?
방법 1
만년불변의synchronized.

public synchronized void write(Uers u){ 
 if(!checkIfExistUser(u)){ 
   // do something 
  } 
} 
물론 우리는 위의 방법이 있으면 나타나지 않을 것이라는 것을 인정해야 한다. 데이터베이스에 두 개의 장삼의 기록이 있다
그러나 위의 자물쇠의 입도가 너무 커서 장삼이 썼을 때 이사도 쓸 수 없었다.
사실 우리가 원하는 것은 단지 장삼 본인이 동시에 여러 번 쓸 수 없다는 것이다.
방법 2
클래스 String은 문자열 풀을 유지합니다.intern 방법을 호출할 때, 이 String 대상과 같은 문자열이 풀에 이미 포함되어 있다면, 이 대상은 equals(Object) 방법으로 결정됩니다. 풀에 있는 문자열을 되돌려줍니다.String이 동시에 String임을 알 수 있습니다.intern () 은 항상 같은 대상을 되돌려주기 때문에 같은 사용자에 대한 잠금을 실현합니다.자물쇠의 입도가 구체적인 사용자에 국한되기 때문에 시스템은 최대한의 합병을 얻었다.

public synchronized void write(Uers u){ 
  synchronized(u.getUserId.intern()) { 
   // do something 
  } 
}
위의 사고방식은 장삼이 쓸 때 이사는 쓸 수 있지만 두 장의 장삼일을 쓸 수 없다는 것을 보증한다.
방법
사실 저는 개인적으로 방법2는 이미 매우 좋다고 생각합니다. 만약에 굳이 방법2에 또 무슨 문제가 있다면 다음과 같이 말할 수 밖에 없습니다.
String.()의 결함은 클래스 String이 JVMperm 구역에 있는 문자열 탱크를 유지하는 것입니다. 사용자 수가 너무 많으면 문자열 탱크에 넣은 String을 제어할 수 없고 OOM 오류나 과도한 Full GC를 초래할 수 있습니다.
그럼 어떡하지?

public synchronized void write(Uers u){ 
  String userSuffix=getSuffix(u); 
  synchronized(userSuffix.intern()) { 
   // do something 
  } 
} 
그 접미사를 얻는 전략에 대해서는 모두가 스스로 생각해라.
이 전략이 있으면 나는 1억 명의 사용자를 보장할 수 있다. 아마도 10000개의 다른 접두사만 있을 것이다.
장삼이사의 접미사와 같을 수도 있지만 장삼이사가 동시에 요청을 할 확률은 그리 크지 않을 것이다.정말 동시에 보내도 잠깐만 기다리면 안 돼요?
방법

Map locks = new Map();   
List lockKeys = new List();   
for(int number : 1 - 10000) {   
  Object lockKey = new Object();   
  lockKeys.add(lockKey);   
  locks.put(lockKey, new Object());   
}    
public void doSomeThing(String uid) {   
  Object lockKey = lockKeys.get(uid.hash() % lockKeys.size());   
  Object lock = locks.get(lockKey);   
  synchronized(lock) {   
   // do something   
  }   
} 
 
개인적인 느낌과 방법 3의 핵심 차이는 많지 않다.
방법
만약 집단 상황에서 두 개의 장삼이 거의 순식간에 두 서버에 들어가면 자바 언어 수준의 자물쇠는 모두 폐기되어야 한다.
redis의 분포식 자물쇠를 사용할 수 있습니다
방법
zookeeper 사용하기
단지 이런 사고방식이 있다고 들었을 뿐, 본인은 조키퍼를 사용한 적이 없으니, 이 방법은 더 이상 말하지 않겠습니다.
이상은 본문의 전체 내용입니다. 본고의 내용이 여러분의 학습이나 업무에 일정한 도움을 줄 수 있는 동시에 저희를 많이 지지해 주시기 바랍니다!

좋은 웹페이지 즐겨찾기