54.iBATIS, MyBatis/iBatis2008. 11. 13. 10:13
반응형

---다이나믹쿼리------------------------------------------

 

 <statement id="UserLikeGenre" resultClass="common.bean.Genre">
  SELECT * FROM GENRE
  <dynamic prepend="WHERE">
   <isNotEmpty prepend="OR" property="genrename1">
    GENRENAME LIKE '%$genrename1$%'
   </isNotEmpty>
   <isNotEmpty prepend="OR" property="genrename2">
    GENRENAME LIKE '%$genrename2$%'
   </isNotEmpty>
   <isNotEmpty prepend="OR" property="genrename3">
    GENRENAME LIKE '%$genrename3$%'
   </isNotEmpty>
   <isNotEmpty prepend="OR" property="genrename4">
    GENRENAME LIKE '%$genrename4$%'
   </isNotEmpty>
   <isNotEmpty prepend="OR" property="genrename5">
    GENRENAME LIKE '%$genrename5$%'
   </isNotEmpty>
  </dynamic>
 </statement>

 

값이 비어있지 않다면 생성해준다~

 

statement 를사용하면 '$$' 로 해야 하며~ %%로 검색하기 위해서

statement를 사용

 

 

---간단한 select 문------------------------------------------

 

<select id="UserCouponeCheck" resultClass="common.bean.Coupone">
  SELECT * FROM COUPONE WHERE ID=#id# AND COUPONEENDDAY
  <![CDATA[>]]>           <-- 요놈은 xml 검증 무시~하기 위해
  SYSDATE
 </select>

 

 

 

