Search Results

Search Results for '분류 전체보기' : 38 POSTS

  1. 2011.03.10 자바스크립트 클로저 예제(Javascript Closure)
  2. 2011.03.09 SQLite
  3. 2011.01.26 Mysql Replication 으로 분산처리 하기
  4. 2011.01.14 Intent 존재여부 확인하기
  5. 2010.10.25 MYSQL 쿼리시 ENUM의 ORDER BY

자바스크립트 클로저 예제(Javascript Closure)

자바스크립트에는 클로저( Closure)라는 개념이 있습니다.(랭귀지에 따라 클로저가 있는 언어도 있고 그렇지 않은 언어도 있습니다.) 오랫동안 잘 이해하고 있다가 어느정도 이해는 되었지만 아직 몸에 익지 않았다가 최근에 두번이나 클로저로 해결할 문제를 누가 물어와서 정리를 합니다.

클로저는 자신의 범위(Scope) 밖에 있는 변수들에 접근할 수 있는 함수를 의미합니다.

사실 이 말만 가지고는 잘 감이 오지 않고 보통 자바스크립트내에서는 함수의 생명주기는 끝이났지만 함수내의 변수를 내부함수가 참조하고 있기 때문에 유지되어 접근할수 있는 함수를 클로저라고 합니다.

<input type="button" id="btn1"/>
<input type="button" id="btn2"/>
<input type="button" id="btn3"/>
<input type="button" id="btn4"/>


위와 같이 버튼이 4개 있고 각 버튼을 클릭했을때 각 버튼당 1,2,3,4가 찍히게 하고 싶다고 하겠습니다. 당연히 가장 쉬운 방법은 각 버튼에 인라인으로 onclick="alert('1')" 처럼 각 버튼당 파라미터를 주는 것이 쉽겠지만 이럴 경우 요즘 일반적인 구조와 동작을 불리하는 Unobtrusive Javascript에도 맞지 않고 유지보수에도 별로 좋지 않습니다. 

일반적으로 사람들이 위와같은 구현을 하기 위해서 가장 먼저 시도하는 코드는 아래와 같을 것입니다.


window.onload = function() {
    for(var i=1; i < 5; i++ ) {
        document.getElementById("btn" + i).addEventListener("click", function() {
            alert(i);
        }, false);
    }
}

모두는 아니겠지만 보통 위와같은 코드를 시도하리라고 생각하고 정상적으로 동작할 것을 기대하지만 위 코드는 제대로 동작하지 않습니다. for문을 돌면서 각 버튼에 click이벤트리스너를 등록하고 각 루프에서의 i를 alert으로 보여줍니다. 이렇게 할경우 의도한 것은 1,2,3,4의 alert()을 의도한것이지만 alert()에 넘겨준 파라미터는 i의 값이 아닌 i의 참조이기 때문에 실제 버튼을 클릭하면 모든 버튼을 클릭할 때 i의 최종값이 5가 모두 찍혀버립니다. 



이 상황이 클로저가 적합한 상황인데 클로저를 사용하는 것은 이해만 하면 그렇게 어렵지 않습니다.


window.onload = function() {
    for(var i=1; i < 5; i++ ) {
        (function(m) {
            document.getElementById("btn" + m).addEventListener("click", function() {
                alert(m);
            }, false);
        })(i);
    }
}

?
위와 같이 작성합니다. for문안에 실행할 구문을 익명함수( (function() {})와 같은 형태)로 만들고는 i를 파라미터로 넘기면서 실행시켜버립니다.(익명함수에 (i)를 붙혀서 바로 실행시켰습니다.) 이렇게 하면 익명함수안의 내부변수인 m에 i의 값이 할당되어 버리고 구조상은 실행뒤에 소멸되어야 하지만 클로저로 인하여 각 값으로 할당된 멤버변수를 각 이벤트리스너에서 그대로 사용할 수 있게 됩니다. 위 코드로 실행하면 각 버튼을 클릭시 1,2,3,4의 원하던 값이 찍히게 됩니다.


덧) 그냥 예제코드이기 때문에 표준인 addEventListener만을 사용했습니다. IE에서 돌려보실 계획이라면 attachEvent를 사용하셔야 합니다.

약간 보충설명을 하자면,
첫번째 예제는 클로저의 생성으로 인한 부작용을 보여줍니다.
원래 의도는 각 버튼마다 alert시에 1,2,3,4를 결과로 보여주려는 의도이나 이벤트 핸들러 함수의 i값이 바깥쪽 변수인 i값에 대한 참조를 유지하고 있어, 즉 클로저의 생성으로 인해 최종값인 5를 모두 가리키게 되는 예제입니다.
사실 두번째 예제는 클로저의 부작용을 막기위한 처리로 제시한 예제인데, 이 예제도 클로저가 생성되긴 합니다만 익명함수의 인자로 값을 넘겨버림으로써 바깥쪽 변수인 i에 대한 변수스코프를 끊어버리고, 이벤트 핸들러에서는 익명함수의 인자값에 접근함으로써 의도한 대로 처리가 되게 됩니다.
괄호로 둘러싼 함수표현식 안에서는 바깥쪽 변수에 접근하지 못한다는 것을 여기서 아실 수 있습니다.


