-
MyBatis, DBCP(DataBase Connection Pool)-0627(2)웹프로그래밍 2022. 6. 28. 18:57728x90
오전에는 view단을 건들였으니 오후에는 back단을 건들여보자
<예시>
P.L : MemberDAO
B.L.L: MemberService
C.L : MemberInsertServlet
어플리케이션의 Performance체크 ->connection pool 사용하자
mybatis 사용해보자
웹어플리케이션에는 memory관리중요
VM ) 1. 가비지컬렉터 2. 가비지컬렉터 안되는부분 (int, long,String 기본형데이터 값이 직접 들어가는것들)
String계속 쓰면 점유만 되고 삭제는 안됨
String buffer : 똑같은 문자열 관리하지만 할당되는 힙 영역인 그 영역 회수 가능(가비지 컬렉터가능)
공간적 요소(memory 소요량)
String str ="ad"; str += "dc";ab dc abdc 이렇게 3개의공간잡힘
그나마 해결방법 : String.format("$s dc","ab")
Stringbuffer sb = new StringBuffer("ab"); sb.append("dc");객체참조형으로 할당을 했죠 객체의 메소드르 통해서 상태변경가능
처음에 ab였어 추가하면 abdc됨 여기서는 메모리공간 하나 할당해놓고변경가능 그리고 필요없음 사라지기까지가능!!
시간적 요소(소요시간) : latency time + processing time

가장소요시간 짧은 : 5번 cpu에 의해서 일어나기에 성능만 좋다면
1.5 3.4 공통점: 네트워크 타야함
1.5 : 네트워크 품질에 따라
3.4: 네트워크 품질에 따라
하지만 네크워크 다름 3.4 : 데이터베이스와미들티어에서 발생하는구간 개발자는 1번 제어할 수없어 고객마다 다르니
그래서 우리가 1.5 어떻게 할 수가없어

네트워크 타는구간 : latency
누가더 지배적으로 시간을 잡아먹는가?
1: 9 야 latemcy가 다 잡아먹고있으니 얘를 튜닝해서 9라는 숫자를 줄이자
만약 반대라면? 우리 로직을 어떻게 바꾸면 processing 여기서 줄일 수있을까를 찾아야함
한번의 처리와 한번의 연결지연
<oneConnOenProcess.jsp>
<%@page import="java.sql.ResultSet"%> <%@page import="java.sql.Statement"%> <%@page import="kr.or.ddit.db.ConnectionFactory"%> <%@page import="java.sql.Connection"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> 데이터베이스로부터 a001을 조회하고, 한번 브라우저에 출력. <% long start = System.currentTimeMillis(); String sql = "SELECT * FROM MEMBER WHERE MEM_ID = 'a001'"; try( Connection conn = ConnectionFactory.getConnection(); Statement stmt = conn.createStatement(); ){ ResultSet rs = stmt.executeQuery(sql); if(rs.next()){ out.println(rs.getString("MEM_NAME")); } } long end = System.currentTimeMillis(); %> 소요시간 : <%=end-start %>ms </body> </html>
<100Conn100Process.jsp>
<%@page import="java.sql.ResultSet"%> <%@page import="java.sql.Statement"%> <%@page import="kr.or.ddit.db.ConnectionFactory"%> <%@page import="java.sql.Connection"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> 데이터베이스로부터 a001을 조회하고, 한번 브라우저에 출력. <% long start = System.currentTimeMillis(); String sql = "SELECT * FROM MEMBER WHERE MEM_ID = 'a001'"; for(int i=1; i<=100; i++){ try( Connection conn = ConnectionFactory.getConnection(); Statement stmt = conn.createStatement(); ){ ResultSet rs = stmt.executeQuery(sql); if(rs.next()){ out.println(rs.getString("MEM_NAME")); } } } long end = System.currentTimeMillis(); %> 소요시간 : <%=end-start %>ms </body> </html>

리스너가 현재 연결을 거부했다...-> express버전 동시에연결할 수 있는게 20.30개 밖에 없음
현재 데이터베이스 감당할 수 있는 커넥션 개수 넘겨버림
SELECT * FROM V$RESOURCE_LIMIT;통로(DB) , 시간의의미 (웹), 디비에서 세션은 커넥션을의미

