티스토리 툴바


SELECT ... FOR UPDATE는 업데이트 전에 결과 Row에 Lock을 설정하기 위한 쿼리이다.

업데이트하고 명시적으로 Commit을 해야만 Lock이 해제된다.

결과 Row를 확인하고 업데이트가 필요없다고 판단되더라도

명시적인 Commit이 필요한 셈이다.

DefaultSqlSession.commit()의 코드는 다음과 같다.

  public void commit() {
    commit(false);
  }

여기에서 사용되는 commit(boolean force)의 코드는 다음과 같다.

  public void commit(boolean force) {
    try {
      executor.commit(isCommitOrRollbackRequired(force));
      dirty = false;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

여기에서 사용되는 isCommitOrRollbackRequired(boolean force)의 코드는 다음과 같다.

  private boolean isCommitOrRollbackRequired(boolean force) {
    return (!autoCommit && dirty) || force;
  }

selectXxx()는 dirty 설정을 하지 않기 때문에 Commit은 되지 않는다.

그렇다면 어떻게 해야 할까?

이미 눈치챘겠지만, 다음과 같이 force 파라미터를 true로 설정해서 호출하면 된다.

commit(true);

혹시나 commit() 메소드 호출 후에도 Lock이 해제되지 않는다고 삽질하지 마시길.

Reference:
http://docs.oracle.com/cd/E17952_01/refman-5.1-en/innodb-locking-reads.html

Posted by izeye

자바에서 바이트 배열을 16진수로 변환하기 위해 직접 구현할 수도 있겠지만,

Apache Commons Codec 라이브러리 내 Hex 클래스의 encodeHex() 메소드를 사용할 수 있겠다.

다음을 이를 사용하는 테스트 코드이다.

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.apache.commons.codec.binary.Hex;
import org.junit.Test;

public class HexTest {
 @Test
 public void testEncodeHex() {
  String expectedHex = "010a141e";
  byte[] byteArray = {1, 10, 20, 30};
  String hex = new String(Hex.encodeHex(byteArray));
  System.out.println(hex);
  assertThat(hex, is(expectedHex));
 }
}

Reference:
http://stackoverflow.com/questions/332079/in-java-how-do-i-convert-a-byte-array-to-a-string-of-hex-digits-while-keeping-l

Posted by izeye

자바에서 배열을 합치기 위해 어떻게 해야할까?

다양한 방법이 있을 수 있겠다.

Apache Commons Lang 라이브러리 내 ArrayUtils 클래스의 addAll() 메소드를 사용할 수 있다.

혹은 Generics를 이용해서 직접 구현할 수도 있겠다.

다음은 이를 활용한 테스트 코드와 샘플 코드이다.

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import java.util.Arrays;

import org.apache.commons.lang.ArrayUtils;
import org.junit.Test;

public class ArrayUtilsTest {
 String[] expected = {"string1", "string2", "string3", "string4"};
 String[] first = {"string1", "string2"};
 String[] second = {"string3", "string4"};

 @Test
 public void testAddAll() {
  String[] actual = (String[])ArrayUtils.addAll(first, second);
  System.out.println(Arrays.toString(actual));
  assertThat(actual, is(expected));
 }

 @Test
 public void testConcat() {
  String[] actual = concat(first, second);
  System.out.println(Arrays.toString(actual));
  assertThat(actual, is(expected));
 }

 @Test
 public void testConcatAll() {
  String[] actual = concatAll(first, second, first, second);
  System.out.println(Arrays.toString(actual));
  assertThat(actual, is(concat(expected, expected)));
 }

 public static <T> T[] concat(T[] first, T[] second) {
  T[] result = Arrays.copyOf(first, first.length + second.length);
  System.arraycopy(second, 0, result, first.length, second.length);
  return result;
 }

 public static <T> T[] concatAll(T[] first, T[]... rest) {
  int totalLength = first.length;
  for (T[] array : rest) {
   totalLength += array.length;
  }
  T[] result = Arrays.copyOf(first, totalLength);
  int offset = first.length;
  for (T[] array : rest) {
   System.arraycopy(array, 0, result, offset, array.length);
   offset += array.length;
  }
  return result;
 }
}

Generics를 사용해서 구현하면 객체에 대해서는 한 메소드로 해결이 되지만,

Primitive Type은 모두 별개의 메소드로 만들어야 한다는 불편함이 존재한다.

그렇다고 달리 뾰족한 수가 없다.

NIO 패키지 내 Buffer 클래스 군의 Chaining 기법을 사용하면 비교적 깔끔하게 구현할 수 있기는 하다.

물론 모두 별개의 메소드로 만들어야 한다는 문제는 여전히 안고 있다.

Reference:
http://stackoverflow.com/questions/80476/how-to-concatenate-two-arrays-in-java

Posted by izeye