RSS :
Response

SQLite

출처 : http://blog.naver.com/crowdark7/109969054


SQLite

A. SQLite의 사용

B. Query

C. 자료의 표현(CursorAdapter)

 

 

 

A. SQLite의 사용

 

SQLite

 데이터베이스는 어플리케이션이 자료를 다룬다면 중요한 요소입니다. 임베디드에 내장되는 소프트웨어 역시 DB를 가지고 있습니다. SQLite는 이러한 DB를 관리하는 DB엔진으로 2000년 리처드 힙 박사에 의해 개발된 무료 엔진입니다.

 안드로이드에서는 데이터를 저장하는 장소가 웹이 아닌 파일이 될 가능성이 큽니다. 그러므로 원하는대로 복사, 삭제, 이동할 수 있습니다.

 

SQLite 관련 클래스

 SQLite는 따로 GUI툴을 제공하지 않습니다. 편하게 테이블을 만들거나 할 수 없고 SQL문을 사용해야 합니다. 그래서 안드로이드에서는 DB를 관리할 수 있는, 그리고 SQLite를 편하게 쓸 수 있는 클래스를 제공합니다.

 

SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)

인수

설명

context

DB를 생성하는 컨텍스트입니다. 보통 메인 액티비티를 전달하게 됩니다.

name

DB 파일의 이름입니다.

factory

커스텀 커서를 사용할 때 지정하는데 null을 사용하게 되면 표준 커서를 사용합니다.

version

DB의 버전입니다.

* 커서는 후에 설명하겠습니다.

 

SQLiteOpenHelper의 주요 메서드

이 클래스에서는 DB를 생성하거나 읽을 때에 다음의 메서드들을 호출합니다.

메서드

호출시기

설명

onCreate

처음 DB생성 시

테이블을 만들고 초기 설정과 레코드들을 삽입합니다.

onUpgrade

DB를 업그레이드 시

기존의 테이블을 변형시키거나 새로 만들게 되는 작업을 수행합니다.

onOpen

DB를 열 때

파일이 존재한다면 이 메서드가 호출됩니다.

 

DB를 쓰거나 읽기 위해서는 다음의 메서드를 이용합니다.

메서드

설명

getReadableDatabase

읽기 전용으로 DB를 이용합니다.

getWritableDatabase

읽고 쓰기를 위해 DB를 이용합니다.

close

DB를 닫는 것으로 위 두 작업 이후 해주어야 합니다.

만약 DB파일이 없다면 파일을 생성한 후에 자동으로 onCreate를 호출하게 될 것입니다.

버전이 바뀐 경우는 onUpgrade를 호출하겠지요. 이 메서드들을 이용하면 DB를 열고 객체를 리턴받을 수 있습니다.

 

 

B. Query

 

DB를 가져왔다면 이를 사용해야 합니다.

안드로이드에서는 메서드를 이용해서 DB를 다룰 수도 있지만 직접 쿼리문을 사용해서 DB를 다룰 수도 있습니다.

메서드를 이용하는 것보다 쿼리문을 그대로 사용하는 게 더욱 편합니다.

그렇다면 이런 DB의 사용에 관해서 알아봅시다.

 

DB 가져오기

먼저 DB에 기록하거나 DB를 읽기 위해서는 앞서 본 메서드로 DB를 가져와야 합니다.

 

SQLiteDatabase db객체 = SQLiteHelper클래스.getWritableDatabase();

SQLiteHelper클래스의 경우는 SQLiteHelper를 상속해서 DB를 관리하기 위한 클래스를 하나 만들어줘야 합니다.

SQLiteHelper는 추상클래스 이기 때문에 위의 onCreate, onUpgrade, onOpen을 구현해야 하기 때문입니다.

 

데이터 맵 준비

 

DB를 불러왔으니 기록할 데이터를 작성합니다.

데이터는 기본적으로 키 값과 내용물로 구성됩니다. 그리고 이 데이터를 저장하기 위해서는 맵(Map)이 필요합니다.

이 맵을 생성시키는 생성자는 다음과 같습니다.

생성자

설명

ContentValues()

비어있는 디폴트 크기의 맵을 생성합니다.

ContentValues(int size)

size 만큼의 크기를 가진 맵을 생성합니다.

ContentValues(ContentValuse from)

인수로 받은 ContentValues의 복사본을 생성합니다.

 

맵에 데이터를 넣는 메서드는 put메서드를 사용합니다. 모든 타입에 오버로드 되어 있으므로 필드의 타입에 맞는 것을 사용하면 됩니다.

