[리니지M] 혈맹 창설 및 가입


리니지M 캐릭터 사전 등록이 가능 하게 되면서 혈맹도 창설이 가능 하다


혈맹은 군주 캐릭터로 등록한 유저만 가능 하다



군주캐릭터 등록후


혈맹 창설 버튼을 클릭한 후




혈맹 창설 버튼을 클릭한 후 


혈맹 이름을 입력해 만들면 된다!



줄쟁이도 혈맹을 만들었는데 


켄라우헬 3서버의 치킨 이라는 혈맹이다


치킨은 누구나 좋아 하니까 



https://lineagem.plaync.com/preorder/guild/index?invitationId=MzU3Mjc=


위 링크로 들어가면 혈맹 가입이 가능해 진다



줄쟁이의 혈맹에 가입해 함께 게임을 한다면 혼자 하는 것보다


훨씬 많은 장점이 있다!


리니지 레볼루션때와 같이 현직 프로그래머이며 블로거인 군주가


각종 정보를 공유하고


버그소식과 매크로정보등을 빠르게 접할 수 있을 테니까!


그리고 가장 중요한건


이미 혈맹에 가입 되어 있으니 회사사람들


차장 부장 과장님들과 함께 게임하면서 강제로


회사혈맹에 가입하지 않아도 된다는 점이 있다!





사전 혈맹 창설 후 혜택은 아래와 같다






혈맹 가입 해서 즐거운 게임을 하도록 하자


켄라우헬 3섭 치킨 혈맹 가입은


https://lineagem.plaync.com/preorder/guild/index?invitationId=MzU3Mjc=



이곳에서!




2017/05/18 - [Yame Game Life/Lineage M] - [리니지M] 캐릭터 사전 생성


[리니지M] 캐릭터 사전 생성


리니지 M 캐릭터 사전 등록이 시작 되었다.


직업은 기존의 리니지1에 있었던


군주, 요정, 기사 , 마법사 


이렇게 4가지 클래스를 선택 할수 있으며 남여 선택이 가능 하다.



첫날부터 엄청난 등록으로 이미 1서버들은 등록이 만료 되었다




캐릭터 사전 등록은


https://lineagem.plaync.com/



이곳에서 할 수 있다


캐릭터 사전 등록 규칙은 아래와 같다


NC플레이 가입하라고 하는데 페이스북이나 구글 아이디로도 등록이 가능 하다






그리고 캐릭터 생성룰은




2017/05/18 - [Yame Game Life/Lineage M] - [리니지M] 사전 혈맹 창설 및 가입


[MSSQL] 프로시저 트리거 while 반복문, 변수값 컬럼명으로 사용하는 방법





1
2
3
4
5
6
7
8
9
10
11
12
declare @colCount int, @colNum int, @columnName CHAR(8) -- 변수 선언
set @colCount = 0
 
while @colCount < 24 -- 반복문 시작
    begin
        SET @columnName = 'T' -- 변수를 컬럼명으로 사용하기 위한 변수
        IF @colCount < 10 BEGIN
            SET @columnName = 'T0' -- 컬럼명이 T00 T01 T02 이런식일때 
        END
        exec ('select ' + @columnName + @colCount + 'into tValData from T_TABLE_NAME')
        set @colCount = @colCount +1 -- 
    end -- 반복문 끝
cs



테이블의 컬럼명이 T00 T01 이런식으로 될떄가 있다.


for문을 돌리고 싶다거나 변수값을 컬럼명으로 사용하고 싶을땐 위와 같이 사용 하면 된다.

[Spring] MyBatis Batch + Transaction 을 이용한 대용량 SQL작업


마을에서 오크잡는 퀘스트 하고 있는데 갑자기


중간보스를 잡아오라는 퀘스트가 떨어졌다...



일정시간마다 라즈베리파이에서 받아온 원시데이터를 재가공하여


DB에 insert 해주어야 하는 작업


