스프링은 주요 데어터 엑서스기술인 자체적인 dataSource 생성 방식 대신 스프링 빈으로 등록돤 DataSource를 사용하여 필요한 방법을 제공해준다. 


스프링의 JDBC 기술과 동작원리
JDBC : 자바의 데이터 엑서스 기술이 기본이 되는 로우레벨의 API이다. 
기술
1.Connection 열기와 닫기
2.Statement 준비와 닫기 및 실행
sql 정보가 담긴 statement 또는 preparedStatment를 생성하고 필요한 준비작업을 한다. 
3.ResultSet 루프
ResultSet에 담기 쿼리 실행 결과가 한건 이상이라면 루프를 돌면서 각자 로우를 처리해줘야하는데 루프름 만들어 반복해주는것도 스프링 JDBC가 해주는 작업이다. 
4.예외처리의 반환
5.트랜잭션 처리 

SimleJdbcTemplate
 jdbcTemplate과 NameParameterJdbcTemplate에서 가장 많이 사용되는 기능을 통합하고 자바 5이상의 장점을 최대한 활용할 수 있게 만든것이다. 
멀티 스레드 환경에서도 안전하게 공유해서 사용가능하다. 

SimpleJdbcInsert, SimpleJdbcCall
DB가 제공해주는 메타정보를 활용해서 최소한의 코드만으로 단순한 JDBC코드를 작성하게 해준다.

sql파라미터
작업시 문자열로 된 sql을 제공해줘야하는데 파라미터 바인딩 방법을 사용한다. 
map / mapSQLParameterSource 사용
 -실행메소드 INSERT, UPDATE, DELETE와 같은 SQL을 사용할때 simpleJdbcTemplete의 update()를사용
 -조회메소드 
 -배치메소드 update()로 실행하는 sql들을 배치모드로 실행하게 해준다 JDBC statement를 사용하여 addBatch(), executeBatch() 메소드르 이용해 여러개의 sql을 처리한다. 

스프링의 DAO
 보통 DAO는 도메인 오브젝트 또는 DB 데이틀 단위로 만든다 . 스프링은 JdbcDaoSupport라는 JDBC를 이용한 DAO작서에 사용할수있는 추상클래스를 제공하고 있다. 

MYbatis 

 자바 오브젝트와 sql문 사이의 자동매핑 기능을 지원하는 ORM 프레임워크이다. 
sql을 자바 코드에서 분리하여 별도의 xml 파일 안에 작성하고 관리할 수 있어 sql 변경시 자바코드를 수정하고 컴파일 하지 않아도 된다.

 ORM(Object Relation Mapping) : 오브젝트와 RDB 사이에 존재하는 개념과 접근방법, 성격차이 때문에 요구되는 불편한 작업을 제거해줘서 개발자가 오브젝트를 가지고 정보를 다루면 ORM 프레임워크가 이를 RDB에 적절한 형태롸 변환해주거나 그 반대로 RDB에 저장되어있는 정보를 자바 오브젝트가 다루기 쉬운 형태로 변환해주는 기술이다. 
 따라서 ORM을 사용하는 개발자는 모든 데이터를 오브젝트 관점으로 본다. 

iBatis -> MyBatis
 -Apache project 팀에서 google code팀으로 이동하면서 명칭수정
 -용어변경
 SqlMapConfig -> Configration
 sqlMap => Mapper
 resultClass -> resultType
-자바 1.4까지만 iBatis 사용
-lib제공
<dependency>
    <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.2.2</version>
</dependency>
 
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis-spring</artifactId>
    <version>1.2.0</version>
</dependency>
-sqlMapClient DI 설정불필요 , sqlsessionFactory, sqlSessionTemplate만 bean id 지정하면 됨 ...


등록, 수정 , 삭제
 insert()  
 sql아이디(statementName)와 파라미터 오브젝트를 넣어주면 해당 insert 문을 실행한다. 
내부적으로 ibatis의 SqlMapExecutor의 insert() 메소드가 사용된다. 파라미터 유무에 따라 다음 두가지중 하나가 사용된다.
  Object insert( String statementName )
  Object insert( String statementName, Object parameterObject )

 update()
 실행후 영향받은 로우개수를 리턴해주는 메서드 2개와 로우 개수를 체크해주는 메소드 1개가 있다. 기대했던 로우수와 다른 경우 예외가 발생한다. 

 delete() 
  실행후 영향받은 로우개수를 리턴해주는 메서드 2개와 로우 개수를 체크해주는 메소드 1개가 있다. 기대했던 로우수와 다른 경우 예외가 발생한다. 

 조회
 단일 로우 오브젝트: 실행 결과가 한건
 다중 로우: 실행결과가 한건 이상인 경우 각 로우를 오브젝트에 담아 이를 다시 리스트로 돌려준다.
 다중 로우 조회( queryForMap() ): 맵이 앤드리마다 로우 하나의 내용이 들어간다. 맵의 키는 지정된 컬럼값이 사용된다. 
 핸들러 방식 ( queryWithRowHandler() ): sql의 결과를 루프를 돌면서 각 로우마다 콜벡 오브젝트를 호출하는 방식이다. 