close하지 못한 커넥션들이 존재하면서 커넥션 또 만드려고 하니 에러가 발생한것이다.
--정보조회하기 SELECT * FROM V$RESOURCE_LIMIT; --변경하기 alter system set sessions=200 scope=spfile; alter system set processes=200 scope=spfile;그 다음에는 restart를 해야함
LAI 접속 끊기 , cmd(관리자창) , lsnrctl status,lsnrctl stop, stopdb, startdb,lsnrctl status

lsnrctl status 

<oneConn100Process.jsp>
<%@page import="java.sql.ResultSet"%> <%@page import="java.sql.Statement"%> <%@page import="kr.or.ddit.db.ConnectionFactory"%> <%@page import="java.sql.Connection"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> 데이터베이스로부터 a001을 조회하고, 한번 브라우저에 출력. <% long start = System.currentTimeMillis(); String sql = "SELECT * FROM MEMBER WHERE MEM_ID = 'a001'"; try( Connection conn = ConnectionFactory.getConnection(); Statement stmt = conn.createStatement(); ){ ResultSet rs = stmt.executeQuery(sql); if(rs.next()){ for(int i=1; i<=100; i++){ out.println(rs.getString("MEM_NAME")); } } } long end = System.currentTimeMillis(); %> 소요시간 : <%=end-start %>ms </body> </html>
연결 수립 하는데서 많이 잡아먹음
<100ConnOenProcess.jsp>
<%@page import="java.sql.ResultSet"%> <%@page import="java.sql.Statement"%> <%@page import="kr.or.ddit.db.ConnectionFactory"%> <%@page import="java.sql.Connection"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> 데이터베이스로부터 a001을 조회하고, 한번 브라우저에 출력. <% long start = System.currentTimeMillis(); String sql = "SELECT * FROM MEMBER WHERE MEM_ID = 'a001'"; String memName = null; for(int i=1; i<=100; i++){ try( Connection conn = ConnectionFactory.getConnection(); Statement stmt = conn.createStatement(); ){ ResultSet rs = stmt.executeQuery(sql); if(rs.next()&&memName==null){ memName = rs.getString("MEM_NAME"); } } } out.println(memName); long end = System.currentTimeMillis(); %> 소요시간 : <%=end-start %>ms </body> </html>연결은 100번 출력은 한번, 새로고침 여러번하면 꺼짐 .. -> 서버가 감당할 수 없을만큼 커넥션이 생성되고 있음

서버시간줄이려면
커넥션의 생성을 관리 , 커넥션 수립시간 줄이기
여기서 connection pool 사용
툴 ,커넥션만들기, 툴 커넥션 넣어주기, 서비스할 수 있는 스레드 필요
--추가 공부
1. DB 접속을 위한 JDBC 드라이버 로드
2. getConnection Method로 부터 DB 커넥션 객체를 얻음
3. 쿼리 수행을 위한 PreparedStatement 객체 생성
4. excuteQuery를 실행해서 결과를 받아옴.
여기서 비효율적인 부분은 1번과 2번 입니다.
DB 연결 시 마다 Driver를 로드하고 커넥션 객체를 얻는 작업을 반복하죠.
이 부분을 효율적으로 처리하도록 바꾸는 것이 DBCP의 역할 입니다.
DBCP를 사용하게 되면,
WAS 실행 시 미리 일정량의 DB Connection 객체를 생성하고 Pool 이라는 공간에 저장해 둡니다.
사용자의 요청이 발생하면 Connection을 제공하고 사용자와의 연결이 종료된다면 Pool에 다시 반환하여 보관하는 것을 의미합니다.
그리고 DB 연결 요청이 있으면, 이 Pool 이라는 공간에서 Connection 객체를 가져다 쓰고 반환 하게 됩니다.

출처: https://aljjabaegi.tistory.com/402 [알짜배기 프로그래머:티스토리]
https://www.apache.org/ -> commons -> DBCP접속 ->


commons-dbcp2 아티팩트는 commons-pool2 아티팩트의 코드에 의존하여 기본 개체 풀 메커니즘을 제공합니다.옆에 example 들어가서