void put(String key, 데이터의 타입 value)

 

사용 예

ContentValues data = new ContentValues();

data.put(“key1”, “데이터1 입니다”);

data.put(“key2”, “데이터2 입니다”);

 

DB에 데이터 삽입

 

메서드를 이용한 삽입

long SQLiteDatabase.insert(String table, String nullColumnHack, ContentValues values)

인수

설명

table

DB Table의 이름을 말합니다.

nullColumnHack

DB에서는 완전히 비어있는 행을 삽입하는 것을 허용하지 않습니다. 대신 비어있다는 것을 표현하기 위해서 NULL을 쓰게 됩니다. 그래서 만약 NULL이 들어가야 할 곳에 들어가게 될 것을 말합니다.

values

생성해 놓은 데이터 맵을 말합니다.

 

쿼리를 이용한 삽입

void execSQL(String sql)

sql 인수는 SQL문이 들어가게 됩니다. SQL문은 삽입의 경우는 다음과 같습니다.

execSQL(“INSERT INTO 테이블 명 VALUES (데이터);”);

 

DB의 데이터 삭제

메서드를 이용한 삭제

조건에 맞는 데이터만을 삭제했다면 0, 모든 데이터를 삭제했다면 1을 리턴합니다.

int delete(String table, String whereClause, String[] whereArgs)

인수

설명

table

DB Table의 이름을 말합니다.

whereClause

조건항으로 해당 조건에 맞는 항을 삭제하라는 뜻입니다. null을 넣게 되면 모든 행을 삭제합니다.

whereArgs

조건을 규정하는 argument입니다.

 

쿼리를 이용한 삭제

void execSQL(String sql)

SQL문은 삭제의 경우는 다음과 같습니다.

execSQL(“DELETE FROM 테이블 명 WHERE 조건;”);

 

DB의 데이터 갱신

메서드를 이용한 갱신

 

int update(String table, ContentValues values, String whereClause, String[] whereArgs)

인수

설명

table

DB Table의 이름을 말합니다.

values

갱신 내용을 말합니다.

whereClause

조건항으로 해당 조건에 맞는 항을 삭제하라는 뜻입니다. null을 넣게 되면 모든 행을 삭제합니다.

whereArgs

조건을 규정하는 argument입니다.

 

쿼리를 이용한 갱신

void execSQL(String sql)

SQL문은 삭제의 경우는 다음과 같습니다.

execSQL(“UPDATE 테이블 명 SET 갱신 내용 WHERE 조건;”);

 

DB의 데이터 검색

메서드를 이용한 검색

엄청나게 인수가 많지만 대부분 null이 될 가능성이 큽니다.

Cursor query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)

인수

설명

distinct

검색되는 행 중에서 중복되는 내용은 제거하고 출력합니다. null을 지정하면 모두 출력합니다. 이 행을 제외하고도 쓸 수 있습니다.

table

DB Table의 이름을 말합니다.

columns

보여줄 열을 지정합니다. null을 지정하면 모든 열을 보여줍니다.

selection

어떤 행을 검색할지 정합니다. WHERE에 해당하는 내용으로 null을 지정하면 모든 행을 출력합니다.

selectionArgs

 

groupBy

GROUP BY에 해당하는 내용으로 특정 속성을 기준으로 그룹을 지어 출력합니다. 설명이 힘들기 때문에 SQL문을 참조하시기 바랍니다. null을 지정하면 그룹을 만들지 않습니다.

having

GROUP BY에서 조건을 정하는 부분입니다. 해당 속성 기준으로 조건에 만족하는 것만 출력합니다.

orderBy

ORDER BY에 해당하는 내용으로 행을 어느 속성 기준으로 정렬시킬지 정합니다. null의 경우 정렬시키지 않습니다.

limit

LIMIT에 해당하는 내용으로 출력 행의 수를 제한합니다.

 

쿼리를 이용한 검색

void execSQL(String sql)

SQL문은 검색의 경우는 다음과 같습니다.

execSQL(“SELECT 속성 FROM 테이블 명 WHERE 조건

GROUP BY 속성 HAVING 조건 ORDER BY 속성 LIMIT 행의 수”);

 

SQLite 이용 예제

public class EnglishWord extends Activity {

                  WordDBHelper mHelper;

                  EditText mText;

                  public void onCreate(Bundle savedInstanceState) {

                                   super.onCreate(savedInstanceState);

                                   setContentView(R.layout.data_englishword);

 

                                   mHelper = new WordDBHelper(this);

                                   mText = (EditText)findViewById(R.id.edittext);

 

                                   findViewById(R.id.insert).setOnClickListener(mClickListener);

                                   findViewById(R.id.delete).setOnClickListener(mClickListener);

                                   findViewById(R.id.update).setOnClickListener(mClickListener);

                                   findViewById(R.id.select).setOnClickListener(mClickListener);

                  }

                 