---간단한 insert 문------------------------------------------

 

 <insert id="UserInsertGenre">
  INSERT INTO MEM_LIKEGENRE(MEMLIKEGENRENO, ID, GENRECODE)
  VALUES(MEM_LIKEGENRE_SEQ.NEXTVAL,#id#,#likegenreno#)
 </insert>

 

 

---간단?한 update 문---------------------------------------

 

 <statement id="UserUpdate">
  UPDATE MEMBER SET
  ID='$id$',NAME='$name$',PASSWORD='$password$',SSN='$ssn$',
  DETAILADDR='$detailaddr$',PHONE='$phone$',EMAIL='$email$',
  BIRTHDAY=TO_DATE('$birthday$','yy/mm/dd'),
  MILEAGE='$mileage$',SEQ='$seq$' WHERE ID LIKE '%$id$%' AND
  PASSWORD LIKE '%$password$%' AND ssn LIKE '%$ssn$%'
 </statement>

 

Posted by 1010
54.iBATIS, MyBatis/iBatis2008. 11. 13. 10:12
반응형

- iBATIS가 적합하지 않은 경우 ( 정통 ORM 프레임웍이 더 적합한 경우)


 
1.
개발자가 데이터베이스에 대한 전권을 가지고 있는 경우.
    개발 완료 후 운영시점에는 데이터베이스에 대한 권한을 가지지 못할 가능성이 있는 경우는 제외.

 2. 개발팀내에 데이터베이스 쿼리에 대한 구루 개발자가 없는 경우

 3. 개발팀내의 개발자들이 새로운 툴 또는 프레임웍에 대한 도전의식이 넘치는 경우 혹은 새로운
    기술에 대한 오픈 마인드를 가지고 있는 경우

 4. 한번의 데이터 액세스 구문 작성으로 여러 데이터베이스를 지원해야 할 경우

 5. 어플리케이션의 전체 레이어가 모두 객체지향적 아키텍쳐를 지향하고 싶은 경우

 6. 데이터베이스의 정규화가 잘 적용되어 있는 경우
 

 

- iBATIS가 더 적합한 경우 ( 정통 ORM 프레임웍이 적합하지 않은 경우)


 
1.
데이터베이스에 대한 전권을 가지고 있지 못한 경우

 2. SQL 쿼리에 대한 완벽한 제어를 해야 하거나 하고 싶은 경우

 3. DBA와 사이가 좋지 않은 경우 혹은 DBA가 직접 쿼리작성을 원하는 경우

 4. 개발팀원이 정통 ORM 툴에 대해 사전 지식이 없거나 학습할 수 있는 기간이 불충분한 경우

 5. 프로시져처럼 SQL 쿼리 구문만을 별도의 공간에 보관하고 싶은 경우

 6. 반복적인 쿼리 작성을 피하고 싶거나, 쿼리 구문의 재활용이 필요한 경우
 7. 데이타베이스의 정규화가 미비한 경우 (물론 잘 정규화된 DB에 대해서는 말할 것도 없고.. ㅡ.ㅡ)
 8. 이미 존재하는 데이터베이스에 대해서 새로운 어플리케이션을 개발해야 하는 경우

Posted by 1010
54.iBATIS, MyBatis/iBatis2008. 11. 13. 10:08
반응형

가장 간단히 설명하면, JAVA에서 DB관련 작업을 편하게 해주는 프레임웍정도라고 할까?

iBATIS in action에서 iBATIS는 "SQL 실행 결과를 자바빈즈 혹은 Map 객체에 매핑해주는 퍼시스턴스 솔루션으로 SQL을 소스 코드가 아닌 XML로 따로 분리해 관리하여 지겨운 SQL 문자열 더하기에서 해방시켜 줍니다. 또한 XML에서 동적 SQL 요소를 사용하여 쿼리 문장을 프로그래밍 코딩 없이 자유롭게 변환할 수 있게 해줍니다. 이러한 접근방식으로 인해 iBATIS를 사용하면 JDBC를 사용할 때보다 약 60% 정도의 코드만으로 프로그램 작성이 가능하다" 라고 한다.

말로만 하면 뭔소리인지 모르겠으니 간단한 예제 정도를 들어보자.

- 일반적인 JDBC 예제
import javax.naming.*;
import javax.sql.*;
import java.sql.*;

public class Employee {
  public Account getAccount(int id) throws SQLException, NamingException{
    Account account = null;
    
    String sql = "select * from employee where id= ?";
    
    Connection conn      = null;
    PreparedStatement ps = null;
    ResultSet rs       = null;
    
    try {      
      Context ctx = new InitialContext();
      DataSource ds =
              (DataSource)ctx.lookup(
                 "java:comp/env/jdbc/TestDB"); 
      conn = ds.getConnection();
      ps = conn.prepareStatement(sql);
      ps.setInt(1, id);
      rs = ps.executeQuery();
      
      while( rs.next()){
        account = new Account();
        account.setId(rs.getInt("ID"));        
      }
    } finally {
      try {
        if ( rs != null ) rs.close();
      } finally {
        try {
          if (ps != null) ps.close();
        } finally {
          if (conn != null) ps.close();
        }
      } 
    } 
    return account;  
  }
}   

뭐다들 아시겠지만 간단히 쿼리를 날려서 Acount 객체에 담아가지고 오는 소스이다. 대충봐도 무척이나 길다,
이걸 iBATIS를 이용해서 처리하는 예를 보자, 

- iBATIS 를 이용한 예
acount.xml
<select id="getAcount" resultClass="Acount" parameterClass="java.lang.Integer">

    select * from employee where id= #id#
</select>

java
Acount act = (Acount) sqlMap.queryForObject("getAcount",new Integer(5));
 
보면 알겠지만 상단에 쿼리를 닮고있는 xml과 아래 간단히 크 쿼리를 실행시키는 java 한줄정도?이다.
사실 iBATIS를 설정하는 config파일과 sqlMap객체를 불러오는 부분이 있긴하지만, 무척이나 좋아보이도록,
이것만 쓰겠다. -_-;;

iBATIS 의 목표와 특징은 몇마디로 짧게정의하다면,

쉽고, 간단하고, 의존성이 적은 프레임웍이라는 것이다. 
sql문과 java코드와의 분리만으로도 java개발자는 쿼리문을 신경쓰지 않아도 된다. sql문이 변경되더라도,
파라미터 값만 변경되지 않는다면, java소스에서는 수정할 부분이 없다.

~ 이론적인 면은 대충 접어두고 실전으로 넘어가자(사실 나도잘몰라서;;ㅈㅅ) 

다음 포스트는 실제로 이클립스에서 오라클 디비와 연동하겠습니다.

beans.tistory.com
Posted by 1010
54.iBATIS, MyBatis/iBatis2008. 11. 13. 10:08
반응형

1. 우선 iBATIS 를 다운받습니다.

2. 다운을 풀고, /lib 폴더에 ibatis-2.3.4.726 를 톰캣의 lib폴더나 프로젝트의 web-inf/lib 폴더에 넣습니다.
- /현제프로젝트/WebContent/WEB-INF/lib/
- /톰캣/lib/   (톰캣6버전)

두폴더중 편한곳에다가 jar파일을 저장합니다.


3. example 폴더를 타고 들어가보면 sqlMapConfi.xml 파일이 있습니다. 이파일을 복사해서 붙여넣기 하셔도되고
src폴더에서 새로 xml 파일을 만드셔도 됩니다.

sqlMapClient.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMapConfig      
    PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"      
    "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

  <!-- Configure a built-in transaction manager.  If you're using an 
       app server, you probably want to use its transaction manager 
       and a managed datasource -->
  <transactionManager type="JDBC" commitRequired="false">
    <dataSource type="SIMPLE">
      <property name="JDBC.Driver" value="org.hsqldb.jdbcDriver"/>
      <property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@192.168.10.103:1521:db"/>
      <property name="JDBC.Username" value="ahm"/>
      <property name="JDBC.Password" value="ahm"/>
    </dataSource>
  </transactionManager>

  <!-- List the SQL Map XML files. They can be loaded from the 
       classpath, as they are here (com.domain.data...) -->
  <sqlMap resource="db/Account.xml"/>
  <!-- List more here...
  <sqlMap resource="com/mydomain/data/Order.xml"/>
  <sqlMap resource="com/mydomain/data/Documents.xml"/>
  -->

</sqlMapConfig>

빨간부분으로 표시된부분이 제가 수정한 부분입니다. db정보는 propertie로 빼서 관리하는방법도 있으나, 
우선은 이렇게 하도록 하겠습니다. 

4. 자바빈즈를 생성합니다. 

db라는 패키지를 만들고 그 밑에 Acount.java 파일을 생성합니다. 결과를 담아올 빈즈입니다. 
Account.java

package
 db;

public class Account {
  private int id;

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }
}