로우수가 적다면 그냥 만들겠지만 대용량 작업일 경우 답이 안나온다.


약 1만건~10만건 정도의 데이터를 날려줘야 하는데 ㅂㄷㅂㄷㅂㄷ


그래서 찾아본 방법은 Batch와 Transaction 을 이용한 대용량 sql 작업



나도 정확히 내가 뭘 한건지도 모르고 그냥 스택오버 플로우, 오키, 전자정부 뒤적거리면서 이것 저것 다 때려 박느라

필요 없는 설정이 있을 수도 있으니 아는 사람은 댓글좀 달아주시길 바랍니다.



1.  XML 설정


1) mapper 설정

context-mapper.xml 파일이나 context-sqlMap.xml 파일에


마이바티스 연동을 위해 만들어놨던 설정을 아래와 같이 바꿔준다.


9번 라인의 batch설정으로 batch 사용이 가능 하도록 하는 듯 하다.


1
2
3
4
5
6
7
8
9
10
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:/egovframework/sqlmap/example/sql-mapper-config.xml" />
        <property name="mapperLocations" value="classpath:/egovframework/sqlmap/example/mappers/mssql/*.xml" />
    </bean>
 
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
        <constructor-arg index="0" ref="sqlSession" />      
        <constructor-arg index="1" value="BATCH" />
    </bean>
cs



2) datasource 설정

DB접속 정보 작성하는 곳에 트렌젝션메니저 설정을 하는데 이걸 해야 하는 건진 잘 모르겠다.


1
2
3
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
cs



3) dispatcher-servlet 설정


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:task="http://www.springframework.org/schema/task" 
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                   http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context-4.0.xsd
                http://www.springframework.org/schema/task
                http://www.springframework.org/schema/task/spring-task.xsd
                http://www.springframework.org/schema/mvc 
                http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
 
 
<tx:annotation-driven proxy-target-class="true"/>
cs


7번 라인과 17번 라인을 추가해주고 20번라인의 내용을 넣어 주도록 한다.



4) pom.xml


1
2
3
4
5
6
7
8
<!-- 트랜젝션 처리를 위함 -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
cs



디펜던시에 추가를 해줘야 트랜젝션 처리가 가능한건진 모르겠음. 전자정부 자체에 관련된게 이미 추가 되어 있을 수도 있고

정확히 모르겠음 저건



2. DAO or impl 작성


나는 DAO를 사용하지 않고 공통DAO하나 만들어 놓고 impl에서 바로 쿼리를 날려주는 방식을

좋아 한다.


어차피 DAO에서 특별히 해줄것도 없고.. 해줘야 하는것이 있어도 impl에서 해주면 되니까



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
    public void updateSchedulerHistoryRow(List<MinHistoryVO> historyList) {
        // TODO Auto-generated method stub
        
       // 트렌젝션 시작
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        long startTime = System.currentTimeMillis();
            try {
                
                for (MinHistoryVO list : historyList) {                     
                    sqlSession.update("scheduler.updateSchedulerHistoryRow", list);
                }
 
            } finally {
                sqlSession.flushStatements();
                sqlSession.close();
            }
 
        long endTime = System.currentTimeMillis();
        long resutTime = endTime - startTime;
        System.out.println("트랜젝션 배치" + " 소요시간  : " + resutTime/1000 + "(ms)");
    }
cs



난 이런식으로 작성 했다.


가끔 6번 라인에 ExecutorType.BATCH 이 매개변수를 안넣고 시작 할 수 있는데

그러면 트렌젝션 안돌고 커넥션 다 찍으면서 돌게 된다.


저렇게 해도 수만건이 돌게 되면 세션에저장될 데이터들이 넘쳐흘러서 그런지 버벅거릴때가 있는데


그럴땐 컨트롤러에서 조금씩 끊어서 날려 주도록 하자