                  Button.OnClickListener mClickListener = new View.OnClickListener() {

                                   public void onClick(View v) {

                                                     SQLiteDatabase db;

                                                     ContentValues row;

                                                     switch (v.getId()) {

                                                     case R.id.insert:

                                                                       db = mHelper.getWritableDatabase();

                                                                       // insert 메서드로 삽입

                                                                       row = new ContentValues();

                                                                       row.put("eng", "boy");

                                                                       row.put("han", "머스마");

                                                                       db.insert("dic", null, row);

                                                                       // SQL 명령으로 삽입

                                                                       db.execSQL("INSERT INTO dic VALUES (null, 'girl', '가시나');");

                                                                       mHelper.close();

                                                                       mText.setText("Insert Success");

                                                                       break;

                                                     case R.id.delete:

                                                                       db = mHelper.getWritableDatabase();

                                                                       // delete 메서드로 삭제

                                                                       db.delete("dic", null, null);

                                                                       // SQL 명령으로 삭제

                                                                       //db.execSQL("DELETE FROM dic;");

                                                                       mHelper.close();

                                                                       mText.setText("Delete Success");

                                                                       break;

                                                     case R.id.update:

                                                                       db = mHelper.getWritableDatabase();

                                                                       // update 메서드로 갱신

                                                                       row = new ContentValues();

                                                                       row.put("han", "소년");

                                                                       db.update("dic", row, "eng = 'boy'", null);

                                                                       // SQL 명령으로 갱신

                                                                       //db.execSQL("UPDATE dic SET han = '소년' WHERE eng = 'boy';");

                                                                       mHelper.close();

                                                                       mText.setText("Update Success");

                                                                       break;

                                                     case R.id.select:

                                                                       db = mHelper.getReadableDatabase();

                                                                       Cursor cursor;

                                                                       // query 메서드로 읽기

                                                                       //cursor = db.query("dic", new String[] {"eng", "han"}, null,

                                                                       //                                null, null, null, null);

                                                                       // SQL 명령으로 읽기

                                                                       cursor = db.rawQuery("SELECT eng, han FROM dic", null);

                                                    

                                                                       String Result = "";

                                                                       while (cursor.moveToNext()) {

                                                                                        String eng = cursor.getString(0);

                                                                                        String han = cursor.getString(1);

                                                                                        Result += (eng + " = " + han + "\n");

                                                                       }

 

                                                                       if (Result.length() == 0) {

                                                                                        mText.setText("Empyt Set");

                                                                       } else {

                                                                                        mText.setText(Result);

                                                                       }

                                                                       cursor.close();

                                                                       mHelper.close();

                                                                       break;

                                                     }

                                   }

                  };

}

 

class WordDBHelper extends SQLiteOpenHelper {

                  public WordDBHelper(Context context) {

                                   super(context, "EngWord.db", null, 1);

                  }

 

                  public void onCreate(SQLiteDatabase db) {

                                   db.execSQL("CREATE TABLE dic ( _id INTEGER PRIMARY KEY AUTOINCREMENT, " +

                                   "eng TEXT, han TEXT);");

                  }

 

                  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

                                   db.execSQL("DROP TABLE IF EXISTS dic");

                                   onCreate(db);

                  }

}

 

 

C. 자료의 표현(CursorAdapter)

 

커서(Cursor)

앞서 보면 종종 커서에 대한 얘기가 나옵니다. 일반적인 커서의 뜻은 위치를 가리키는 곳이라는 뜻입니다.

안드로이드에서는 결과 셋의 위치를 가리키는 포인터라고 이해하면 됩니다. 커서를 이용하면 대단히 많은 양이라고 할지라도 위치를 가리키는 특성 때문에 부하가 높지 않습니다.

 

커서를 이용해 쿼리 읽기

검색을 한 경우 리턴되는 커서는 가장 처음 레코드의 앞을 가리킵니다. 이후에 moveToNext를 이용하여 첫 레코드부터 차례로 다 읽을 수 있습니다. 보통 while문을 사용합니다.

while(cursor.moveToNext()){ … }

 

어댑터를 이용한 출력

커서를 어댑터에 바인딩해 놓으면 어댑텨 뷰로 출력할 수가 있습니다. 커서를 사용하는 어댑터는 아래와 같습니다.

SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to)

인수

설명

context

컨텍스트를 의미합니다. 보통 메인 액티비티가 됩니다.

layout

커서를 출력할 레이아웃을 말합니다.

c

검색한 데이터의 원본인 커서를 말합니다.

from

열 이름을 배열로 지정합니다.

to

각 열이 어느 위젯으로 출력될지 위젯의 ID를 지정합니다.

 

커서 어댑터 사용 예제

 

public class ProductList extends Activity {

                  ProductDBHelper mHelper;