5. XML을 생성합니다.

우리가 사용할 쿼리를 작성하는 XML입니다.
Account.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap      
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"      
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="Account">
  <!-- Select with no parameters using the result map for Account class. -->
  <select id="getAcount" resultClass="db.Acount">  다음값을 이용하여 쿼리와 맵핑합니다.
    select id from ACCOUNT where name=#value#
  </select>
</sqlMap>

6. 이제 쿼리를 실행할 JAVA를 작성한다.

SimpleExample.java

package db;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import com.ibatis.common.resources.Resources;

import java.io.Reader;
import java.io.IOException;
import java.sql.SQLException;

public class SimpleExample {

  private static SqlMapClient sqlMapper;

  static {
    try {
      Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
      sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader);
      reader.close(); 
    } catch (IOException e) {
      // Fail fast.
      throw new RuntimeException("Something bad happened while building the SqlMapClient instance." + e, e);
    }
  }

  public static Account getAcount() throws SQLException {
    return (Account)sqlMapper.queryForObject("getAcount","ahm");
    // 이부분에서 쿼리를 실행한다. queryForObject는 한개의 데이터를 가져올떄 사용하는 메소드이다.
  }
  
  public static void main(String[] args){
    
    try {
    Account temp = getAcount();    
    System.out.println(temp.getId());
  } catch (SQLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
  }
}

물론 이 java파일을 실행하기 전에는 DB에 TABLE과 데이터가 준비되어있어야겠다.

현제 이클립스내에 폴더구조이다.


이미지와 같이 , iBATIS 를 설정하는 설정파일인 sqlMapConfig.xml 파일과
               실제 SQL이 담겨져 있는 Account.xml 파일
               결과를 담아올 객체인   Account.java 파일
               이러한 과정을 호출하는 SimpleExample.java 파일
               그리고 WEB-INF/lib 에 ibatis-**.jar 파일 등을 해당폴더에 넣고 위에 순서대로 따라한다면
               DB에서 요청사항을 무난히 가져올수 있을것이다. 

다음엔 좀더 세부적인 설정사항이라던지 자세한 정보를 보여드리겠습니다. 
                  HTTP://BEANS.TISTORY.COM

Posted by 1010
54.iBATIS, MyBatis/iBatis2008. 7. 25. 16:04
반응형

<JDBC 연결을 위한 DB서버 정보 세팅>

database.propertis

#ORACLE 10g  DB server관련 드라이버,URL,계정,비밀번호 세팅
db_driver=oracle.jdbc.driver.OracleDriver
db_url=jdbc:oracle:thin:@localhost:1521:XE
db_usernm=scott
db_pw=tiger

앞의 프러퍼티 이름은 임의로 정해주면 된다.


ORM을 위한 POJO 객체를 생성한다.

Member.java

//POJO
package com;

import java.io.Serializable;

public class Member implements Serializable {
 private String id;
 private String pw;
 private String nm;
 public String getId() {
  return id;
 }
 public void setId(String id) {
  this.id = id;
 }
 public String getNm() {
  return nm;
 }
 public void setNm(String nm) {
  this.nm = nm;
 }
 public String getPw() {
  return pw;
 }
 public void setPw(String pw) {
  this.pw = pw;
 }
}

테이블과 연관하기 위한 정보및 쿼리를 작성한다.

Member.xml