3. controller


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
        //컨트롤러에서 일정 개수 단위로 끊어서 날려 준다.
        int insertCount = 0;
        List<MinHistoryVO> divHisList  = new ArrayList<MinHistoryVO>();
        for(int hisCount = 0, hisSize = historyList.size(); hisCount < hisSize; hisCount++){
            MinHistoryVO _tempData = new MinHistoryVO();
            _tempData = historyList.get(hisCount);
            divHisList.add(_tempData);
            if(insertCount == 1000 || hisSize-1 == hisCount){
                schedulerService.updateSchedulerHistoryRow(divHisList); // 트렌젝션
                divHisList =  new ArrayList<MinHistoryVO>();
                insertCount = 0;
            }
            else{                    
                insertCount++;
            }
        }
cs



while문 사용하는게 익숙하지 않아서 나는 for문을 주로 사용 한다.

리스트에 잔뜩 있는 데이터들을 새로운 작은 바구니에 담아서 끊어서 날려준다.








이렇게 하면 MsSql Server 2005버전 기준 1만건 insert하는데 5초정도 걸린다.


저기에  마이바티스 foreach까지 써서 벌크인서트 하면 시간은 더 단축 된다.


원시데이터를 쪼개서 60개컬럼에 따로 박아야 하기 때문에


넘겨주는 파라미터 개수 2100개 제한이 있어서 제대로 사용 못했는데


여러개로 쪼갠다음에  Mybatis foreach 돌려서 한번에 날려주면 시간은


훨씬 더더더더더 단축 된다.





Socket.IO 자기 브라우저 에서만 emit 되는 현상 해결 방법


남는시간에 react를 공부해 보고자 튜토리얼들을 보고 난 후


실시간 채팅기능을 만들어 보고자


socket.io를 사용 하게 되었다.


여러가지 React Socket.io 라든지  Socket.io React 라던지 여러가지 많았는데 이것 저것 삽질 하다가


그냥 원래 node.js에서 잠깐 만들었던 방법으로 socket.io만 사용해서 구현 하기로 했다.


그런데 분명히 코딩도 제대로 했고


브라우저에서 emit 날려주면 날린 브라우저에서는 값을 다시 제대로 받아 오는데


다른 브라우저에서 날려준 값을 받아오지 못하는게 아닌가


반나절을 삽질을 하다가


socket.io 레퍼런스 사이트를 들어가 하나씩 들춰 보기 시작했다.


.

.

.

.


세상에....


한달사이에 또 무언가 바뀌어 있었다 ㅋㅋㅋㅋㅋㅋ



view단에서가 아니라 server단에서 바뀐게 있었다


기존에 서버에 작성했던 코드는


1
2
3
4
5
6
7
8
9
// 소켓 통신 관련
var io = require('socket.io').listen(3303);
console.log("socket server run!!");
 
io.sockets.on("connection"function(socket){
  socket.on('private'function(msg){ // 응답
    socket.emit('private',msg); // 요청
  });
});
cs



이런식이었다. 그런데 이게 업데이트 되면서


위와 같이 작성한 소켓통신은 통신을 요청한 브라우저 에서만 다시 서버에서 요청을 날려주는 것 이었다.


응답은 받지만 다시 클라이언트로 요청을 날려주는건 요청한 브라우저에게만 날려 주는 것.



접속한 모두가 서버로 부터 요청을 받기 위한 방법


1
2
3
4
5
6
7
8
9
10
// 소켓 통신 관련
var io = require('socket.io').listen(3303);
console.log("socket server run!!");
 
// 커넥션된 모드에게 날려주는 것
io.on('connection'function(socket){
  socket.on('chat'function(msg){
    io.emit('chat', msg);
  });
});
cs


서버에서 이렇게 작성을 해 주어야 한다.



뭐가 다른지 햇갈린다면 두개를 동시에 비교 해 보도록 하자



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 소켓 통신 관련
var io = require('socket.io').listen(3303);
console.log("socket server run!!");
 