                  public void onCreate(Bundle savedInstanceState) {

                                   super.onCreate(savedInstanceState);

                                   setContentView(R.layout.data_productlist);

                                  

                                   mHelper = new ProductDBHelper(this);

                                   Cursor cursor;

                                   SQLiteDatabase db = mHelper.getWritableDatabase();

 

                                   cursor = db.rawQuery("SELECT * FROM product", null);

                                   startManagingCursor(cursor);

 

                                   SimpleCursorAdapter Adapter = null;

                                   Adapter = new SimpleCursorAdapter(this,

                                                                       android.R.layout.simple_list_item_2,

                                                                       cursor, new String[] { "name", "price" },

                                                                       new int[] { android.R.id.text1, android.R.id.text2});

                                   ListView list = (ListView)findViewById(R.id.list);

        list.setAdapter(Adapter);

                  }

}

 

class ProductDBHelper extends SQLiteOpenHelper {

                  public ProductDBHelper(Context context) {

                                   super(context, "Product.db", null, 1);

                  }

 

                  public void onCreate(SQLiteDatabase db) {

                                   db.execSQL("CREATE TABLE product ( _id INTEGER PRIMARY KEY AUTOINCREMENT, " +

                                                     "name TEXT, price INTEGER);");

                                   db.execSQL("INSERT INTO product VALUES (null, '오징어 땅콩', 900);");

                                   db.execSQL("INSERT INTO product VALUES (null, '농심 포테이토 칩', 2000);");

                                   db.execSQL("INSERT INTO product VALUES (null, '로보트 태권 V', 1000);");

                                   db.execSQL("INSERT INTO product VALUES (null, '꼬마 자동차 붕붕', 1500);");

                                   db.execSQL("INSERT INTO product VALUES (null, '윈도우즈 API 정복', 32000);");

                                   db.execSQL("INSERT INTO product VALUES (null, '롯데 인벤스 아파트', 190000000);");

                                   db.execSQL("INSERT INTO product VALUES (null, '88 라이트', 1900);");

                                   db.execSQL("INSERT INTO product VALUES (null, '프라이드 1.6 CVVT 골드', 8900000);");

                                   db.execSQL("INSERT INTO product VALUES (null, '캐리비안 베이 입장권', 25000);");

                  }

 

                  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

                                   db.execSQL("DROP TABLE IF EXISTS product");

                                   onCreate(db);

                  }

}

 

* 포스트의 내용은 김상형 저, "안드로이드 프로그래밍 정복"의 내용을 참고하였습니다.

 

출처 : http://blog.naver.com/crowdark7/109969054


RSS :
Response

Mysql Replication 으로 분산처리 하기

MySQL Replication(복제)

MySQL Replication(복제)  개나 2 이상의 MySQL database server(slave) 하나의 MySQL database server(master) 부터 데이터를 복제해   있는 기능을 제공한다.

MySQL Replication 비동기 방식으로 처리된다 slave master로부터 데이터를 받아 복제하기 위해 항상 master 연결되어 있을 필요가 없다.

 

MySQL Replication Binary logging mechanism 사용하여 이뤄진다.

Master 서버는(MySQL 인스턴스) binary log 변경된 데이터 정보를 기록하며  log slave 읽어서 실행함으로써 복제가 된다.

 

Master에서 binary logging 활성화되면 Master 모든 데이터 구문이 bindary log 저장되며 slave bindary log 모든 내용을 복사해서 읽어온다.

따라서 slave log 파일내의 position 유지할 필요가 있다그래야 로그파일 전체를 처음

부터 읽지 않고 효과적으로 로그 파일을 운영할  있다.

여기서 position 로그파일내 위치를 의미하며 어느 부분부터 읽겠다는 것을 의미 한다.

 

Configuration 따라 다음과 같은 단위로 복제가 이뤄질  있다.

l  all database

l  selected database

l  selected tables within a database

 

 

 

Replication 구성  – Appendix A.


 

Replication Configuration

 

[ Master Configuration ]

1.  Replication User 생성
slave
 master 접속하여 데이터를 복제하기 위한 MySQL 계정이 필요하다. root 사용해도 상관 없지만 slave Replication 설정을 하면(slave configureation 참조) 계정 정보가 암호화되지 않은 텍스트 형태로 slave 서버의 master.info(mysql\data) 파일에 기록이 되기 때문에 보안상 root 기타 계정을 사용하는 것을 권하지 않는다따라서 복제를 위한 계정을 하나 생성한다.
 계정은 단지 REPLICATION SLAVE Privilege 있으면 되므로 다음과 같이 계정을 생성한다.(REPLICATION SLAVE Privilege 있으면 된다는 의미는 INSERT/UPDATE 등과 같은 Privilege 필요 없다는 의미이다따라서 복제 계정은 mysql query실행을  없다.)

mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' IDENTIFIED BY 'slavepass';

è  repl 계정이며 slavepass 계정의 비밀번호 이다.

è  %대신 IP주소를 넣으면  IP로부터 접속하는 slave 대해서만 접속을 허용하겠다는 의미(그냥 % 사용하자..!)