mybatis 사용예시
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
        p:dataSource-ref="dataSource"
        p:configLocation="classpath:sqls/mybatis-config.xml"
        p:mapperLocations="classpath*:sqls/**/sql-*.xml">
    </bean>
    mybatis-config.xml
    <configuration>
        <typeAliases>
             <typeAlias alias="MemberVO"                type="com.bo.common.vo.MemberVO"/>
             <typeAlias alias="BoardVO"                 type="com.bo.common.vo.BoardVO"/>
        </typeAliases>
    <configuration>


    @VO( "MemberVO" )
    public class MemberVO{
       
       @Name( "순번" )
       private Object      seq;
       @Name( "순번필드명" )
       private String      seqName;
       @Name( "대상테이블명" )
       private String      tblName.... 
    member.xml
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="memberInfo">
       <resultMap type="MemberVO" id="result" />
       <select id="listMember" resultMap="result" parameterType="java.util.HashMap">
            SELECT * FROM tbl_member WHERE memberTeam=#{where.memberTeam}
        </select>.....
   
   MemberDaoImpl
      @Repository( "MemberDaoImpl" )
   public class MemberDaoImpl implements MemberDao{
       @Autowired
       @Resource ( name = "commonDB" )
       private SqlSession  sqlSession;
       @Override
       public List<MemverVO> list( Object object ) throws Exception{
             return sqlSession.selectList( "memberInfo.listMember", object );
       } ....
그밖의  mybatis 동적 SQL

    1.<trim>, <if>
    <select id="CommonFileInfo" resultType="Integer" parameterType="java.util.HashMap" useCache="false">
             SELECT
                    COUNT(*)
             FROM
                    BOARD
             <trim prefix="WHERE" prefixOverrides="AND | OR ">
                    <if test="where.fileType != null and where.fileType != ''">
                           AND FILE_TYPE = #{where.fileType}
                    </if>
                    <if test="where.regUser != null and where.regUser != ''">
                           AND REG_USER = #{where.regUser}
                    </if>
             </trim>
       </select>
            <where>태그의 오류를 대신한 것으로  where 엘리먼트는 태그에 의해 컨텐츠가 리턴되면 단순히 “WHERE”만을 추가한다. 
           게다가 컨텐츠가 “AND”나 “OR”로 시작한다면 그 “AND”나 “OR”를 지워버린다.
            
            2.<foreach>
        <update id="update">
             <foreach collection="list" item="item" index="index" open="INSERT ALL " separator=" " close="SELECT * FROM DUAL">
                     INTO BOARD(
                           SEQ
                           , NAME
                           , WRITER
                           <if test='item.modifyCause != null and item.modifyCause != "" and item.modifyCause != "-"'>
                           , MODIFY_CAUSE
                           </if>
                    ) VALUES
                    (
                           #{item.seq}
                           , #{item.name}
                           , #{item.writer}
                           <if test='item.modifyCause != null and item.modifyCause != "" and item.modifyCause != "-"'>
                           , #{item.modifyCause}
                           </if>
                    )
             </foreach>
       </update>
  1.  <choose>  
       SELCT *
       FROM
             <choose>
                    <when test="where.type eq 'tblboard1'.toString()">TBL_BOARD_1 TB_1</when>
                    <when test="where.type eq 'tblboard12'.toString()">TBL_BOARD_2 TB_2</when>
             </choose>
    4.bind
        <select id="selectBlogsLike" resultType="Blog">
        <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
        SELECT * FROM BLOG
        WHERE title LIKE #{pattern}
        </select>
mybatis의 plug-in
mybatis-config.xml
       <plugins>
           <plugin interceptor="com.util.MybatisInterceptor"/>
       </plugins>

mybatis에서는 plug-in을 이용하여 mybatis쿼리가 실행하는 시점에 간섭하여 사용자가 정의한 별도의 작업을 진행할수있다.

MybatisInterceptor.java
@Intercepts( {
    @Signature( type = Executor.class, method = "update", args = { MappedStatement.class, Object.class } ),
    @Signature( type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class } ),
    @Signature( type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class } ) } )
public class MybatisInterceptor implements Interceptor {
       @Override
       public Object intercept( Invocation invocation ) throws Throwable {
             Object args[] = invocation.getArgs();
             MappedStatement ms = (MappedStatement) args[0];
             String id = ms.getId();
             //로그 찍고 싶지않은 쿼리들 예외처리
             if ( "memberInfo.listMember".equals( id ) )
                    return invocation.proceed();
            
             //바인딩 변수 사용했을 경우 ?로 표시되므로 ?를 바인딩된 값으로 치환해준다. 
             BoundSql boundSql = ms.getBoundSql( args[1] );
             StringBuilder sql = new StringBuilder( boundSql.getSql() );
             if ( boundSql.getParameterMappings().size() > 0 ) {
                    ArrayList<ParameterMapping> parameterMappingsList = (ArrayList<ParameterMapping>) boundSql.getParameterMappings();
                    for ( int i = 0; i < parameterMappingsList.size(); i++ ) {
                        ParameterMapping parameterMapping = parameterMappingsList.get( i );
                        Object result = null;
                        String fieldName = parameterMapping.getProperty();
                        result = Ognl.getValue( fieldName, boundSql.getParameterObject() );
                        int index = sql.indexOf( "?" );
                        ....
                        sql.replace( index, index + 1, result );
                    }
             }

                            return sql;
       }

-prepared statement
쿼리가 실행되는 순서는 
구분분석(parse) >> 치환(bind) >> 실행(execute) >> 인출(patch) 과정을 거치는데  일반적인 statement를 사용하면 select쿼리를 입력했을때 매번 전과정을 수행한다. 하지만 prepared STatement를 사용하는 경우에는 효율을 높이기 위해 최초1번만 parse를 한다. 
 그리고 변경되는 값은 변수로 선언해주고 매번 값을 대입하여 사용하여아한다.  바인드 데이터는 sql문법이 아닌 내부의 인터프리터나 컴파일 언어로 처리하기 때문에 문법적인 의미를 가지지 않아 인젝션 공격에 안전하다. 













'STUDY > SPRING' 카테고리의 다른 글

@MVC (ing)  (0) 2018.11.12
Java EE 디자인패턴(ing)  (0) 2018.11.12
Aspect Oriented Programming  (0) 2018.11.06
TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02

+ Recent posts