// 소켓 통신 날린 사람만 받을 수 있는 것.
io.sockets.on("connection"function(socket){
  socket.on('private'function(msg){ // 응답
    socket.emit('private',msg); // 요청
  });
});
 
 
// 커넥션된 모드에게 날려주는 것
io.on('connection'function(socket){
  socket.on('chat'function(msg){
    io.emit('chat', msg);
  });
});
cs



위는 날린 사람에게만 날려주는 것


아래는 모두에게 날려주는 것


커넥션을 할때 io.sockets.on 과 io.on의 차이 였다.


물론 이렇게 한다면 개인적인 소켓통신을 하도록 하는 것이 더 편해지는 것 같다.






[MSSQL]Insert실행시 자동증가되는 IDENTITY값 바로 가져오기



insert를 실행시키고 자동으로 증가 되도록 해놓은 PK값이 바로 필요한 경우가 있다.


A테이블에 값이 입력되면 그 값에 종속되는 B테이블의 값을 넣어야 하는데


PK를 알아오기 위해서 insert후 다시 select 하더라도 한 컨트롤러에서 해결하기란 힘들다.


게다가 해당 pk값을 모르기 때문에 다시 select 하는 것도 문제.


해결 방법


1
2
SELECT @@IDENTITY
 
cs

이걸 사용 하는 것 이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
 
INSERT INTO 
        T_AUTH
        (
         VAL1
        ,VAL2
        ,VAL3)