n  ) ….. ON *.* TO 'repl'@'1.1.1.2' IDENTIFIED BY 'slavepass';

 

2.  Configuration 설정(my.ini 또는 my.cfg)

[mysqld]

log-bin=mysql-bin

server-id=1

è  server-id 1~(2^32)-1내의 숫자중 아무것이나 설정해도 된다.

è  log-bin=mysql-bin는 바이너리 로그파일의 생성경로이며 log-bin만 기입시 기본 디렉토리에 생성된다.

3.  MySQL 데몬 재시작

 

4.  Master 정보 보기

mysql> FLSUSH TABLES WITH READ LOCCK;

mysql> SHOW MASTER STATUS;

+------------------+----------+--------------+------------------+

| File                | Position | Binlog_Do_DB | Binlog_Ignore_DB |

+------------------+----------+--------------+------------------+

| mysql-bin.000001 |       98   |                 |                     |

+------------------+----------+--------------+------------------+

è  File : 로그 파일을 의미한다.

è  Position : 로그 파일내 읽을 위치

è  Binlog_Do_DB : binary log 파일(변경된 이벤트 정보가 쌓이는 파일)

è  Binlog_Ignore_DB : 복제 제외 정보

n  Binlog_Do_DB Binlog_Ignore_DB Slave 시작하기 전까지는 나타나지 않는다.


 

[ Slave Configuration ]

1.  Configuration 설정

[mysqld]

server-id=2

replicate-do-db=’database name’


# master-host=xxx.xxx.xxx.xxx  --> 마스터의 IP

master-user=xxxx  --> 리플리케이션용 ID

master-password=xxxx  --> 패스워드

master-port=3306  --> 접속할 포트번호 (일반적인 포트 3306)

è  slave server-id 정의한다 1~(2^32)-1내의 숫자중 아무것이나 설정해도 되나 Master와는 다르게 한다.

è  replicate-do-db: 복제할 데이터베이스를 의미한다.

n  2 이상의 데이터 베이스 복제를 원하면 replicate-do-db  추가한다.

 

2.  database dump

복제할 데이터베이스를 master로부터 dump하여 넣는다.

 

3.  CHANGE MASTER TO

Master 연결하기 위한 정보를 다음과 같이 설정한다.

mysql> CHANGE MASTER TO

MASTER_HOST='Master server host name or Master server IP',

MASTER_USER='replication user',

MASTER_PASSWORD='replication password',

MASTER_LOG_FILE='Log File name',

MASTER_LOG_POS=position;

è  MASTER_HOST: Master 서버의 정보를 입력한다.

è  MASTER_USER: replication 위해 생성한 계정 ID

è  MASTER_PASSWORD: replication 위해 생성한 계정 비밀번호

è  MASTER_LOG_FILE: SHOW MASTER STATUS에서 보이는 로그 파일 

è  MASTER_LOG_POS: SHOW MASTER STATUS에서 보이는 position

n  SHOW MASTER STATUS master에서 실행해야 한다.(master 설정 참고)

 

4.  MySQL 데몬 재시작

 

 Slave 실행이 되면(MySQL 데몬 시작 또는 slave start) master 접속하기 위한 정보를 master.info(mysql\data)에서 읽어 온다만일 master.info 아무런 정보가 없으면 my.ini 참고하여 master.info 연결정보를 기록한다.

여기서 주의할 점은 이미 master.info 정보가 있으면 my.ini 참조하지 않으므로 my.ini정보를 수정해도 master 연결시 반영되지 않는다.

그러나 CHANGE MASTER TO 이용하면 master.info 바로 변경한다.

따라서 master 연결정보는 my.ini 설정하는  보다는 CHANGE MASTER TO 이용하여 설정하는게 낫다.

 

다음과 같은 option CHANGE MASTER TO에서 사용된다.

master-host

master-user

master-password

master-port

master-connect-retry

master-ssl

master-ssl-ca

master-ssl-capath

master-ssl-cert

master-ssl-cipher

master-ssl-key

 

 

 

[양방향 동기화 처리]

Master서버에서 Slave 구현하고자 한다면 다음과 같은 방법으로 처리

1. 현재 Slave서버에 replication 계정 생성

2. 현재 Slave my.ini 변경

log-bin=mysql-bin 추가

3. 현재 SLAVE 서버 데몬 재시작

4. 현재 Master my.ini 변경

replicate-do-db=’database name’추가

4. 현재 Master에서 CHANGE MASTER TO 실행

5. 현재 Master 서버 데몬 재시작

 

 


 

Replication Monitoring

//ON Master

mysql> SHOW PROCESSLIST\G

*************************** 1. row ***************************

Id: 11

User: repl

Host: 192.168.1.22:3556

db: NULL

Command: Binlog Dump

Time: 21960

State: Has sent all binlog to slave; waiting for binlog to be updated