<?xml version="1.0" encoding="EUC-KR" standalone="no"?>
<!DOCTYPE sqlMap          
                                PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"          
                                "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="Member">
 <!--
  Member
 -->
 <typeAlias alias="member" type="com.Member" /><!-- pojo클래스 별칭주기 -->

 <resultMap id="getMemberAll" class="member"><!-- 클래스 프러퍼티와 디비 컬럼맵핑 -->
  <result property="id" column="id" />
  <result property="pw" column="pw" />
  <result property="nm" column="nm" />
 </resultMap>

 <select id="getMemberAll" resultMap="getMemberAll">
  SELECT id, pw, nm FROM MEMBER
 </select>
 
 <select id="getMember" resultMap="getMemberAll">
  SELECT id, pw, nm FROM MEMBER

  WHERE ID=#id#
 </select>

 <insert id="insertMember" parameterClass="member">
  INSERT INTO MEMBER (id, pw, nm) VALUES (#id#, #pw#, #nm#)
 </insert>

 <update id="updateMember" parameterClass="member">
  UPDATE MEMBER SET pw = #pw#, nm = #nm#

  WHERE ID = #id#
 </update>

 <delete id="deleteMember" parameterClass="member">
  DELETE FROM MEMBER WHERE ID = #id#
 </delete>

</sqlMap>

PreparedStatement에서 동적으로 값을 할당하기 위해 ?를 사용 하듯이

#id#처럼 동적으로 값이 할당 되는 부분을 정한다.


SqlMapClientManager.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig 
                                PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
                                "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
        <properties resource="com/database.properties" /><!-- 디비 정보 프러퍼티  세팅 -->
        <settings cacheModelsEnabled="false"
                  useStatementNamespaces="true"
        />

        <transactionManager type="JDBC"> <!--  프러퍼티 값을 세팅-->
                <dataSource type="SIMPLE">
                    <property name ="JDBC.Driver" value="${db_driver}"/>
                    <property name ="JDBC.ConnectionURL" value="${db_url}"/>
            <property name ="JDBC.Username" value="${db_usernm}"/>
            <property name ="JDBC.Password" value="${db_pw}"/>
                </dataSource>
        </transactionManager>

        <sqlMap resource="com/Member.xml" /> <!-- pojo, 테이블을 맵핑한 xml들 -->
</sqlMapConfig>
프러퍼티에 세팅한 정보를 가져와 JDBC관련 세팅을 하고,

pojo와 연관시킨 xml를 읽어 들인다.


SqlMapClientManager.java

package com;
import java.io.Reader;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
/**
*
* @author Administrator
*
*/
public class SqlMapClientManager {
       
        private static final SqlMapClient sqlMap;

        static {
                try {
                        String resource = "com/SqlMapClientManager.xml";
                        Reader reader = Resources.getResourceAsReader(resource);
                        sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
                       
                } catch (Exception e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                }
        }
       
        private SqlMapClientManager(){}
       
        public static SqlMapClient getSqlMapClient() {
                return sqlMap;  
        }

}

SqlMapClientManager.xml 파일을 읽어 들여 SqlMapClient 인스턴스를 생성한다.


MemberDAO.java

package com;

import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

import com.ibatis.sqlmap.client.SqlMapClient;

public class MemberDAO {

 private static SqlMapClient sqlMap = SqlMapClientManager.getSqlMapClient();
 public List listAll(){//모든 회원 조회

  Member paramMember = new Member();
  Member returnMember = new Member();

  List list=null;
  try {
   list = sqlMap.queryForList("Member.getMemberAll", paramMember);
  } catch (SQLException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  return list;

 }

 public Member getMember(Member member){  //회원 정보 조회

  Member paramMember = member;
  Member returnMember = new Member();

  try {
   member = (Member) sqlMap.queryForObject("Member.getMember", paramMember);
  } catch (SQLException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return member;
 }


 public void insert(Member member){ //회원 등록

  Member paramMember = member;
  System.out.println("insert Member");
  System.out.println(member.getId());
  System.out.println(member.getNm());
  System.out.println(member.getPw());
  try {
   sqlMap.insert("Member.insertMember",paramMember);
  } catch (SQLException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }
 public void update(Member member){
  // 사용자 수정
  Member paramMember = member;

  try {
   sqlMap.update("Member.updateMember",paramMember);
  } catch (SQLException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }

 public void delete(Member member){
  // 사용자 삭제
  Member paramMember = member;
  try {
   sqlMap.update("Member.deleteMember",paramMember);
  } catch (SQLException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }
}

sqlMapClient 인스턴스를 통해 MEMBER테이블에 접근하기 위한 API제공

Posted by 1010
54.iBATIS, MyBatis/iBatis2008. 7. 25. 16:03
반응형

Hibernate 첫 번째 예제 - 튜토리얼

                                  원문 : http://www.laliluna.de/first-hibernate-example-tutorial.html

                                  역자 : 김종대(jdkim528@korea.com)

이 튜토리얼은 Hibernate를 사용하는 간단한 예제를 보여준다. 우리는 Hibernate가 어떻게 동작하는지를 보여주는 간단한 자바 어플리케이션을 생성시킬 것이다.

(광고 생략...)

개괄

저자: Sebastian Hennebrueder

날짜: December, 19th 2005

사용된 소프트웨어와 프레임워크

Eclipse 3.x

MyEclipse 4.x가 권장되지만 선택사항임

Hibernate 3.x (3.1을 사용함)

소스 코드: http://www.laliluna.de/download/first-hibernate-example-tutorial.zip

소스들은 라이브러리들을 포함하지 않는다. hibernate.org에서 라이브러리들과 당신의 데이터베이스 드라이버를 내려 받고 그것들을 아래에 설명되어 있는 프로젝트에 추가한다. 예제는 당신의 데이터베이스 설정들과 동작하도록 구성되어야 한다! 튜토리얼을 읽기 바란다.

 

튜토리얼의 PDF 버전:  http://www.laliluna.de/download/first-hibernate-example-tutorial-en.pdf

Hibernate2용 이전 PDF 버전:  http://www.laliluna.de/download/first-hibernate-2-example-tutorial-en.pdf

짧은 개요

Hibernate는 객체 관계형 매핑을 위한 솔루션이고 영속 관리 솔루션 또는 영속 계층이다. 이것은 아마 Hibernate를 배우는 아무나 이해 가능한 것은 아니다.

당신이 생각할 수 있는 것은 아마 당신이 당신의 어플리케이션에 몇몇 기능들(비지니스 로직)을 갖도록 하고 데이터베이스 내에 데이터를 저장하고 싶어하는 것이다. 당신이 자바를 사용할 때 모든 비지니스 로직은 통상적으로 다른 클래스 타입들인 객체들과 동작한다. 당신의 데이터베이스 테이블들은 전혀 객체들이 아니다.

Hibernate는 데이터베이스 테이블들을 어떤 클래스로 매핑시키는 솔루션을 제공한다. 그것은 데이터베이스 데이터를 어떤 클래스로 복사한다. 반대 방향으로 그것은 객체들을 데이터베이스에 저장하는 것을 지원한다. 이 과정에서 객체는 하나 이상의 테이블들로 전환된다.

저장소에 데이터를 저장시키는 것은 영속이라 명명된다. 그리고 테이블들을 객체들에 복사하는 것 등등은 객체 관계형 매핑이라 명명된다.

Java 프로젝트를 생성한다

Eclipse를 사용하여 새로운 프로젝트를 생성시키기 위해 Ctrl+n (Strg+n) 키를 누른다. Java 프로젝트를 선택한다. 우리는 그것을 FirstHibernateExample라 명명할 것이다.
 

MyEclipse를 사용하여 Hibernate용 프로젝트를 준비한다

MyEclipse를 사용하고 있다면, 패키지 탐색기 내에서 당신의 프로젝트 상을 마우스 오른쪽 버튼 클릭하고 Add Hibernate capabilities.를 선택한다.




 

마법사를 계속하고 src 디렉토리 내에 새로운 hibernate.cfg.xml 을 생성시킨다.

마지막 단계에서 당신은 Hibernate SessionFactory를 생성시킬 수 있다. 나는 내 자신의 것을 생성 시키는 것을 선호한다. 당신은 아래에서 그것을 찾을 수 있다.

Hibernate용 프로젝트를 준비한다

당신이 MyEclipse를 사용하고 있지 않을 때 http://www.hibernate.org/ 웹 사이트로부터 Hibernate를 내려 받아라.

파일을 추출한다. Hibernate는 많은 라이브러리들의 목록으로 구성되어 있다. 당신은 그것들 모두를 필요로 하지 않는다. lib 디렉토리 내에 필수적인 것을 설명하고 있는 README 파일이 존재한다. 당신의 프로젝트 properties를 열고, “Java Build Path”를 선택하고, “Add External Jars”을 클릭하고 아래에 보이는 라이브러리들을 당신의 프로젝트 경로에 추가한다.

 



 

SessionFactory를 생성시킨다

세션 팩토리는 Hibernate에서 중요하다. 그것은 단위 쓰레드 당 오직 한 개의 세션 인스턴스만이 사용됨을 보증하는 설계 패턴을 구현하고 있다. 당신은 단지 이 팩토리로부터 당신의 Hibernate 세션을 얻을 것이다.

de.laliluna.hibernate 패키지 내에 HibernateSessionFactory로 명명된 클래스를 생성시키고 아래의 소스 코드를 추가한다.

/**
 * 
 * @author Sebastian Hennebrueder
 * created Feb 22, 2006
 * copyright 2006 by http://www.laliluna.de
 */
package de.laliluna.hibernate;

import javax.naming.InitialContext;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;

/**
 * @author hennebrueder 이 클래스는 오직 한 개의 SessionFactory 만이 초기화 되고
 *         컨피그레이션이 싱글톤으로 쓰레드 안전하게 행해진다는 점을 보증한다.
 *         실제로 그것은 단지 Hibernate SessionFactory를 포장한다.
 *         JNDI 이름이 구성될 때 세션은 JNDI에 바인드 되고, 
 *         그 밖의 경우 그것은 오직 로컬 상으로 저장된다.
 *         당신은 임의의 종류의 JTA 또는 Thread transactionFactory들을 사용하는 것이 자유롭다. 
 */
public class InitSessionFactory {

	/**
	 * Default constructor.
	 */
	private InitSessionFactory() {
	}

	/**
	 * hibernate.cfg.xml 파일의 위치. 주의: 위치는 Hibernate가 사용하는 classpath 상에 있어야 한다
	 * #resourceAsStream 스타일은 그것의 구성 컨피그레이션 파일을 검색한다.
	 * 그것은 Java 패키지 내에 있는 config 파일에 위치된다 - 
	 * 디폴트 위치는 디폴트 Java 패키지이다.<br>
	 * <br>
	 * 예제: <br>
	 * <code>CONFIG_FILE_LOCATION = "/hibernate.conf.xml". 
	 * CONFIG_FILE_LOCATION = "/com/foo/bar/myhiberstuff.conf.xml".</code>
	 */
	private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";

	/** hibernate 컨피그레이션의 싱글톤 인스턴스 */
	private static final Configuration cfg = new Configuration();

	/** hibernate SessionFactory의 싱글톤 인스턴스 */
	private static org.hibernate.SessionFactory sessionFactory;

	/**
	 * 아직 초기화 되지 않았다면 컨피그레이션을 초기화 시키고 현재 인스턴스를 반환한다
	 * 현재 인스턴스를 반환한다
	 * 
	 * @return
	 */
	public static SessionFactory getInstance() {
		if (sessionFactory == null)
			initSessionFactory();
		return sessionFactory;
	}

	/**
	 * ThreadLocal Session 인스턴스를 반환한다. 필요하다면 Lazy는 
	 * <code>SessionFactory</code>를 초기화 시킨다.
	 * 
	 * @return Session
	 * @throws HibernateException
	 */
	public Session openSession() {
		return sessionFactory.getCurrentSession();
	}

	/**
	 * 이 메소드의 행위는 당신이 구성했던 세션 컨텍스트에 의존한다.
	 * 이 팩토리는  다음 프로퍼티 is intended to be used with a hibernate.cfg.xml
	 * <property name="current_session_context_class">thread</property>를 
	 * 포함하는 hibernate.cfg.xml과 함께 사용되게 기안되어 있다. 이것은 
	 * 현재의 열려진 세션을 반환할 것이거나 존재하지 않을 경우 새로운 세션을 생성시킬 것이다
	 * 
	 * @return
	 */
	public Session getCurrentSession() {
		return sessionFactory.getCurrentSession();
	}

	/**
	 * 심지어 하나 이상의 쓰레드가 sessionFactory를 빌드하려고 시도하는 경우조차도 
	 * 안전한 방법으로 sessionFactory를 초기화 시킨다
	 */
	private static synchronized void initSessionFactory() {
		/*
		 * [laliluna] 다시 null을 체크한다 왜냐하면 sessionFactory가 마지막 체크와 현재의 체크 사이에
		 * 초기화 되었을 수도 있기 때문이다
		 * 
		 */
		Logger log = Logger.getLogger(InitSessionFactory.class);
		if (sessionFactory == null) {
 

			try {
				cfg.configure(CONFIG_FILE_LOCATION);
				String sessionFactoryJndiName = cfg
				.getProperty(Environment.SESSION_FACTORY_NAME);
				if (sessionFactoryJndiName != null) {
					cfg.buildSessionFactory();
					log.debug("get a jndi session factory");
					sessionFactory = (SessionFactory) (new InitialContext())
							.lookup(sessionFactoryJndiName);
				} else{
					log.debug("classic factory");
					sessionFactory = cfg.buildSessionFactory();
				}

			} catch (Exception e) {
				System.err
						.println("%%%% Error Creating HibernateSessionFactory %%%%");
				e.printStackTrace();
				throw new HibernateException(
						"Could not initialize the Hibernate configuration");
			}
		}
	}
 
	public static void close(){
		if (sessionFactory != null)
			sessionFactory.close();
		sessionFactory = null;
 
	}
}


 

Log4J 구성하기

당신이 위에서 보았듯이 우리는 log4j 라이브러리를 추가시켰다. 이 라이브러리는 소스 디렉토리 내에 컨피그레이션 파일처럼 행하거나 다음 오류로서 당신을 맞이한다.

log4j:WARN No appenders could be found for logger (TestClient).
log4j:WARN Please initialize the log4j system properly.

루트 디렉토리에 log4j.properties로 명명된 파일을 생성시키고 다음을 삽입시킨다:

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=debug, stdout

log4j.logger.org.hibernate=info
#log4j.logger.org.hibernate=debug

### log HQL query parser activity
#log4j.logger.org.hibernate.hql.ast.AST=debug

### log just the SQL
log4j.logger.org.hibernate.SQL=debug

### log JDBC bind parameters ###
log4j.logger.org.hibernate.type=info

### log schema export/update ###
log4j.logger.org.hibernate.tool.hbm2ddl=info

### log HQL parse trees
#log4j.logger.org.hibernate.hql=debug

### log cache activity ###
log4j.logger.org.hibernate.cache=info

### log transaction activity
#log4j.logger.org.hibernate.transaction=debug

### log JDBC resource acquisition
#log4j.logger.org.hibernate.jdbc=debug

### enable the following line if you want to track down connection ###
### leakages when using DriverManagerConnectionProvider ###
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace

데이터베이스 드라이버를 추가한다

Hibernate는 데이터베이스에 접근할 데이터베이스 드라이버를 필요로 한다. 프로젝트 properties를 열고, “Java Build Path”를 클릭하고, “Add External Jars”를 선택하고 당신의 데이터베이스 드라이버를 추가한다. 당신이 PostgreSQL를 사용할 때 당신은  http://jdbc.postgresql.org에서 당신의 데이터베이스 드라이버를 찾을 수 있고 MySQL을 사용하고 있다면 이곳 http://www.mysql.de/products/connector/j에서 찾을 수 있다.

데이터베이스와 테이블드을 생성시킨다.

Create a database with MySql 또는 PostgreSQL 또는 당신이 좋아하는 DBMS에 데이터베이스를 생성시킨다. 그것을 “firsthibernate”로 명명한다.

PostgreSql을 사용한다면 테이블을 생성시키기 위해 다음 스크립트를 사용하라:

CREATE TABLE "public"."honey" (
  id SERIAL, 
  name text, 
  taste text, 
  PRIMARY KEY(id)
);


 

MySql을 사용하고 있다면 다음 스크립트를 사용하라:

CREATE TABLE `honey` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(250) default NULL,
  `taste` varchar(250) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

클래스를 생성시킨다

Create a new class named “Honey” in the package “de.laliluna.example”. Add three fields id, name and taste and generate (Context menu -> Source -> Generate Getter and Setter) or type the getters and setters for the fields. Then create an empty constructor.

package de.laliluna.example;

/**
 * @author laliluna
 *
 */
public class Honey {
	private Integer id;
	private String name;
	private String taste;
 
	public Honey(){
 
	}
 
	/**
	 * @return Returns the id.
	 */
	public Integer getId() {
		return id;
	}
	/**
	 * @param id The id to set.
	 */
	public void setId(Integer id) {
		this.id = id;
	}
	/**
	 * @return Returns the name.
	 */
	public String getName() {
		return name;
	}
	/**
	 * @param name The name to set.
	 */
	public void setName(String name) {
		this.name = name;
	}
	/**
	 * @return Returns the taste.
	 */
	public String getTaste() {
		return taste;
	}
	/**
	 * @param taste The taste to set.
	 */
	public void setTaste(String taste) {
		this.taste = taste;
	}
}



 

매핑 파일들을 생성시킨다

이미 생성되어 있지 않다면 루트 디렉토리에 “hibernate.cfg.xml”로 명명된 새로운 파일을 생성시킨다.

hibernate 파일 내에 다음을 추가한다. 당신의 데이터베이스 구성에 적합하게 username과 password를 변경하는 것을 잊지 말라.

PostgreSQL 버전:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
	<property name="connection.url">jdbc:postgresql://localhost/firsthibernate</property>
	<property name="connection.username">postgres</property>
	<property name="connection.driver_class">org.postgresql.Driver</property>
	<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
	<property name="connection.password">p</property>
 <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
    <!--  thread is the short name for
      org.hibernate.context.ThreadLocalSessionContext
      and let Hibernate bind the session automatically to the thread
    -->
    <property name="current_session_context_class">thread</property>
    <!-- this will show us all sql statements -->
    <property name="hibernate.show_sql">true</property>
	<!-- mapping files -->
	<mapping resource="de/laliluna/example/Honey.hbm.xml" />
</session-factory>
</hibernate-configuration>


 

MySQL 버전:


 

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
	<property name="connection.url">jdbc:mysql://localhost/firsthibernate</property>
	<property name="connection.username">root</property>
	<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
	<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
	<property name="connection.password">r</property>
 <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
    <!--  thread is the short name for
      org.hibernate.context.ThreadLocalSessionContext
      and let Hibernate bind the session automatically to the thread
    -->
    <property name="current_session_context_class">thread</property>
    <!-- this will show us all sql statements -->
    <property name="hibernate.show_sql">true</property>
 
	<!-- mapping files -->
	<mapping resource="de/laliluna/example/Honey.hbm.xml" />

</session-factory>
</hibernate-configuration>


 

이 파일은 데이터베이스에 대한 구성 우리의 경우에는 PostgreSQL 데이터베이스의 구성 그리고 모든 매핑 파일들을 포함한다. 우리의 경우 그것은 단지 파일 Honey.hbm.xml이다. 

<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>

태그는 dialect를 구성한다. 당신의 데이터베이스에 맞게 이것을 변경하라. 당신의 데이터베이스를 위한 dialect를 찾기 위해 Hibernate 레퍼런스의 “SQL Dialects” 장에서 찾아보라.

de.laliluna.example 패키지 내에 Honey.hbm.xml을 생성시키고 그것을 다음으로 변경하라:

PostgreSQL 버전:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
 <class name="de.laliluna.example.Honey" table="honey">
 <id name="id" column="id" type="java.lang.Integer">
		<generator class="sequence">
				<param name="sequence">honey_id_seq</param>
			</generator>

 </id>
 
 <property name="name" column="name" type="java.lang.String" />
 <property name="taste" column="taste" type="java.lang.String" />
 </class>
</hibernate-mapping>


 

MySQL 버전:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
 <class name="de.laliluna.example.Honey" table="honey">
 <id name="id" column="id" type="java.lang.Integer">
 <generator class="increment"/>
 </id>
 <property name="name" column="name" type="java.lang.String" />
 <property name="taste" column="taste" type="java.lang.String" />
 </class>
</hibernate-mapping>


 

이 파일에서 우리의 클래스 Honey로부터 데이터베이스 테이블 honey로의 매핑이 구성되어 있다.

테스트 클라이언트를 생성한다

“de.laliluna.example” 패키지 내에 Java 클래스 “TestClient”를 생성시킨다.

다음 소스 코드를 추가한다. 그것은 데이터베이스 내에 엔트리들을 생성시키는 메소드, 그것들을 업데이트하고 리스트하는 메소드들을 포함하고 있다.

/**
 * Test application for example 
 * @author Sebastian Hennebrueder
 * created Jan 16, 2006
 * copyright 2006 by http://www.laliluna.de
 */

package de.laliluna.example;

import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import de.laliluna.hibernate.InitSessionFactory;

public class TestExample {

	private static Logger log =Logger.getLogger(TestExample.class);
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Honey forestHoney = new Honey();
		forestHoney.setName("forest honey");
		forestHoney.setTaste("very sweet");
		Honey countryHoney = new Honey();
		countryHoney.setName("country honey");
		countryHoney.setTaste("tasty");
		createHoney(forestHoney);
		createHoney(countryHoney);
		// our instances have a primary key now:
		log.debug(forestHoney);
		log.debug(countryHoney);
		listHoney();
		deleteHoney(forestHoney);
		listHoney();

	}

	private static void listHoney() {
		Transaction tx = null;
		Session session = InitSessionFactory.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();
			List honeys = session.createQuery("select h from Honey as h")
					.list();
			for (Iterator iter = honeys.iterator(); iter.hasNext();) {
				Honey element = (Honey) iter.next();
				log.debug(element);
			}
			tx.commit();
		} catch (HibernateException e) {
			e.printStackTrace();
			if (tx != null && tx.isActive())
				tx.rollback();

		}
	}

	private static void deleteHoney(Honey honey) {
		Transaction tx = null;
		Session session = InitSessionFactory.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();
			session.delete(honey);
			tx.commit();
		} catch (HibernateException e) {
			e.printStackTrace();
			if (tx != null && tx.isActive())
				tx.rollback();
		}
	}

	private static void createHoney(Honey honey) {
		Transaction tx = null;
		Session session = InitSessionFactory.getInstance().getCurrentSession();
		try {
			tx = session.beginTransaction();
			session.save(honey);
			tx.commit();
		} catch (HibernateException e) {
			e.printStackTrace();
			if (tx != null && tx.isActive())
				tx.rollback();
		}
	}
}


 

축하합니다. 당신은 Hibernate 세계에서 당신의 첫 번째 단계들을 마쳤습니다. 

우리는 당신이 Hibernate 세계에 빠르게 진입하기를 원했다. Hibernate를 사용하는 많은 복잡한 토픽들과 더 나은 구현이 존재한다. 예를 들어, 각각의 메소드 내에서 세션을 열고 닫는 것은 좋은 연습이 아니다. 하나의 세션은 재사용될 수 있으며 그 동안에 많은 시간을 절약한다.

당신이 최상의 실전에 대해 더 많은 것을 배우고자 원할 경우 우리의 세미나 또는 다른 튜토리얼을 살펴보길 바란다.

Copyright and disclaimer

This tutorial is copyright of Sebastian Hennebrueder, laliluna.de. You may download a tutorial for your own personal use but not redistribute it. You must not remove or modify this copyright notice.(이 튜토리얼은 Sebastian Hennebrueder, laliluna.de에 저작권이 있다. 당신은 당신 자신의 개인 용도로 튜토리얼을 내려받을 수 있지만 그것을 재배포할 수 없다. 당신은 이 저작권 경고를 제거하지 말아야 하거나 변경시키지 말아야 한다.이하 생략...)

The tutorial is provided as is. I do not give any warranty or guaranty any fitness for a particular purpose. In no event shall I be liable to any party for direct, indirect, special, incidental, or consequential damages, including lost profits, arising out of the use of this tutorial, even if I has been advised of the possibility of such damage.

Posted by 1010