values(
        #{VAL1}
        ,#{VAL2}
        ,#{VAL3})
 
SELECT @@IDENTITY AS SEQ
cs



이런식으로 사용 하면


SEQ라는 컬럼에 자동증가된 값을 반환 한다


참고로 MYBAITIS에서는


INSERT가 아니라 SELECT로 감싸줘야 정상 작동 한다


예를 들어


1
2
3
4
5
6
7
8
9
10
11
12
13
14
<select id="insertAuth" parameterType="VO" resultType="VO">
    INSERT INTO 
        T_AUTH
        (
         VAL1
        ,VAL2
        ,VAL3)
    values(
        #{VAL1}
        ,#{VAL2}
        ,#{VAL3})
 
    SELECT @@IDENTITY AS SEQ
</select> 
cs



이런식으로 만들면 VO SEQ에 해당 값이 담겨서 리턴 된다.

react-router v4  browserHistory.push 오류 해결 방법


리엑트 라우터가 버전3에서 버전4로 올라감에 따라 


엄청나게 많은 것들이 변했다.


지금 새로운 프로젝트를 만들고 새로운 버전의


패키지들을 받은 후 코딩을 하려면 불과 한달전에 공부했던 코드들이 동작하지 않게 되었다.



망할.. 예전 webpack 버전1에서 2버전으로 올라가면서 바뀐거 찾아내느라 생고생 했는데



이젠 react-router가 문제다




Link를 사용하지 않고 바로 함수 내에서 리다이렉트를 시키는 방법으로


v3에서는 



1
browserHistory.push('/');
cs


이렇게 사용 하였으나


v4에선


Uncaught (in promise) ReferenceError: browserHistory is not defined


브라우저 콘솔창에 위와 같은 에러 메세지가 나타난다.


해결방법


생각보다 간단했다. 위의 코드 대신에


1
this.props.history.push('/');
cs



이렇게 사용해주면 된다.


물론 상단에 리엑트 라우터를 임포트시킬 필요는 없다.


그냥 기능이 넘어와 버린건지 정확하게는 알 수 없지만


깃터브를 뒤져보니 아래와 같은 의견을 찾았다.


걍 이전버전에서는 됐는데 v4에선 안된다 라는 말 같다.





@wyze @timdorr first of all thanks for the v4. I have a few questions and I could not find any solutions for this anywhere, so asking here.

In the earlier versions of the react-router, we could push the the URL using browserHistroy.push() method. When you use browserHistroy the query which you pass, will be transformed to the search key in the history object. The below is an example which used to work in earlier versions.

let query = {
  reportType: 'summary',
  timeZone: 'UTC'
}
  browserHistroy.push({
    pathname: 'some_path',
    query
  })

This will resolve the URL to - test.com/some_path/?reportType=summary&timeZone=UTC

In the current version (v4), it is not possible to pass the query object to the history.push() method.

  histroy.push({
    pathname: 'some_path',
    query
  })

This will resolve the URL to - test.com/some_path/

How to get this working with v4.

자취생 100kg부터 살빼기 2차도전 - 1주차


작년 10월  다이어트 4주차에 업무 스트레스에 못이겨


다시 폭풍음주  + 야식크리로 자연스럽게 다이어트는 실행하지 못했다.



저번 다이어트는 식단만 먼저 바꿔놓고 운동은 나중에 하기로 했었는데


이제는 운동도 겸해야겠다.



저번주까지만 해도 몸무게는 95키로 정도였는데 

신기하게도 몇일 운동했더니 98키로 까지 올라갔다..



운동은


유산소 40분~1시간


근력운동 - 30분 (타바타 + 그외의 부위)


정도로 진행 할 것이고


복근 타바타는 저번주부터 하루 2회씩 간단하게나마 하고 있다.



일단... 먹는건 포기가히가 너무 힘들기 때문에


먼저 혼술을 끊는것 부터 시작 하기로 했다.


밖에서 사람들이랑 먹는건 아직까진 도저히 못끊겠고


집에서 혼자 야식+혼술 하는것 에서 술만 빠져도 큰 도움이 되지 않을까 하는 생각이다.



MongoDB 기본 명령어


설치방법은 여러군데 소개되어 있으니 패스.


1. 접속 방법


C:\Program Files\MongoDB\Server\3.2\bin



윈도우에서 몽고DB 설치 경로의 bin 폴더를 환경변수 path에 등록하지 않았다면 


CMD에서 해당 경로로 이동후


만약 path설정 했다면 아무데서나 


1
> mongod
cs



라는 명령어로 몽고DB 서버를 실행 시킨다


그 이후


1
> mongo

cs


명령어로 접속 하면 된다.






2. 데이터베이스 생성



1
> use yamea_db
cs



use db명


이런식으로 DB를 생성해 줄 수 있다


현재 사용중인 DB를 확인 하려면


1
> db
cs



db라는 명령으를 사용하면 현재 사용중인 DB명이 나타난다



내가 만든 DB 리스트를 확인하는 방법은


1
> show dbs
cs


show dbs 라는 명령으를 사용 하면 되는데 데이터베이스를 만들자마자


확인하는 경우엔 목록이 뜨지 않는다


최소한 한개 document를 추가 해야 한다


1
> db.book.insert({"name""Yamea MongoDB""author""cheesu"});
cs


이런식으로 추가 하면


디비목록에 보여지게 된다.




3. 데이터베이스 제거


1
2
3
4
 > use yamea_db
switched to db mongodb_tutorial
> db.dropDatabase();
"dropped" : yamea_db "ok" : }
cs


이렇게 use 명령어로 삭제하려는 db 접속후


db.dropDatabase(); 


명령어를 사용하면 데이터베이스 제거를 할 수 있다.




4. 컬렉션 생성


1) createCollection 생성



use 명령어로 DB 접속 후


1
 > db.createCollection("book")
cs


명령어로 생성



2) createCollection + 옵션 생성





1
 > db.createCollection("articles", {capped: true, size: 6142800,max: 10000)}
cs



이렇게 한줄로 쭉 써도 되고


1
2
3
4
5
6
 > db.createCollection("articles", {
... capped: true,
... autoIndex: true,
... size: 6142800,
... max: 10000
... })
cs



