<update id="companyBoardCountUpadate" parameterType="CompanyBoardContent">
<selectKey order="BEFORE" keyProperty="companyCount" resultType="String">
SELECT
c.company_count+1
from
tb_company AS c
where
c.company_code = #{companyCode}
</selectKey>
UPDATE tb_company
SET
company_count= #{companyCount}
WHERE
company_code = #{companyCode}
</update>
쿼리문도 전부 정상이고 오탈자도 없으며,, DTO에 알맞은 getter, setter도 전부 있었는데!!!!!!!!!!!
org.apache.ibatis.executor.ExecutorException: No setter found for the keyProperty 'companyCount' in java.lang.String.
이 오류로 인해 진행이 안되는 상황이었다..
조언도 구해봤는데 원인을 전혀 모르겠어서 서브쿼리로 처리했다...
마이바티스!!!!!! 나는 너를 믿었는데!!
그래도 서브쿼리로 바꾼 코드가 더 간결해서 기분이 좋아졌다 ~~ ^^~!!
<update id="companyBoardCountUpadate" parameterType="CompanyBoardContent">
UPDATE tb_company
SET
company_count= (SELECT company_count +1)
WHERE
company_code = #{companyCode}
</update>
package kr.or.ksmart;
class Member{
//인스턴스변수, 멤버필드
private String memberName;
//생성자메서드
public Member(String memberName) {
this.memberName = memberName;
};
//메서드
public String getMemberName () {
return memberName;
};
}
class User{
//생성자메서드를 접근지정자 private으로 선언 시 외부에서 객체화 불가능
private User() {
};
public static User getInstance() {
return new User();
};
}
public class JavaEx01 {
public static void main(String[] args) {
/*
* 복습1. Member라는 클래스를 생성할 것이다.
* 이 Member라는 클래스는 인스턴스화 할 때 매개변수 1개를 받아야만 인스턴스화가 가능하다.
* 또한 Member 클래스는 인스턴스변수 memberName 그리고 getMemberName이라는 메서드를 가지게 된다.
* 위의 조건대로 클래스를 생성하고 선언과 호출을 하도록 하여라.
* (인스턴스화 할 때 들어간 인수값은 인스턴스변수에 저장된다.)
*/
Member member = new Member("김최첨단");
System.out.println(member.getMemberName());
/*
* 복습2. User클래스를 생성할 것이다.
* 이 User클래스는 new 연산자를 통하여 인스턴스화 할 수 없으며, getInstance라는 메서드를 통해서 인스턴스화 가능하다.
* 이 클래스를 선언하고 인스턴스화를 시키도록 하여라.
*/
User user = User.getInstance();
System.out.println(user+"<<-user");
/*
* 복습3. 래퍼클래스가 무엇인지 서술하시오.
*
* 기본형 타입의 데이터를 객체로 취급하기 위해 사용하는 클래스.
* 클래스변수와 클래스메서드 위주로 다
*/
/*
* 복습4. 인스턴스변수와 클래스변수 차이점을 서술하시오.
* 인스턴스변수 : 인스턴스화 되어야 접근 가능한 변수
* 클래스변수 : 인스턴스화 하지 않아도 접근 가능한 변수
*
* 인스턴스변수는 클래스가 인스턴스화 될 때마다 함께 새로이 인스턴스화 되는 변수이고
* 클래스변수는 정적으로 선언되어있어, 한 번 인스턴스화된 주소값을 변동없이 가리키는 변수이다.
*/
/*
* 복습5. class로 변환된(바이트 코드) 파일을 실행시키거나, java 프로그래밍의 메모리를 관리하는 프로그램의 명칭이 무엇인가요?
*
* Java Virtual Machine
*/
}
}
package kr.or.ksmart;
class MemberSuper{
public String getMemberName() {
return null;
}
public final int getMemberAge() {
return 0;
}
public void setMemberAddr(String addr1) {
}
public void setMemberAddr(String addr1, String addr2) {
}
}
class MemberSub extends MemberSuper {
@Override
public String getMemberName() {
return null;
}
/*public int getMemberAge() {
return 0;
}*/
}
public class JavaEx02 {
public static void main(String[] args) {
/*
* 복습6. MemberSuper클래스와 MemberSub클래스가 있다.
* MemberSub는 MemberSuper의 멤버를 가지고 있다.
* 위의 설명에 맞는 클래스를 선언하고 호출하도록 하여라.
*/
/*
* 복습7. 복습6의 클래스의 관계에서 추가적인 메서드를 생성할 것이다.
* MemberSuper 클래스에 getMemberName과 getMemberAge라는 메서드가 있다.
* MemberSub 클래스에서 getMemberName 오버라이딩은 가능하나, getMemberAge는 오버라이딩이 불가능하다.
* 위의 설명에 알맞게 메서드를 작성하여라.
*/
/*
* 복습8. 복습6의 클래스의 관계에서 추가적인 메서드를 생성할 것이다.
* setMemberAddr 메서드가 1개의 매개변수를 받을 수도 있고
* setMemberAddr 메서드가 2개의 매개변수를 받을 수도 있다.
* 메서드를 알맞게 작성하여라. >>메서드오버로딩
*/
}
}
package kr.or.ksmart;
interface In1{
public int in1();
}
interface In2{
public int in2();
}
class InIm implements In1, In2 {
@Override
public int in2() {
return 0;
}
@Override
public int in1() {
return 0;
}
}
public class JavaEx03 {
public static void main(String[] args) {
/*
* 복습9. 인터페이스 2개를 상속받은 클래스를 생성할 것이다.
* 인터페이스의 명은 In1, In2 이며
* int 형을 리턴하는 In1 인터페이스의 in1 메서드, In2 인터페이스의 in2 메서드를 가지고 있다.
* InIm으로 클래스를 생성하고 2개의 인터페이스를 상속받아 객체화할 수 있도록 만들어라.
* 또한 InIm를 객체화하고 In1, In2를 업캐스팅 하도록 하여라
*/
InIm inIm = new InIm();
In1 in1 = inIm;
In2 in2 = inIm;
/*
* 복습10. 객체지향의 4대 원칙을 서술하시오.
* 캡슐화, 추상화, 상속, 다형성
*/
/*
* 복습11. 객체지향 설계의 5대 원칙을 서술하시오.
* SOLID
* 1. SRP(단일 책임 원칙) - 소프트웨어의 설계 부품(클래스, 함수 등)은 단 하나의 책임만을 가져야 한다.
* 2. OCP(개방-폐쇄 원칙) - 기존의 코드를 변경하지 않고(Closed) 기능을 수정하거나 추가할 수 있도록(Open) 설계해야 한다. > getter, setter
* 3. LSP(리스코프 치환 원칙) - 자식 클래스는 부모클래스에서 가능한 행위를 수행할 수 있어야 한다. > 업캐스팅과 관련
* 4. ISP(인터페이스 분리 원칙) - 한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다. 하나의 일반적인 인터페이스 보다 여러 개의 구체적인 인터페이스가 낫다.
* 5. DIP(의존 역전 원칙) - 의존 관계를 맺을 때, 변화하기 쉬운 것 보다 변화하기 어려운 것에 의존해야 한다는 원칙이다.
*/
}
}
match 함수를 사용하려고 하였는데 match는 정규식을 인식하기 때문인지 +를 문자열로 받아주질 않았다..
그래서 정규표현식을 사용해버리기로 했다~
//로그인 실패시 alert ()
var message = null;
//uri에서 get방식으로 넘긴 값 추출
var uri = decodeURI(location.href);
var get = uri.substr(uri.indexOf('?')+1);
if(uri != get){
message = get.substr(get.indexOf('=')+1);
};
//.을 제외한 특수문자 정규식
var regExp = /[\{\}\[\]\/?,;:|\)*~`!^\-+<>@\#$%&\\\=\(\'\"]/gi;
if(regExp.test(message)){
//.을 제외한 특수문자를 공백으로 치환
message = message.replace(regExp,' ');
};
//추출한 값이 null이 아닐 경우 alert창 출력
if(message != null){
alert(message);
};
test를 통해 .을 제외한 특수문자 정규식과 message의 문자열과 비교해 특수문자 여부를 파악하고
message에 특수문자가 있다면 정규식에 기술한 특수문자들을 공백으로 바꾸는 식을 만들었다!
<!-- 처리업무 등록 -->
<insert id="unpaidInsert" parameterType="Unpaid">
<!-- unpaidCode -->
<selectKey order="BEFORE" keyProperty="unpaidCode" resultType="String">
select
(case count(*)
when 0 then 'unpaid_1'
else CONCAT('unpaid_',max(cast(substring(unpaid_code,8) as decimal))+1)
end) as unpaidCode
from
tb_unpaid
</selectKey>
<selectKey order="BEFORE" keyProperty="customerCode" resultType="String">
SELECT
c.customer_code
from
tb_customer AS c
where
#{customerName} = c.customer_name
and
#{customerTel} = c.customer_tel
</selectKey>
<selectKey order="BEFORE" keyProperty="unpaidRegStaffCode" resultType="String">
SELECT
sf.staff_code
from
tb_staff as sf
join
tb_member as m
on
sf.member_id = m.member_id
join
tb_store AS sr
on
sf.store_code =sr.store_code
where
#{unpaidRegMemberName} = m.member_name
and
#{unpaidRegStoreName} = sr.store_name
</selectKey>
INSERT INTO tb_unpaid
(unpaid_code
, unpaid_exp_date
, unpaid_part
, unpaid_sub_name
, unpaid_desc
, customer_code
, unpaid_memo
, unpaid_status
, unpaid_reg_date
, unpaid_reg_staff_code)
VALUES
(#{unpaidCode}
, NOW()
, #{unpaidPart}
, #{unpaidSubName}
, #{unpaidDesc}
, #{customerCode}
, #{unpaidMemo}
, #{unpaidStatus}
, NOW()
, #{unpaidRegStaffCode})
</insert>
mapper.xml 에서 <insert></insert> 안에 <selectKey></selectKey>를 여러개 사용하여 여러가지의 조인 값을 가져오고싶었다! 하지만 계속 오류가 발생했다.
알고보니<selectKey></selectKey> 는 한개만 사용할 수 있다고 한다!!
<!-- 처리업무 등록 -->
<insert id="unpaidInsert" parameterType="Unpaid">
<selectKey order="BEFORE" keyProperty="unpaidCode,customerCode,unpaidRegStaffCode" resultType="Map">
select
(case count(*)
when 0 then 'unpaid_1'
else CONCAT('unpaid_',max(cast(substring(unpaid_code,8) as decimal))+1)
end) as unpaidCode
,tc.customer_code as customerCode
,tc.staff_code as unpaidRegStaffCode
from
tb_unpaid AS u ,(
SELECT
c.customer_code,
tf.staff_code
from
tb_customer AS c,
(
SELECT
sf.staff_code
from
tb_staff as sf
join
tb_member as m
on
sf.member_id = m.member_id
join
tb_store AS sr
on
sf.store_code =sr.store_code
where
#{unpaidRegMemberName} = m.member_name
and
#{unpaidRegStoreName} = sr.store_name
)AS tf
where
#{customerName} = c.customer_name
and
#{customerTel} = c.customer_tel
)AS tc
</selectKey>
INSERT INTO tb_unpaid
(unpaid_code
, unpaid_exp_date
, unpaid_part
, unpaid_sub_name
, unpaid_desc
, customer_code
, unpaid_memo
, unpaid_status
, unpaid_reg_date
, unpaid_reg_staff_code)
VALUES
(#{unpaidCode}
, NOW()
, #{unpaidPart}
, #{unpaidSubName}
, #{unpaidDesc}
, #{customerCode}
, #{unpaidMemo}
, #{unpaidStatus}
, NOW()
, #{unpaidRegStaffCode})
</insert>
그래서 서브쿼리를 사용하여 여러개의 컬럼을 한개의 selectKey에 담았다.
insert 쿼리문에서 값을 받을 때 #{paramater}와 selectKey의 select문의 alias가 대응된다~!!
친구랑 대화하다보니 하나의 서비스에서 처리하지 않고 서비스를 나누어서 처리하는 방법도 있을 거라고 깨달았다!!
서비스를 나누어 처리하면 서브쿼리를 쓰지 않고도 처리할 수 있을 것이다.
서비스를 하나로 만들면 서비스를 나눈 것 보다유지보수 측면에서 이득이라고 하니 상황에 따라 골라서 사용해야겠다.
또, 요즘 join이 없도록 작업하는 추세라고 하는데!!
정규화를 막 배운 입장에서는 아직 실제로 사용하기에는 정규화가 마음에 걸린다...
하지만 서브쿼리 안에!! 서브쿼리 안에!! 서브쿼리를 넣다 보니 join이 없는 작업이 더 편리할 것 같다고 느꼈다.
지금 하고있는 프로젝트는 작은 규모이기 때문에 데이터베이스에 데이터가 적어서 체감을 못했지만, join이 많이 일어나면 데이터가 많이 존재할 경우 처리속도가 느려진다고 하니 참고해야겠다!!