=> 우리가 db연결할때와 비슷!!
Maven Repository: Search/Browse/Explore
extras-cats Last Release on Jun 26, 2022
mvnrepository.com



자바sql패키지 : 리모콘 같은 역할


얘로 사용할 수 있다,
DriverManager 사용하려면 계속 선언해줬지만 private static DataSource ds;사용하면
내가로딩하는게아니라 데이터베이스 구현체가 따로 로딩해줌
<ConnectionFactory>
package kr.or.ddit.db; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSource; /** * Factory method[Object] pattern * : 하나의 객체에 대한 생성을 또다른 객체가 전담하는 구조. * */ public class ConnectionFactory { private static String url; private static String user; private static String password; private static DataSource ds; static { String dbInfoPath = "kr/or/ddit/db/dbInfo.properties"; try( InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(dbInfoPath); ){ Properties dbInfo = new Properties(); dbInfo.load(is); url = dbInfo.getProperty("url"); user = dbInfo.getProperty("user"); password = dbInfo.getProperty("password"); BasicDataSource bds = new BasicDataSource(); bds.setDriverClassName(dbInfo.getProperty("driverClassName")); bds.setUrl(url); bds.setUsername(user); bds.setPassword(password); int initialSize = Integer.parseInt(dbInfo.getProperty("initialSize")); //initialSize:최초 커넥션을 맺을 때 Connection Pool에 생성되는 커넥션의 갯수 //BasicDataSource 클래스 생성 후 최초로 getConnection() 메서드를 호출할 때 커넥션 풀에 채워 넣을 커넥션 개수 long maxWait = Long.parseLong(dbInfo.getProperty("maxWait")); //maxWait :Pool이 예외를 throw하기 전 연결이 반환될 때까지(사용 가능한 Connection 객체가 없는경우) 대기하는 최대 시간(ms) 또는 무한 대기(-1) int maxTotal = Integer.parseInt(dbInfo.getProperty("maxTotal")); // maxTotal 동시에 사용할 수 있는 최대 커넥션의 갯수 bds.setInitialSize(initialSize); bds.setMaxWaitMillis(maxWait); bds.setMaxTotal(maxTotal); ds = bds; // Class.forName(dbInfo.getProperty("driverClassName")); } catch (Exception e) { throw new RuntimeException(e); } } public static Connection getConnection() throws SQLException { // Connection conn = DriverManager.getConnection(url, user, password); Connection conn = ds.getConnection(); return conn; } }새로고침 빨리 해도 서버 안터짐

선생님 결과 dbs.setInitialSize(5);
5개 반납하면 다시 또 가능 일정개수미만으로만 커넥션 운영하게됨
최대 2초가 되도 반납이안된다면 토탈 10개까지 운영할 수 있대 다시하나만들어 6개만들어
또 2초 지났는데 반납안돼 토탈은 10개 4개정도 여유있어 .. 그러다가 마감 11번째 손님은 sqlexception발생
dbs.setMaxTotal(10);
어떤경우에도 커넥션 10개 넘을 수 없다.

=> 수정은 여기에서 할 수 있다.
한번의 처리와 한번의 연결지연

백번의 처리와 백번의 연결지연

백번의 처리와 한번의 연결지연:

한번의 처리와 백번의 연결지연

=> 시간이 확실히 짧아진것을확인할 수 있다.
MyBatis
https://mybatis.org/mybatis-3/ko/index.html
=> 마이마티스에 관한 정보 확인할 수 있다.

iBATIS 1. sqlmapper
2. 데이터변환역할을 한다해서 datamapper

ibatis와 차이점 mapper가 따로 존재함
sqlmapper,datamapper
SQL Mapper는 작성한 SQL 구문으로 RDB에 직접 질의하여 그 결과 값을 객체에 매핑 시켜준다.
SQL 변수 종류
리터럴 변수 란?
sql 구문 중 where절에 column과 비교되는 값이 상수값으로 직접 선언된 경우의 변수
예) SELECT * FROM TABLE01 WHERE COL01 = "TEST";
바인드 변수 란?
sql 구문 중 where절에 column과 비교되는 값이 바인드 변수 형태로 사용하는 경우의 변수
바인드 변수의 자리에는 parameter로 넘겨지는 값들이 대체됨.
예) SELECT * FROM TABLE01 WHERE COL01 :=1;
transactionManager 이제 신경써줘야하니까 기억잘하기클래스패스리소스로 관리

차이 : 컴파일안됨
공통점 :클래스패쓰 리소스



쿼리만들때만 사용 일단 그냥 xml만들어준다

이름은 예시 

dtd설정파일때문에 코더~되는것임


=> 여기참고하면된다.
${ } : 프로펄티의 플레이스홀더

poolMaximumActiveConnections 5
poolMaximumIdleConnections 3
처음에 놀아도되는 3개만운영
poolTimeToWait 이시간만큼 기다려도 안와 그러면 2개만들 수 있어
<Configuration 다시> 뒤에 공백 주의
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration> <!-- 연결정보 따로 생성 후 불러오기 --> <properties resource="kr/or/ddit/db/dbInfo.properties"/> <!-- 마이바티스 설정과 관련된 기본 세팅 선언 --> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <!-- type에 적힌걸 Member라고 부를래! (별칭 설정) --> <typeAliases> <package name="kr.or.ddit.vo"/> </typeAliases> <!-- environments : DB에 연결할 설정에 대한 정보 선언 --> <environments default="dev"> <!-- default : 연결 설정을 여러 개 생성하여 아이디로 구분하고 기본으로 연결할 설정 정보를 설정하는 속성 --> <!-- Database연결할 설정 정보 선언 => environment에 대한 이름을 dev라고 부를게! --> <environment id="dev"> <!-- 트랜잭션을 제어를 누가 할 것인가에 대한 설정 --> <!-- JDBC : JDBC가 커밋/롤백을 직접 처리하기 위해 사용(수동 commit) MANAGED : 트랜잭션에 대해 직접적인 영향을 행사하지 않는 것 의미(자동 commit) --> <transactionManager type="JDBC"/> <!-- 실제 DB접속에 관한 정보를 넣는 태그 --> <!-- type : ConnectionPool을 사용할건지에 대한 여부 UNPOOLED POOLED JNDI --> <dataSource type="POOLED"> <property name="driver" value="${driverClassName}"/> <property name="url" value="${url}"/> <property name="username" value="${user}"/> <property name="password" value="${password}"/> <property name="poolMaximumActiveConnections" value="${maxTotal}"/> <property name="poolMaximumIdleConnections" value="${initialSize}"/> <property name="poolTimeToWait" value="${maxWait}"/> </dataSource> </environment> </environments> <!-- DB에 사용되는 쿼리문들을 담은 mapper파일을 등록하는 부분 --> <mappers> <mapper resource="kr/or/ddit/mybatis/mappers/Member.xml"/> </mappers> </configuration>mappers
이제 우리는 매핑된 SQL 구문을 정의할 시간이다. 하지만 먼저 설정을 어디에 둘지 결정해야 한다. 자바는 자동으로 리소스를 찾기 위한 좋은 방법을 제공하지 않는다. 그래서 가장 좋은 건 어디서 찾으라고 지정하는 것이다



mapperproxy언어 기억해두기
SqlSession sqlSession = sqlSessionFactory.openSession(); => 커넥션과 같은역할
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>vo의 글자맞춰주기위해서 ..
데이터베이스 컬럼명 형태가 VACC_NO 일 경우 CamelCase형태를 적용시키면 vaccNo로 자동 매핑된다.
VO사용시 해당 변수명에 맞게 매핑이 된다.
<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="kr.or.ddit.member.dao.MemberDAO"> <select id="selectMemberForAuth" parameterType="MemberVO" resultType="MemberVO"> SELECT MEM_ID, MEM_PASS, MEM_NAME, MEM_HP, MEM_ADD1 FROM MEMBER WHERE MEM_ID = #{memId} </select> </mapper>Junit Test해보자


insert제외하고 mybatis로 고쳐보자~

-select id="selectMemberForAuth" 메소드이름따라감 즉 인터페이스에 선언했던것들이 들어올 수 있는것이다!!!!
=> dao의 시그니쳐 따라감
-SqlSessionFactory :session을 가지고 있는 공장같은것 session은 connection역할을 하는것이다.
전체에서 레코드 하나를 바인딩하기위한 구조 여러건이든 한건이든 resultType동일하게 MemberVO
<MemberDAoImpl>
package kr.or.ddit.member.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import kr.or.ddit.db.ConnectionFactory; import kr.or.ddit.mybatis.CustomSqlSessionFactoryBuilder; import kr.or.ddit.vo.MemberVO; public class MemberDAOImpl implements MemberDAO { private SqlSessionFactory sqlSessionFactory = CustomSqlSessionFactoryBuilder.getSqlSessionFactory(); @Override public MemberVO selectMemberForAuth(MemberVO inputData) { try( SqlSession sqlSession = sqlSessionFactory.openSession(); ){ // return sqlSession.selectOne("kr.or.ddit.member.dao.MemberDAO.selectMemberForAuth", inputData); MemberDAO mapperProxy = sqlSession.getMapper(MemberDAO.class); return mapperProxy.selectMemberForAuth(inputData); } } @Override public List<MemberVO> selectMemberList() { try( SqlSession sqlSession = sqlSessionFactory.openSession(); ){ // return sqlSession.selectList("kr.or.ddit.member.dao.MemberDAO.selectMemberList"); MemberDAO mapper = sqlSession.getMapper(MemberDAO.class); return mapper.selectMemberList(); } } @Override public MemberVO selectMember(String memId) { try( SqlSession sqlSession = sqlSessionFactory.openSession(); ){ return sqlSession.selectOne("kr.or.ddit.member.dao.MemberDAO.selectMember", memId); } } @Override public int insertMember(MemberVO member) { StringBuffer sql = new StringBuffer(); sql.append(" INSERT INTO MEMBER ( "); sql.append(" MEM_ID, MEM_PASS, MEM_NAME, "); sql.append(" MEM_REGNO1, MEM_REGNO2, MEM_BIR, "); sql.append(" MEM_ZIP, MEM_ADD1, MEM_ADD2, "); sql.append(" MEM_HOMETEL, MEM_COMTEL, MEM_HP, "); sql.append(" MEM_MAIL, MEM_JOB, MEM_LIKE, "); sql.append(" MEM_MEMORIAL, MEM_MEMORIALDAY, MEM_MILEAGE "); sql.append(" ) VALUES ( "); sql.append(" ?, ?, ?, "); sql.append(" ?, ?, TO_DATE(?, 'YYYY-MM-DD'), "); sql.append(" ?, ?, ?, "); sql.append(" ?, ?, ?, "); sql.append(" ?, ?, ?, "); sql.append(" ?, TO_DATE(?, 'YYYY-MM-DD'), 1000 "); sql.append(" ) "); try (Connection conn = ConnectionFactory.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql.toString());) { int idx = 1; stmt.setString(idx++,member.getMemId()); stmt.setString(idx++,member.getMemPass()); stmt.setString(idx++,member.getMemName()); stmt.setString(idx++,member.getMemRegno1()); stmt.setString(idx++,member.getMemRegno2()); stmt.setString(idx++,member.getMemBir()); stmt.setString(idx++,member.getMemZip()); stmt.setString(idx++,member.getMemAdd1()); stmt.setString(idx++,member.getMemAdd2()); stmt.setString(idx++,member.getMemHometel()); stmt.setString(idx++,member.getMemComtel()); stmt.setString(idx++,member.getMemHp()); stmt.setString(idx++,member.getMemMail()); stmt.setString(idx++,member.getMemJob()); stmt.setString(idx++,member.getMemLike()); stmt.setString(idx++,member.getMemMemorial()); stmt.setString(idx++,member.getMemMemorialday()); return stmt.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(e); } } }<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="kr.or.ddit.member.dao.MemberDAO"> <select id="selectMemberForAuth" parameterType="MemberVO" resultType="MemberVO"> SELECT MEM_ID, MEM_PASS, MEM_NAME, MEM_HP, MEM_ADD1 FROM MEMBER WHERE MEM_ID = #{memId} </select> <select id="selectMemberList" resultType="MemberVO"> SELECT MEM_ID, MEM_NAME, MEM_HP , MEM_ADD1, MEM_MAIL, MEM_MILEAGE FROM MEMBER </select> <select id="selectMember" parameterType="string" resultType="MemberVO"> SELECT MEM_ID, MEM_PASS, MEM_NAME, MEM_REGNO1, MEM_REGNO2, TO_CHAR(MEM_BIR, 'YYYY-MM-DD') MEM_BIR, MEM_ZIP, MEM_ADD1, MEM_ADD2, MEM_HOMETEL, MEM_COMTEL, MEM_HP, MEM_MAIL, MEM_JOB, MEM_LIKE, MEM_MEMORIAL, TO_CHAR(MEM_MEMORIALDAY, 'YYYY-MM-DD') MEM_MEMORIALDAY, MEM_MILEAGE, MEM_DELETE FROM MEMBER WHERE MEM_ID = #{memId} </select> </mapper>@Override public MemberVO selectMemberForAuth(MemberVO inputData) { try( SqlSession sqlSession = sqlSessionFactory.openSession(); ){ return sqlSession.selectOne("kr.or.ddit.member.dao.MemberDAO.selectMemberForAuth",inputData); } }"kr.or.ddit.member.dao.MemberDAO.selectMemberForAuth" 에러날 수도있잖아 -> 오타방지 mapperProxy 사용하자
진짜 객체가아니고 가짜 대리!! 진짜 구현체가 아니라 구현체역할을 대리하고있는 MemberDAO들어오는것임
그래서 이렇게 하면 사용할 수 있다.

인터페이스 없는 상태라면 프록시 구조를 사용할 수 없다.
수정
MemberDAO mapperProxy =sqlSession.getMapper(MemberDAO.class); return mapperProxy.selectMemberForAuth(inputData);=> 너무 많은 proxy사용 만들고 버리고 반복 => 단점이 존재해! proxy를 만들어놓고 싱글톤으로 활용하면 좋을것이다.
<Junit 테스트 하기>
package kr.or.ddit.member.dao; import static org.junit.Assert.*; import java.sql.SQLException; import java.util.List; import org.junit.Test; import kr.or.ddit.vo.MemberVO; public class MemberDAOTest { MemberDAO dao = new MemberDAOImpl(); @Test public void testSelectMemberForAuth() { MemberVO inputData = new MemberVO(); inputData.setMemId("a001"); MemberVO member = dao.selectMemberForAuth(inputData); System.out.println(member); assertNotNull(member); } @Test(expected=RuntimeException.class) public void testInsertMemberThrow() { MemberVO member = new MemberVO(); dao.insertMember(member); } @Test public void testInsertMember() { MemberVO member = new MemberVO(); member.setMemId("a002"); member.setMemPass("java"); member.setMemName("신규"); member.setMemBir("1999-01-01"); member.setMemZip("000-000"); member.setMemAdd1("대전"); member.setMemAdd2("오류"); member.setMemHp("000-000-0000"); member.setMemMail("aa@gmail.net"); int rowcnt = dao.insertMember(member); assertEquals(1, rowcnt); } @Test public void testSelectMemberList() { List<MemberVO> memberList = dao.selectMemberList(); assertNotNull(memberList); assertNotEquals(0, memberList.size()); } @Test public void testSelectMember() { assertNotNull(dao.selectMember("a001")); } }
=> 이름에다가 컨트롤 11하면 얘만 실행할 수 있어
<과제>
ConnectionFactory 소스 카피 웹스터디02 db에 커넥션팩토리에 방금 카피한거 넣고 save하고 dbcp2 없으니까
pom.xml열고 dbcp2 카피해서 웹스터디02 pop.xml에 가져다 놓고 webstudy 02는 클로즈
03에 있는 db라는 자체를 지우세요
에러나는 두곳
MemberDaoImpl에러는 냅둬
employee props 에서 에러 공통점 다오패키지 마이바티스 쓸 수 있는 구조 로 바꿔라
config

추가 
여기 두곳 에러잡기

추가!

=> kr.or.ddit.props.dao.DataBasePropertyDAO 이렇게 잘 나옴
<EmployeeDAOimpl.java>
package kr.or.ddit.employee.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import kr.or.ddit.mybatis.CustomSqlSessionFactoryBuilder; import kr.or.ddit.vo.EmployeeVO; public class EmployeeDAOImpl implements EmployeeDAO { private SqlSessionFactory sqlSessionFactory = CustomSqlSessionFactoryBuilder.getSqlSessionFactory(); @Override public List<EmployeeVO> selectEmployeeList(Integer managerId) { try ( SqlSession sqlSession =sqlSessionFactory.openSession(); ) { EmployeeDAO empList =sqlSession.getMapper(EmployeeDAO.class); return empList.selectEmployeeList(managerId); } } }<Employee.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="kr.or.ddit.employee.dao.EmployeeDAO"> <select id="selectEmployeeList" parameterType="Integer" resultType="EmployeeVO"> SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, TO_CHAR(HIRE_DATE, 'YYYY-MM-DD') HIRE_DATE, JOB_ID, SALARY, COMMISSION_PCT, MANAGER_ID, DEPARTMENT_ID, EMP_NAME, RETIRE_DATE , ( SELECT COUNT(EMPLOYEE_ID) FROM HR.EMPLOYEES B WHERE A.EMPLOYEE_ID = B.MANAGER_ID ) CHILDCOUNT FROM HR.EMPLOYEES A <if test="managerId==null"> WHERE MANAGER_ID IS NULL </if> <if test="managerId!=null"> WHERE MANAGER_ID = #{managerId} </if> </select> </mapper><쌤>
<?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="kr.or.ddit.employee.dao.EmployeeDAO"> <select id="selectEmployeeList" parameterType="int" resultType="EmployeeVO"> SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, TO_CHAR(HIRE_DATE, 'YYYY-MM-DD') HIRE_DATE, JOB_ID, SALARY, COMMISSION_PCT, MANAGER_ID, DEPARTMENT_ID, EMP_NAME, RETIRE_DATE , ( SELECT COUNT(EMPLOYEE_ID) FROM HR.EMPLOYEES B WHERE A.EMPLOYEE_ID = B.MANAGER_ID ) CHILDCOUNT FROM HR.EMPLOYEES A WHERE MANAGER_ID IS NULL WHERE MANAGER_ID = #{managerId} <!-- if(managerId==null) --> <!-- sql.append(" WHERE MANAGER_ID IS NULL "); --> <!-- else --> <!-- sql.append(" WHERE MANAGER_ID = ? "); --> </select> </mapper><DataBasePropertyDAOImpl>
package kr.or.ddit.props.dao; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import kr.or.ddit.mybatis.CustomSqlSessionFactoryBuilder; import kr.or.ddit.vo.DataBasePropertyVO; public class DataBasePropertyDAOImpl implements DataBasePropertyDAO { private SqlSessionFactory sqlSesstionFactory = CustomSqlSessionFactoryBuilder.getSqlSessionFactory(); @Override public List<DataBasePropertyVO> selectDataBaseProperties() { try( SqlSession sqlSession = sqlSesstionFactory.openSession(); ){ DataBasePropertyDAO mapperProxy = sqlSession.getMapper(DataBasePropertyDAO.class); return mapperProxy.selectDataBaseProperties(); } } }<DBProps.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="kr.or.ddit.props.dao.DataBasePropertyDAO"> <select id="selectDataBaseProperties" resultType="DataBasePropertyVO"> SELECT PROPERTY_NAME, PROPERTY_VALUE, DESCRIPTION FROM DATABASE_PROPERTIES </select> </mapper>728x90'웹프로그래밍' 카테고리의 다른 글
회원탈퇴, Builder pattern,Reflection-22.06.29 (0) 2022.06.29 myBatis(2),Lombok-22.06.28 (0) 2022.06.28 view에대한 공부, modal -0627 (0) 2022.06.28 번외 ) grid적용하는 예제 이해하기 (0) 2022.06.27 tiles를 적용한 후 에러잡기 (0) 2022.06.25