ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • DB연동
    Spring_FrameWork 2019. 3. 22. 17:21

    JDBC 프로그래밍을 하다보면 중복되는 코드가 많다 .

    반복되는 줄이려고 탬플릿 메서드 패턴과 전략패턴을 사용해서 

    스프링이 만든것이 JdbcTemplate이다 이것을 활용하면 코드를 줄일수 있음 


    스프링으로 DB연동을 처리할때 얻을 수 있는 장점은 트랜잭견부분이다.

    JDBC API를 사용할 경우 , 트랜잭션을 처리하려면 다음과 같이 Connection 의 setAutoCommit()을 이용해서 자동 커밋을 비활성화 하고 

    commit() 과 rollback() 메서드를 이용해서 트랜잭션을 커밋하거나 롤백해야한다,


    public void insert(Member member){

    Connetion conn = null;

    PreparedStatement = null;

    try{

    conn = DriverManager.getConnection("jdbc:mysql://localhost/sprig4fs?characterEncoding=utf8","id","passward");

    conn.setAutoCommit(false)

    ....

    conn.commit();

    }catch(SQLException ex){

    if(conn!=null)

    try{conn.rollback();}catch(SQLException e){}

    }finally(){

    if(pstmt!=null){

    try{pstmt.colse();}catch(SQLException e){}

    }

    if(conn!=null){

    try{conn.colse();}catch(SQLException e){}

    }

    }

    }

    스프링을 사용하면 트랜잭션을 적용하고 싶은 메서드에 @Transactional 애노테이션을 붙이기만 하면 된다.


    pom.xml설정

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>sp4</groupId>
        <artifactId>sp4-chap08</artifactId>
        <version>0.0.1-SNAPSHOT</version>
     
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>4.1.0.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>4.1.0.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>com.mchange</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.2.1</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.30</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
        </dependencies>
     
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.1</version>
                    <configuration>
                        <source>1.7</source>
                        <target>1.7</target>
                        <encoding>utf-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
     
    </project>
    cs


    mysql 스키마 생성


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    create user 'spring4'@'localhost' identified by 'spring4';
     
    create database spring4fs character set=utf8;
     
    grant all privileges on spring4fs.* to 'spring4'@'localhost';
     
    create table spring4fs.MEMBER (
        ID int auto_increment primary key,
        EMAIL varchar(255),
        PASSWORD varchar(100),
        NAME varchar(100),
        REGDATE datetime,
        unique key (EMAIL) 
    engine=InnoDB character set = utf8;
    cs


    1행 mysql 사용자 spring4 계정생성 (암호로 spring4 사용)

    3행 spring4fs DB 생성

    5행 spring4fs DB에 spring4 계정이 접근할 수 있도록 권한 부여

    07 - 14 행 spring4fs DB에 Member테이블 생성 캐릭터셋은 utf8로 설정


    그리고 예제에서 사용할 데이터를 미리 넣어둔다

    insert into MEMBER(EMAIL, PASSWORD, NAME, REGDATE)

    values('aaa@aaa.net','1234','kim',now());


    03 DataSource 설정



    JDBC API 는 DataSource를 이용해서 DB를 연결을 구하는 방법을 정의 하고 있다. 

    DataSoruce를 사용하면 다음과 같은 방식으로 Connection을 구할 수 있다. 


    스프링이 제공하는 DB 연동기능도 DataSource를 사용해서 DBConnection 을 구할 수 있도록 구현 되어 있다.

    DB연동에 사용할 DataSource를 스프링 빈으로 등록하고

    DB연동 기능을 구현한 빈객체는 DataSource를 주입받아 사용한다.


    DataSource 기능을 제공하는 모듈로는 c3p0 와 dbcp 등이 존재하고, 

    스프링 테스트 목적으로 사용할 수 있는 DataSource 구현을 제공하고 있다.

    c3p0 모듈이 제공하는 DataSource 구현을 사용한다.


    c3p0모듈은 DataSource를 구현한 ComboPooledDataSource 클래스를 제공하고 있으므로, 이 클래스를 스프링 빈으로 등록해서 DataSource로 사용하면 된다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?xml version="1.0" encoding="UTF-8"?>
     
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd">
     
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
            destroy-method="close">
            <property name="driverClass" value="com.mysql.jdbc.Driver" />
            <property name="jdbcUrl" value="jdbc:mysql://localhost/spring4fs?characterEncoding=utf8" />
            <property name="user" value="spring4" />
            <property name="password" value="spring4" />
        </bean>
     
    </beans>
    cs


    driverClass : JDBC 드라이버 클래스를 지정한다. 위설정은 MYSQL 

    jdbcUrl :  JDBC URL 지정 , 데이터베이스와 테이블의 캐릭터 셋을 UTF-8로 설정 했으므로 JDBC URL의 caracterEncoding 파라미터를 이용해서 MYSQL에 연결할 사용할 캐릭터 셋을 UTF-8로 지정


    user : 사용자 계정 지정

    password : DB 연결할 때 사용할 암호 지정


    close : 커넥션 풀에 보관된 Connection을 종료할 목적으로 사용됨.


    04 JdbcTemplate 을 이용한 쿼리 실행


    DataSource를 설정했다면 스프링이 제공하는 JdbcTemplate 클래스를 이용해서 DB를 연동 처리 할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package spring;
     
    import java.util.List;
     
    import javax.sql.DataSource;
     
    import org.springframework.jdbc.core.JdbcTemplate;
     
    public class MemberDao {
        private JdbcTemplate jdbcTemplate;
        
        
     
        public MemberDao(DataSource dataSource) {
            super();
            this.jdbcTemplate = new JdbcTemplate(dataSource);
        }
    cs


    먼저 dataSource를 주입받도록 설정한다. 


    그리고 스프링에 MemberDao 클래스에 추가 했으므로 스프링 설정에 MemberDao 빈설정을 추가한다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <?xml version="1.0" encoding="UTF-8"?>
     
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd">
     
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
            destroy-method="close">
            <property name="driverClass" value="com.mysql.jdbc.Driver" />
            <property name="jdbcUrl" value="jdbc:mysql://localhost/spring4fs?characterEncoding=utf8" />
            <property name="user" value="spring4" />
            <property name="password" value="spring4" />
        </bean>
        
        <bean id"memberDao" class="spring.MemberDao">
            <constructor-arg ref="dataSource"/>
        </bean>
     
    </beans>
    cs



    JDBCTemplate를 이용한 조회 쿼리 실행 


    JdbcTemplate 클래스 SELECT 쿼리 실행을 위한 query() 메서드를 제공하고 있다.

    그중에서 자주 사용되는 쿼리 메소드

    - List<T> query(String sql, RowMapper<T> rowMapper)
    - List<T> query(String sql, Object[] args,RowMapper<T> rowMapper)
    - List<T> query(String sql, RowMapper<T> rowMapper, Object...args)

    sql파라미터로 전달받은 쿼리를 실행하고 rowmapper를 이용해서 ResultSet의 결과를 자바 객체로 변환한다.
    sql 파라미터가 인덱스 기반 파라미터 (PreparedStatement 의 물음표) 를 가진 경우 , args 파라미터를 이용해서 각 인텍스 파라미터를 지정한다.


    쿼리 실행결과를 변환하는 RowMapper 인터페이스는 다음과 같이 정의 되어있다.

    public interface RowMapper<T>{
    T mapRow(ResultSet rs, int rowNum)throws SQLException;
    }

    RowMapper의 mapRow() 메서드 SQL 실행결과로 구한 ResultSet으로부터 한 행의 데이터를 읽어와 이를 자바 객체로 변환해 주는 매퍼 기능을 구현한다.


    한번 해보자 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    package spring;
     
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.List;
     
    import javax.sql.DataSource;
     
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.RowMapper;
     
    public class MemberDao {
        private JdbcTemplate jdbcTemplate;
        
     
     
     
        public MemberDao(DataSource dataSource) {
            super();
            this.jdbcTemplate = new JdbcTemplate(dataSource);
        }
     
        public Member selectByEmail(String email) {
            //로우매퍼 인터페이스 구현
            RowMapper<Member> rm=new RowMapper<Member>() {
     
                @Override
                public Member mapRow(ResultSet rs,int rowNum) throws SQLException {
                    Member member = new Member(rs.getString("EMAIL"),
                            rs.getString("PASSWORD"),
                            rs.getString("NAME"),
                            rs.getTimestamp("REGDATE"));
                    member.setId(rs.getLong("ID"));
                    return member;
                }
            };
            //jdbc탬플레이트에 query 실행 
            List<Member> result = jdbcTemplate.query("select *from MEMBER where EMAIL =?", rm,email);
            //없으면 null 반환 있으면 리스트의  반환 
            return result.isEmpty() ? null : result.get(0);
        }
     
     
    }
     
    cs

    selectAll도 구현 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
        public List<Member> selectAll() {
            List<Member> results = jdbcTemplate.query("select * from MEMBER"
                    new RowMapper<Member>() {
     
                        @Override
                        public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
                            Member member= new Member(rs.getString("EMAIL"),
                                    rs.getString("PASSWORD"),
                                    rs.getString("NAME"),
                                    rs.getTimestamp("REGDATE"));
                            member.setId(rs.getLong("ID"));
                            return member;
                        }
                });
            return results;
        }
     
    cs

    결과가 1행인 경우 조회 메서드 : queryForObject()


    만약에 카운트 같은 쿼리는 정수 타입으로 바로 받는 게 편하다 

    1
    2
    3
    4
        public int count() {
            Integer count = jdbcTemplate.queryForObject("select count(*) from MEMBER", Integer.class);
            return count;
        }
    cs


    queryforObject의 주의점은 결과는 반드시 한 행

    그 이상이면 오류가 발생한다.

    정확히 1개가 아니라면 query 메서드를 사용해야한다.


    JDBCTemplate을 이용한 변경 쿼리 실행 


    INSERT, UPDATE, DELETE 쿼리를 실행할 때에는 다음의 update()메서드를 사용하면된다.

    - int update(String sql)
    - int update(String sql,Object...args)

    update 사용예

    1
    2
    3
    4
    public void update(Member member) {
            jdbcTemplate.update("update MEMBER set NAME = ?, PASSWORD = ? where EMAIL = ?",
                    member.getName(), member.getPassword(), member.getEmail());
        }
    cs



    PreparedStatementCreator를 이용한 쿼리 실행 


    지금 까지 코드는 쿼리에서 사용할 값을 인자로 전달해 주었다.

    1
    2
    3
    4
    public void update(Member member) {
            jdbcTemplate.update("update MEMBER set NAME = ?, PASSWORD = ? where EMAIL = ?",
                    member.getName(), member.getPassword(), member.getEmail());
        }
    cs


    경우에 따라 set 메서드를 사용해서 직접 인덱스 파라미터 값을 설정해 주어야 할 때가 있다.

    이런 경우에는 PreparedStatementCreator를 인자로 받는 메서드를 이용해서 직접 PreparedStatement를 생성하고 설정해 주어야한다.


    jdbc.Template,update(new PreparedStatementCreator(){

    @Override

    public PreparedStatement createPreparedStatement(Connection con)throws SQLException{

    //파라미터로 전달받은 Connection 을 이용해서 PreparedStatement를  생성

    PreparedStatement pstmt = con.preapeStatement("insert into MEMBER(EMAIL, PASSWORD, NAME, REGDATE)values (?,?,?,?)");

    // 인덱스 파라미터 값 설정

    pstmt.setString(1,member.getEmail());

    pstmt.setString(2,member.getPasswordl());

    pstmt.setString(3,member.getName());

    pstmt.setTimestamp(4,new Timestamp(member.getRegisterDate().getTime()));

    //생성한 pstmt 리턴

    return pstmt

    }

    });


    INSERT 쿼리 실행시 , KeyHolder를 이용해서 자동 생성 키 값을 구하기


    오토 인크리먼트같은 자동 증가 칼럼테이블에 값을 삽입할 경우 , 해당 칼럼의 값이 자동으로 생성된다.

    보통 INSERT 문에는 increment 하는 값을 넣지 않음
    쿼리 실행후 생성된 키값을 알고 싶다면 
    KeyHolder를 사용하면 된다.
    MemberDao insert()메서드를 구현 할 때 삽입되는 Member 객체의 ID 값을 구할수 있다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    KeyHolder keyHolder = new GeneratedKeyHolder();
            jdbcTemplate.update(new PreparedStatementCreator() {
                @Override
                public PreparedStatement createPreparedStatement(Connection con) 
                        throws SQLException {
                    PreparedStatement pstmt = con.prepareStatement(
                            "insert into MEMBER (EMAIL, PASSWORD, NAME, REGDATE) "+
                            "values (?, ?, ?, ?)",
                            new String[] {"ID"});
                    pstmt.setString(1,  member.getEmail());
                    pstmt.setString(2,  member.getPassword());
                    pstmt.setString(3,  member.getName());
                    pstmt.setTimestamp(4,  
                            new Timestamp(member.getRegisterDate().getTime()));
                    return pstmt;
                }
            }, keyHolder);
            Number keyValue = keyHolder.getKey();
            member.setId(keyValue.longValue());
    cs


     PreparedStatement pstmt = con.prepareStatement(
                            "insert into MEMBER (EMAIL, PASSWORD, NAME, REGDATE) "+
                            "values (?, ?, ?, ?)",
                            new String[] {"ID"});

    여기에서 두번째 파라미터가 자동증가 칼럼이므로 아이디를줌


    update()메서드 는 PreaparedStatement를 실행후 , 자동 생성된 키값을 KeyHolder에 보관한다.

    보관된 키는 getKey 메서드로 구할 수있다.

    Number로 받은후 원하는 타입으로 변경해서 사용한다.

    다음코드는 long타입으로 변환

     Number keyValue = keyHolder.getKey();
            member.setId(keyValue.longValue());


    05 MemberDAO 테스트

    메인 클래스 작성하자 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    package main;
     
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.List;
     
    import org.springframework.context.support.AbstractApplicationContext;
    import org.springframework.context.support.GenericXmlApplicationContext;
     
    import spring.Member;
    import spring.MemberDao;
     
    public class MainForMemberDao {
     
        private static MemberDao memberDao;
     
        public static void main(String[] args) {
            AbstractApplicationContext ctx = 
                    new GenericXmlApplicationContext("classpath:appCtx.xml");
     
            memberDao = ctx.getBean("memberDao", MemberDao.class);
     
            selectAll();
            updateMember();
            insertMember();
     
            ctx.close();
        }
     
        private static void selectAll() {
            System.out.println("----- selectAll");
            int total = memberDao.count();
            System.out.println("전체 데이터: " + total);
            List<Member> members = memberDao.selectAll();
            for (Member m : members) {
                System.out.println(m.getId() + ":" + m.getEmail() + ":" + m.getName());
            }
        }
     
        private static void updateMember() {
            System.out.println("----- updateMember");
            Member member = memberDao.selectByEmail("aaa@aaa.net");
            String oldPw = member.getPassword();
            String newPw = Double.toHexString(Math.random());
            member.changePassword(oldPw, newPw);
     
            memberDao.update(member);
            System.out.println("암호 변경: " + oldPw + " > " + newPw);
        }
     
        private static void insertMember() {
            System.out.println("----- insertMember");
            SimpleDateFormat dateFormat = new SimpleDateFormat("MMddHHmmss");
            String prefix = dateFormat.format(new Date());
            System.out.println("prefix :"+prefix);
            Member member = 
                    new Member(prefix + "@test.com", prefix, prefix, new Date());
            memberDao.insert(member);
            System.out.println(member.getId() + " 데이터 추가");
        }
     
    }
    cs

    트랜잭션 처리 

    두개이상의 쿼리를 한번의 작업에 서 실행해야할때 


    @Transaction을 이용한 트랜잭션 처리 

    트랜잭션범위를 지정 가능한 애노테이션
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    package spring;
     
    import org.springframework.transaction.annotation.Transactional;
     
    public class ChangePasswordService {
     
        private MemberDao memberDao;
     
        public ChangePasswordService(MemberDao memberDao) {
            this.memberDao = memberDao;
        }
     
        @Transactional
        public void changePassword(String email, String oldPwd, String newPwd) {
            Member member = memberDao.selectByEmail(email);
            if (member == null)
                throw new MemberNotFoundException();
            
            member.changePassword(oldPwd, newPwd);
            
            memberDao.update(member);
        }
    }
     
    cs

    chagePassword() 메서드에서 실행되는 코드를 하나의 트랜잭션 범위에서 실행한다.
    따라서, memberDao,selectByEmail()에서 실행하는 쿼리와 
    member.changePassword() 에서 실행하는 쿼리가 한트랜잭션에서 묶여서 실행된다.

    @Transactional 애노테이션이 제대로 동작하려면 다음의 두가지 내용을 스프링 설정에 추가해야한다.
    1. PlatformTransactionManager 빈 설정
    2. @Transactional 애노테이션 활성화 설정 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <?xml version="1.0" encoding="UTF-8"?>
     
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd">
     
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
            destroy-method="close">
            <property name="driverClass" value="com.mysql.jdbc.Driver" />
            <property name="jdbcUrl" value="jdbc:mysql://localhost/spring4fs?characterEncoding=utf8" />
            <property name="user" value="spring4" />
            <property name="password" value="spring4" />
        </bean>
        
        <bean id = "transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        
        <tx:annotation-driven transaction-manager="transactionManager"/>
        
        <bean id= "memberDao" class="spring.MemberDao">
            <constructor-arg ref="dataSource"/>
        </bean>
     
    </beans>
    cs


    PlatformTransactionManager는 스프링이 제공하는 트랜잭션 관리자를 위한 인터페이스이다.
    스프링으 구현 기술에 상관없이 동일한 방식으로 트랜잭션을 처리하기 위해  이 인터페이스를 사용함

    JDBC 연동을 사용하는 경우 DataSourceTracsactionManager클래스를  


    PlatformTransactionManager로 사용한 경우다.

    위설정은 dataSource를 프로퍼티의 값으로 이용해서 트래잭션 연동에 사용할 DataSource를 지정한다.


    <tx:annotation-driven> 태그는 @Transactional  애노태이션을 실행하는 기능을 활성화 .

    transaction-manager 속성을 사용해서 트랜잭션을 수행할때 사용할 PlatformTransactionManager  빈을 지정한다.

    앞서는 transactionManger 빈을 설정 했다.


    트랜잭션 처리를 위한 설정을 완료하면 , 트랜잭션 범위에서 실행하고 싶은 스프링 빈 객체의 메서두애 @Transactional 애노테이션을 붙이면 된다.


    chagePwdSvc를 실행할 메인클래스를 작성

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package main;
     
    import org.springframework.context.support.AbstractApplicationContext;
    import org.springframework.context.support.GenericXmlApplicationContext;
     
    import spring.ChangePasswordService;
    import spring.IdPasswordNotMatchingException;
    import spring.MemberNotFoundException;
     
    public class MainForCPS {
     
        public static void main(String[] args) {
            AbstractApplicationContext ctx =
                    new GenericXmlApplicationContext("classpath:appCtx.xml");
     
            ChangePasswordService cps = 
                    ctx.getBean("changePwdSvc", ChangePasswordService.class);
            try {
                cps.changePassword("aaa@aaa.net""1234""1111");
                System.out.println("암호를 변경했습니다.");
            } catch (MemberNotFoundException e) {
                System.out.println("회원 데이터가 존재하지 않습니다.");
            } catch (IdPasswordNotMatchingException e) {
                System.out.println("암호가 올바르지 않습니다.");
            }
     
            ctx.close();
        }
     
    }
     
    cs

    Log를 보기 위해 Log4j를 사용해 보자 

    pom.xml에 log4j.xml추가

    1
    2
    3
    4
    5
        <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
    cs

    메이븐 업데이트 후 

    로그를 어떤형식으로 어디에 기록할지 에 대한 설정 파일로 부터 읽어온다.

    src/main/resources 

    log4j.xml 에 다음과 같이 설정 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <?xml version="1.0" encoding="UTF-8"?>
     
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
     
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
        <appender name="console" class="org.apache.log4j.ConsoleAppender">
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" 
                    value="[%t] [%d{yyyy-MM-dd HH:mm:ss}] %-5p %c:%M - %m%n" />
            </layout>
        </appender>
     
        <root>
            <priority value="INFO" />
            <appender-ref ref="console" />
        </root>
     
        <logger name="org.springframework.jdbc">
            <level value="DEBUG" />
        </logger>
    </log4j:configuration>
    cs

    로그의 디버그 레벨을 보기위한 설정


    메인을 실행했더니

    <bean id="changePwdSvc" class="spring.ChangePasswordService">

    <constructor-arg ref="memberDao"/>

    </bean>

    빈등록을 안했었음


    아까 비번이 랜덤으로 바뀌어있을 것이므로

    비민번호를 "1234"로 변경후

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    log4j:WARN Continuable parsing error 21 and column 23
    log4j:WARN 요소 유형 "log4j:configuration"의 콘텐츠는 "(renderer*,throwableRenderer?,appender*,plugin*,(category|logger)*,root?,(categoryFactory|loggerFactory)?)"과(와) 일치해야 합니다.
    [main] [2019-03-26 03:10:06] INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader:loadBeanDefinitions - Loading XML bean definitions from class path resource [appCtx.xml]
    [main] [2019-03-26 03:10:06] INFO  org.springframework.context.support.GenericXmlApplicationContext:prepareRefresh - Refreshing org.springframework.context.support.GenericXmlApplicationContext@1376c05c: startup date [Tue Mar 26 03:10:06 KST 2019]; root of context hierarchy
    [main] [2019-03-26 03:10:06] INFO  com.mchange.v2.log.MLog:<clinit> - MLog clients using log4j logging.
    [main] [2019-03-26 03:10:07] INFO  com.mchange.v2.c3p0.C3P0Registry:banner - Initializing c3p0-0.9.2.1 [built 20-March-2013 10:47:27 +0000; debug? true; trace: 10]
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager:getTransaction - Creating new transaction with name [spring.ChangePasswordService.changePassword]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
    [main] [2019-03-26 03:10:07] INFO  com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource:getPoolManager - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hge4n6a11eiedp6vm1k2z|462d5aee, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hge4n6a11eiedp6vm1k2z|462d5aee, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost/spring4fs?characterEncoding=utf8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager:doBegin - Acquired Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@6ae5aa72] for JDBC transaction
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager:doBegin - Switching JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@6ae5aa72] to manual commit
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.core.JdbcTemplate:query - Executing prepared SQL query
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.core.JdbcTemplate:execute - Executing prepared SQL statement [select *from MEMBER where EMAIL =?]
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.core.JdbcTemplate:update - Executing prepared SQL update
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.core.JdbcTemplate:execute - Executing prepared SQL statement [update MEMBER set NAME = ?, PASSWORD = ? where EMAIL = ?]
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.core.JdbcTemplate:doInPreparedStatement - SQL update affected 1 rows
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager:processCommit - Initiating transaction commit
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager:doCommit - Committing JDBC transaction on Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@6ae5aa72]
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager:doCleanupAfterCompletion - Releasing JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@6ae5aa72] after transaction
    [main] [2019-03-26 03:10:07] DEBUG org.springframework.jdbc.datasource.DataSourceUtils:doReleaseConnection - Returning JDBC Connection to DataSource
    암호를 변경했습니다.
    [main] [2019-03-26 03:10:07] INFO  org.springframework.context.support.GenericXmlApplicationContext:doClose - Closing org.springframework.context.support.GenericXmlApplicationContext@1376c05c: startup date [Tue Mar 26 03:10:06 KST 2019]; root of context hierarchy
     
    cs

    진행하면 된다. 


    'Spring_FrameWork' 카테고리의 다른 글

    스프링 부트에서 JPA 데이터베이스 사용하기  (0) 2020.06.06
    AOP소개  (0) 2019.03.19
    빈 라이프사이클과 범위  (0) 2019.03.19
    DI정리  (0) 2019.03.18
    의존 자동 주입  (0) 2019.03.15
Designed by Tistory.