책 `코드로배우는 웹프로젝트`를 학습 중에 insert처리 방법에 대해 학습 중인데 책은 오라클을 이용한 코드로 나와있었지만 현재 MYSQL을 좀 더 학습하고 싶어 오라클을 사용하지 않았다. 그러다 보니 쿼리를 사용할때 막히는 부분이 생기는데 오히려 공부가 더 되고 좋았다.(찾아 봐야 할 것들도 더 늘어나고 있다..)
insert문에서 key값을 미리 받는 방법(order="BEFORE")을 찾아봤지만 잘 해결되지 않았다.
그러다 내린 결론.
oracle은 Sequence는 여러테이블에서 사용 될 수 있는 별도의 객체로 DB에 저장된다. 그래서 Sequence객체에서 key 를 가져 올 수 있는 것같다.
MYSQL은 컬럼의 열 속성에 AUTO_INCREMENT 값을 추가한 것으로, 데이터베이스 테이블에 속하고, 해당 테이블에서만 사용가능 하다. 그래서 select last_insert_id()를 사용하면 가장 마지막에 저장된 key를 가져오는데 SQL이 실행되기 전에 키를 먼저 가져 올 수 없다. 그래서 insert문 안에서 after는 되고 before는 0이 되는 것 같다.
insert문이 실행 되기 전 bno 값을 조회하고 싶으면 oracle을 이용해야겠다..... 🤣
mabatis의 mapper 파일을 이용하여 데이터베이스에서 값을 받아오는 예제를 학습 중에 SQL구문의 작성방법을 몰라 삽질을 많이 했다.
아래의 두가지를 학습을 하니 좀 더 이해가 잘 되었다.
- sql map 파일에 SQL구문의 엘리먼트와 속성
- PK값을 자동 생성해주는 SQL문에서 방법과 가져오는 방법
SQL map파일의 엘리먼트와 속성
MyBatis는 내부적으로 JDBC드라이버를 사용하여 데이터베이스와의 연결을 관리한다.
- JDBC 기본 데이터형식을 사용하여 SQL Server 데이터형식과 Java 프로그래밍 언어에서 이해하는 형식 간의 상호작용을 관리한다.
- SQL Map은 Mybatis 프레임워크에서 사용되는 XML기반의 데이터베이스 매핑 파일로 데이터베이스 연산을 정의하고 매핑한다.
SQL map파일에서 사용되는 엘리먼트는 <mapper> , <select>, <insert>, <update>, <delete>, <resultMap>,<cache-ref>, <cache> 가 있다.
엘리먼트/ 속성
*사이트의 표를 확인 하면 더 자세히 확인 할 수 있다.(엘리먼트 속성)
- <mapper> : 루트 엘리먼트
- namespace:
<mapper namespace="org.zerock.mapper.BoardMapper">
- namespace:
- <select>: 데이터베이스의 결과를 자바객체에 매핑할때 resultType, resultMap을 사용
- 고유 식별자:id
- 비지니스 로직에서 전달 받아 쿼리에 전달 될 파라미터의 타입 지정: parameterType/ parameterObject
- 비즈니스 로직으로 전달 할 쿼리 실행 결과를 매핑할 자바 객체 타입 지정: resultType/ resultMap
- resultType: 단일 객체에 매핑할 때 사용(비즈니스 로직으로 반환할, 결과값의 자료형)
- 자바 클래스의 경로(패키지 포함)이나 기본 타입(primitive types)을 지정하거나
<select id="getList" resultType="org.zerock.domain.BoardVO"> - 객체의 alias를 지정 할 수 있다.
<typeAliase type="org.zerock.domain.BoardVO" alias="project"/>
<select id="getList" resultType=" BoardVO">
- 자바 클래스의 경로(패키지 포함)이나 기본 타입(primitive types)을 지정하거나
- resultMap: 주로 select문에서 복잡한 매핑이 필요할때 사용하며, 단순 테이블 조회가 아닌 join구문을 포함하는 등의 복잡한 매핑이 필요할때 사용한다.( 비즈니스 로직으로 반환할, 결과값을 담은 객체)
- resultType: 단일 객체에 매핑할 때 사용(비즈니스 로직으로 반환할, 결과값의 자료형)
- <insert>
- id
- parameterType
- selectKey: 쿼리 실행 후 생성된 키를 조회할 때 사용되는 서브 쿼리를 정의
- KeyProperty: 생성된 키를 매핑할 자바 객체 지정
- resultType: 서브쿼리의 결과를 매핑할 자바 객체 타입 지정
- order: 서브쿼리의 실행 순서를 지정
<selectKey keyProperty="bno" order="AFTER" resultType="java.lang.Long">
- <update>
- id
- parameterType
- <delete>
- id
- parameterType
파라미터 표기법
#{속성}
- 플레이스 홀더문법(SQL인젝션을 방지)
SQL인젝션(SQL Injection)은 악의적인 사용자가 입력된 데이터를 통해 SQL 쿼리를 조작하여 데이터베이스에 대한 공격을 시도하는 보안 취약점을 예방함 - 이 표기법은 마이바티스에게 PreparedStatement파라미터를 만들도록 지시한다. JDBC를 사용할 때 PreparedStatement에는 “?”형태로 파라미터가 전달된다.
<![CDATA[]]>
CDATA는 Character Data의 약자로 XML문서에서 특수문자를 포함하는 텍스트를 작성할때 사용한다.
XML파서는 특수문자를 일반 텍스트로 취급하여 해석하지 않는다.
기본키 자동생성 하는 방법
- 오라클은 시퀀스를 사용하여 DB에서 id값을 자동 생성해준다.
create sequence seq_board;
create table tbl_board (
bno number(10,0), // 데이터 타입의 정의 : NUMBER(precision, scale) 전체 자릿수, 소숫점 이하 자릿수
title vaechar2(200) not null, //최대 200자 문자열
);
alter table tbl_board add constraint pk_board primary key (bno);
- MySQL은 쿼리문의 칼럼의 autoincrement 속성값을 사용하여 DB에 id값을 자동 생성해준다.
- AUTO_INCREMENT PRIMARY KEY : 자동으로 증가하는 값을 설정, 기본키 설정
CREATE TABLE tbl_board (
bno INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
);
- MyBatis에서도 id값을 자동 생성해 줄 수 있다.
- useGeneratedKeys: JDBC의 getGeneratedKeys() 메서드를 사용하여 DB에서 자동으로 생성된 키값을 가져옴
- keyProperty: 자동생성된 키값을 저장할 자바 객체의 속성을 정의하는 속성
<!-- MyBatis(JDBC)에서 PK값을 넣어줌 -->
<insert id="insertSelectKey" useGeneratedKeys="true" keyProperty="bno">
insert into tbl_board (title, content, writer)
values (#{title}, #{content}, #{writer})
</insert>
SQL문에서 생성된 키를 가져오기 위한 방식
- 오라클 시퀀스로 id값부여
nextval(시퀀스의 다음 값을 가져오는 함수= 현재시퀀스 값+1)
CURRVAL(시퀀스의 현재값을 가져오는 함수)
- MySQL은 AUTO_INCREMENT로 id값부여
LAST_INSERT_ID()(가장최근의 값 가져옴)
1. 키 값 조회하기(MYSQL)
방법1: AUTO_INCREMENT가 되는 DBMS에서 사용가능
방법2: selectKey 구문 사용
방법1
- selectKey 엘리먼트를 사용하여 자동으로 생성된 키를 가져옴
- select last_insert_id(): MYSQL에서 사용되는 함수로 마지막으로 삽입된 AOUTO_INCREMENT값을 가져옴
- order: selectKey문을 insert 전/후 실행될지 정함
* MYSQL에서 insert문을 실행한 후 bno 조회
<!-- order속성: <selectKey> 구문을 언제 사용할지 결정 -->
<!-- last_insert_id(): MYSQL에서 사용되는 함수로 마지막으로 삽입된 AOUTO_INCREMENT값을 가져와 bno에 할당-->
<insert id="insertSelectKey">
insert into tbl_board (title, content, writer)
values (#{title}, #{content}, #{writer})
<selectKey keyProperty="bno" order="AFTER" resultType="java.lang.Long">
select last_insert_id()
</selectKey>
</insert>
* 오라클에서 insert문이 실행 되기 전 bno 값을 조회하여 삽입
- 객체에 자동 생성키를 직접 담아준다.
- 객체의 값은 공유하기 때문에 SQL 수행에서 그대로 #{bno} 으로 해도 자동 생성키가 입력된다.
- 보통 id값을 이용하여 쿼리를 작성할 때 사용한다. (bno의 값에 1씩 증가 된 값으로 정하고 싶을때)
<!-- @SelectKey와 사용. PK값을 미리 SQL을 통해 처리하고, 특정이름으로 결과를 보관함.
@insert 할때 SQL문을 보면 #{bno}와 같이 이미 처리 된 결과를 이용하는것을 확인 할 수 있음. -->
<insert id="insertSelectKey_Oracle_Query">
<selectKey keyProperty="bno" order="BEFORE" resultType="long">
select seq_board.nextval form dual
</selectKey>
insert into tbl_board (bno, title, content, writer)
values (#{bno}, #{title}, #{content}, #{writer})
</insert>
MYSQL에서 order=before로 작성하는 방법을 아무리 찾아봐도 모르겠다.. oracle은 Sequence는 여러테이블에서 사용 될 수 있는 별도의 객체로 DB에 저장된다. 그래서 Sequence객체에서 key 를 가져 올 수 있는 것같다.
MYSQL은 컬럼의 열 속성에 AUTO_INCREMENT 값을 추가한 것으로, 데이터베이스 테이블에 속하고, 해당 테이블에서만 사용가능 하다. 그래서 select last_insert_id()를 사용하면 가장 마지막에 저장된 key를 가져오는데 SQL이 실행되기 전에 키를 먼저 가져 올 수 없다. 그래서 insert문 안에서 after는 되고 before는 0이 되는 것 같다.
insert문이 실행 되기 전 bno 값을 조회하고 싶으면 oracle을 이용해야겠다..... 🤣
방법2
- useGeneratedKeys: JDBC의 getGeneratedKeys() 메서드를 사용하여 DB에서 자동으로 생성된 키값을 가져옴
- keyProperty: 자동생성된 키값을 저장할 자바 객체의 속성을 정의하는 속성
<!-- MyBatis(JDBC)에서 PK값을 넣어줌 -->
<!-- useGeneratedKeys: JDBC의 getGeneratedKeys() 메서드를 사용하여 DB에서 자동으로 생성된 키값을 가져옴 -->
<!-- keyProperty: 자동생성된 키값을 저장할 자바 객체의 속성을 정의하는 속성 -->
<insert id="insertSelectKey_JDBCInsertPK" useGeneratedKeys="true" keyProperty="bno" parameterType="BoardVO" >
insert into tbl_board (title, content, writer)
values (#{title}, #{content}, #{writer})
</insert>