Info: NULL

Slave 192.168.1.22 repl계정으로 thread11 연결되어 있음을 보여준다.

 

 

//On Slave

mysql> show processlist\G

*************************** 1. row ***************************

     Id: 1

   User: system user

   Host:

     db: NULL

Command: Connect

   Time: 23049

  State: Waiting for master to send event

   Info: NULL

*************************** 2. row ***************************

     Id: 2

   User: system user

   Host:

     db: NULL

Command: Connect

   Time: 4294967289

  State: Has read all relay log; waiting for the slave I/O thread to update it

   Info: NULL

Id 1: Master 서버와 통신하기 위한 I/O Thread

Id 2: update 내용을 처리하기 위한 SQL Thread

 2개의 Thread 오류가 발생하면 안된다.

 

 

mysql> show slave status\G;

*************************** 1. row ***************************

             Slave_IO_State: Waiting for master to send event

                Master_Host: 192.168.1.14

                Master_User: repl

                Master_Port: 3306

              Connect_Retry: 60

            Master_Log_File: mysql-bin.000004

        Read_Master_Log_Pos: 9187563

             Relay_Log_File: shin-relay-bin.000013

              Relay_Log_Pos: 9187700

      Relay_Master_Log_File: mysql-bin.000004

           Slave_IO_Running: Yes

          Slave_SQL_Running: Yes

            Replicate_Do_DB: ipm3

        Replicate_Ignore_DB:

         Replicate_Do_Table:

     Replicate_Ignore_Table:

    Replicate_Wild_Do_Table:

Replicate_Wild_Ignore_Table:

                 Last_Errno: 0

                 Last_Error:

               Skip_Counter: 0

        Exec_Master_Log_Pos: 9187563

            Relay_Log_Space: 9187700

            Until_Condition: None

             Until_Log_File:

              Until_Log_Pos: 0

         Master_SSL_Allowed: No

         Master_SSL_CA_File:

         Master_SSL_CA_Path:

            Master_SSL_Cert:

          Master_SSL_Cipher:

             Master_SSL_Key:

      Seconds_Behind_Master: 0

Slave_IO_State: 현재 Slave 상태를 나타낸다.(Appendix B 참고)

Slave_IO_Running: I/O Thread 상태

Slave_SQL_Running: SQL Thread 상태

Last Error: 최근에 발생한 오류정상인 경우  값은 없다.

Seconds_BeHind_Master:  값이 크면 클수록 Master로부터 복제할  없는 데이터가 많음을 나타낸다.

 

 

mysql> stop slave

mysql> start slave

MySQL 데몬(서비스)  시작하면 slave 자동으로 시작된다.(my.ini 옵션 skip-slave-start 있으면 자동 시작 안한다.)



[기타 알아두어야 할 내용]

1. 안정성을 위해서 두대의 DB서버의 버전을 동일하게 맞추어 주는것이 좋다.

2. 버전이 다른경우 높은 버전은 Slave 만 가능하다.

3. 서버는 Master 를 먼저 시작한 후 Slave를 시작시킨다.

4. Master의 status 에 지정된 File 이외의 로그파일은 삭제해도 무방하다.

5. Master의 status의 Position과 Slave status의 Read_Master_Log_Pos는 동일해야 한다.

6. 서버환경, 계정이 바뀐후에는 데이터 디렉토리안의 master.info를 변경하거나 제거한 후 재시작을 해야한다.

7. Master의 Replication로그나 Slave의 relay-bin로그는 vi로는 읽을수 없으며 아래와 같은 방법으로 변환후에 읽을 수 있다.


# mysqlbinlog KRDAC1FLD001-relay-bin.000002 > log.sql

8. Insert 이후 Slave 동기화 도중 데이터 조회가 이루어 져야 하는 상황에는 해당 경우만 Master DB에서 보게 하거나 process 종료 후 sleep 타임을 잠시주어 해결하면 된다



1. 구성도



MySQL 리플리케이션은 이중화의 역할 보다는 부하 분산의 역할을 한다고 볼 수 있다. 이 구성은 데이터베이스의 데이터를 갱신(입력/수정/삭제 등) 및 조회(검색 등)하는 비율에 따라 도입 유무를 판단 할 수 있다. 물론, MySQL 리플리케이션 도입에 가장 이상적인 서비스는 대형 포털 사이트와 같은 조회형 서비스에 적합하다.


2. 슬레이브 서버 별로 데이터 분산



MySQL 리플리케이션에서 슬레이브 서버마다 데이터를 동일하게 가져갈 수 있지만 이처럼 각각의 데이타를 가지고 있을 수 있다. 이와 같이 데이터를 나눠 주는 이유는 부하 분산의 차원이다.


3. 이중마스터 서버