이렇게 db.createCollection("articles",{  까지만 입력후 엔터를 쳐서


옵션을 하나씩 추가하는 방법도 가능하다


그런데 현재 버전에서 autoIndex를 포함시키면 에러가 나는데


이유는 모르겠다. 어차피 처음 배우는거니 크게 신경쓰진 말고 이런게 있구나 하고 알아두기만 하자



3) document추가로 인한 자동 생성


createCollection 명령어를 사용하지 않아도 document를 추가 하면 자동으로 컬렉션이 생성 된다.



이렇게 추가 한 컬렉션을 



1
 > show collections
cs


show collections 명령으를 사용하면 만든 컬렉션 목록을 보여주는데




이렇게 나타나게 된다.





5. 컬렉션 제거


컬렉션 제거는 drop() 메소드를 사용 한다.


1
2
3
4
5
6
7
8
9
10
11
> use test
switched to db test
> show collections
articles
book
people
> db.people.drop()
true
> show collections
articles
book
cs



이렇게 하면 people 컬렉션이 사라짐을 확인 할 수 있다.




6. Document 추가


이 Document가 일반 RDBMS에서 말하는 row, data, 행, 


뭐 이런거라고 생각하면 조금 이해가 빠를 거라 생각 된다.



추가 방법은 


1
> db.book.insert({"name""Yamea Guide""author""cheesu"})
cs



이렇게 하나의 다큐먼트를 추가하는 방법과


여러줄을 넣는 방법이 있는데 배열형식으로 전달해 주면 여러 다큐먼트를 동시에 추가 할 수 있다.


1
2
3
4
> db.book.insert([
... {"name""Book1""author""Cheesu"},
... {"name""Book2""author""Yamea"}
... ]);
cs



이런식으로 가능 하며


컬렉션의 다큐먼트 리스트를 확인 하는 방법은


1
> db.book.find()
cs


db.컬렉션이름.find()  이렇게 사용 하면 된다.



이렇게 넣은 document 들을 확인 할 수 있다.




7. Document 제거


db.컬렉션이름.remove(criteria, justOne)


이런 명령어를 사용 하는데


critetia : 삭제할 데이터의 기준값. 이 값이 {} 이면 컬렉션의 모든 데이터를 제거

justOne : 선택적 매개변수이며 이 값이 true면 1개의 다큐먼트만 제거 합니다. 

           생략하면 기본값은 false이며 criteria에 해당되는 모든 다큐먼트들을 제거 한다.



위의 document에서


name이 "yamea Book1"인 Document를 제거 하기 위해선

1
> db.book.remove({"name""Yamea Book1"})
cs



이런 명령어를 사용 하면 된다.





Yame Book1이 사라진걸 확인 할 수 있다.





configuration resolve has an unknown property 'root' path 해결 방법


만약


webpack.config.js 파일에서


경로 작성시 불편함을 해소 하기 위해


resolve: {
root: path.resolve('./src')
},


위와 같은 코드를 사용후


configuration resolve has an unknown property 'root' path 


라는 메세지가 나오며 build할대 에러가 난다면


https://webpack.js.org/guides/migrating/


이곳을 참고 하자



resolve: {
alias: {
Components: path.resolve(__dirname, 'src/components/'),
Containers: path.resolve(__dirname, 'src/containers/')
}
},



이런식으로 alias를 추가해주고 추가한 별칭으로 경로를 사용하면 해결이 된다.



resolve문제인지 모르고 오전내내 삽질하다가


프로젝트를 처음부터 싹 밀어버리고 다시 하나씩 추가해가면서 빌드를 하던중


resolve 문제인걸 알고 한참동안 찾았다.


문서는 항상 진즉에 읽어보도록 하자


webpack1 에서 webpack2로 마이그레이션 되면서


바뀐 부분이 정말 너무 많다;;; 


지금 보고 있는 강좌가 webpack1 일때 작성되었던 강좌라 


설정방법들이 조금씩 다르다.


따로 가르쳐주는 사람이 없으니 정말 맨땅에 헤딩하면서 공부 하는데 


재밌긴 한데 어렵기도 하다.










+ Recent posts