MySQL 리플리케이션에 이중 마스터 서버 구성으로 하는 이유는 슬레이브 서버로 인한 마스터의 서버의 부하를 분산하는 차원이다. 여기서 마스터2 서버는 각 슬레이브에 대해서 마스터 서버의 역할을 수행하긴 하나 마스터1 서버에 대해서는 슬레이블 서버의 역할을 하고 있다.


4. 장애 대처



MySQL 정상적인 서비스가 진행 중이다. 평시에는 슬레이브 서버 중 하나를 백업용으로 활용하는 것도 좋다.


5. 장애복구



MySQL 리플리케이션 서비스 중에 마스터 서버에 장애가 발생하였다면, 슬레이브 서버 중 하나를 마스터 서버로 전환을 하여 서비스를 정상적으로 복구 할 수 있다. 추후 장애가난 마스터 서버가 정상화 되면 슬레이브 서버 중 하나로 역할을 수행하게 만든다.



출처 : http://hanaduri.egloos.com/2389708


RSS :
Response

Intent 존재여부 확인하기

Android는 Intent라고 불리는 아주 강력하지만 사용하기 편리한 Message Type을 제공한다. Intent를 사용함으로써 Applications을 고수준의 라이브러리로 바꾸어 코드의 모듈화 및 재사용을 가능하게 한다. 예를 들어, Android Home Screen과 응용프로그램의 단축 버튼들은 단축키를 생성하는데 Intents를 광범위하게 사용하고 있다.

느슨하게 결합되어 있는 API를 사용하는 것이 좋은 반면 사용자가 보내는 Intent가 다른 Application에 의해 받아지는 것에 대한 확신은 가질 수 없다. 이러한 현상은 Panoramio(위치정보를 제공하는 App)와 그것의 RADRA Intent와 같이 3rd-party Apps에서 특히 일어난다.

이번 Article은 여러분이 사용하고 싶어하는 Intent를 처리할 수 있는 어떤 Application을 시스템이 포함하고 있는지를 알아볼 수 있는 Technique을 기술하게 된다. 아래의 예제는 시스템 Package Manager에게 어떤 App이 특정 Intent에 응답할 수 있는지의 여부를 결정하도록 요청하는 Helper Method를 보여준다. 여러분의 응용프로그램은 해당 Method로 Intent를 보낼 수 있고, 예를 들자면 그런 다음에 해당 Intent를 보낼 수 있는 사용자 Options을 숨기거나 보여줄 수 있다.

/** 
* Indicates whether the specified action can be used as an intent. This 
* method queries the package manager for installed packages that can 
* respond to an intent with the specified action. If no suitable package is 
* found, this method returns false. 

* @param context The application's environment. 
* @param action The Intent action to check for availability. 

* @return True if an Intent with the specified action can be sent and 
*         responded to, false otherwise. 
*/
public static boolean isIntentAvailable(Context context, String action) {
    final PackageManager packageManager = context.getPackageManager();
    final Intent intent = new Intent(action);
    List<ResolveInfo> list =
            packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
    return list.size() > 0;
}

다음에는 그러한 Helper Method를 어떻게 사용할 수 있는지를 보여준다.
@Overridepublic boolean onPrepareOptionsMenu(Menu menu) {
    final boolean scanAvailable = isIntentAvailable(this, "com.google.zxing.client.android.SCAN");
    MenuItem item;
    item = menu.findItem(R.id.menu_item_add);
    item.setEnabled(scanAvailable);
    return super.onPrepareOptionsMenu(menu);
}

이러한 예제에서, Barcode Scanner Application이 설치되어 있지 않다면 Menu는 비활성화 처리된다.

좀더 간단하게 startActivity()를 호출했을 때 ActivityNotFoundException을 캐치하도록 하는 또다른 방법이 있지만 그러한 문제발생에 반응만 할 수 있다. 즉, 여러분은 그러한 것을 예측할 수 없고 동작하지 않기를 바라는 무언가를 차단하는 것에 따라 UI를 업데이트할 수 없다는 것이다. 또한 여기에 기술된 방법은 설치 되지않은 패키지를 설치하고자 하는지를 사용자에게 Startup time시에 묻는데 사용될 수 있다. 그런 다음, 적당한 URI를 사용하여 사용자를 Android Market으로 간단하게 안내할 수 있게 된다.


RSS :
Response

MYSQL 쿼리시 ENUM의 ORDER BY

SQL 컬럼 형식이 ENUM 일때 ORDER BY 의 순서는

필드 내용의 오름차순, 내림차순이 아닌 ENUM 형식의 선택값의 순서에 따라 정렬된다

필드 종류
varchar(10)
enum('standard','reserve')


SELECT
 * 
FROM `test` 
ORDER BY `test`.`varchar` ASC 
LIMIT 0 , 30

varchar  enum
reserve reserve
standard2 standard


SELECT * 
FROM `test` 
ORDER BY `test`.`enum` ASC 
LIMIT 0 , 30

varchar enum 
standard standard
reserve2 reserve

RSS :
Response