myBatis
우선 마이바티스 의존성을 Maven Repository에서 받아서 pom.xml 에 의존 추가해야한다.
<!-- MYBATIS -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.16</version>
</dependency>
<!-- MYBATIS Spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
pom.xml 파일에 의존성 추가 (maven reposiroty)
MyBatis에서 SQL 구문은 SqlSession을 통해 실행되며 쓰레드마다 별도의 SqlSession 인스턴스를 가집니다.
(SqlSession 인스턴스는 쓰레드간 공유되지 않습니다.) SqlSession의 생명주기는 client 요청시 생성되고 역할을 수행한 뒤 소멸합니다. (SqlSessionFactory는 싱글턴 형태로 단 한개만 생성되며 어플리케이션이 실행되고 있는 동안 존재합니다.)
SqlSessionFactory 설정하기
SqlSessionFactory는 SqlSessionFactoryBean 구현체를 활용하여 생성하고 DataSource를 주입받습니다.
(순수 MyBatis 프레임워크만 이용할 경우에는 SqlSessionFactoryBuilder를 사용하지만 Spring에서 MyBatis를 셋팅할 경우 SqlSessionFactoryBean을 사용합니다.)
<context:component-scan base-package="com.example.ex01.config" />
<context:component-scan base-package="com.example.ex01.domain.service" />
<context:component-scan base-package="com.example.ex01.domain.dao" />
<mybatis-spring:scan base-package="com.example.ex01.domain.mapper" />
root-context.xml 에 mybatis 경로를 지정해줘야 사용가능
마이바티스 오류
Error creating bean with name 'memoMapper' defined in file [C:\워크스페이스\ex06_test\target\classes\com\example\ex01\domain\mapper\MemoMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required 이라는 오류가 나서 왜그런지 알아보았다.
우선 GPT 한테 먼저 물어보았는데
ChatGPT의 말:
ChatGPT
오류 메시지에서 알 수 있듯이, MemoMapper 빈을 생성할 때 sqlSessionFactory 또는 sqlSessionTemplate이 설정되지 않아서 발생하는 문제입니다. MyBatis의 매퍼가 스프링 컨테이너에서 동작하려면, SqlSessionFactory 또는 SqlSessionTemplate이 제대로 설정되어 있어야 합니다.
SqlSessionFactory 파일에서 설정이 잘못 되어있는듯하다 ?
해결 방법
이 오류를 해결하기 위해서는 SqlSessionFactory 또는 SqlSessionTemplate이 root-context.xml에 올바르게 설정되어 있는지 확인해야 합니다.
1. SqlSessionFactory 설정 확인
SqlSessionFactory 빈이 root-context.xml에 제대로 등록되어 있는지 확인하세요. DataSource가 정확히 설정되어 있어야 하며, 아래와 같이 설정할 수 있습니다.
xml
코드 복사
<!-- DataSource 설정 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/your_database" />
<property name="username" value="your_username" />
<property name="password" value="your_password" />
</bean>
<!-- SqlSessionFactory 설정 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
2. SqlSessionTemplate 설정
SqlSessionTemplate을 사용하는 경우, SqlSessionTemplate 빈도 등록해야 합니다. SqlSessionTemplate은 SqlSessionFactory를 참조해야 하므로, SqlSessionFactory 빈이 먼저 등록된 상태여야 합니다.
xml
코드 복사
<!-- SqlSessionTemplate 설정 -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory" />
</bean>
3. @MapperScan 또는 <mybatis-spring:scan> 확인
매퍼 인터페이스가 있는 패키지를 스캔하도록 설정되어 있는지 확인하세요. @MapperScan을 Java 설정에서 사용하거나, XML 설정에서 <mybatis-spring:scan base-package="com.example.ex01.domain.mapper" />와 같이 매퍼 패키지를 정확히 지정해야 합니다.
최종 예시 (XML 설정)
최종적으로 root-context.xml의 구성이 다음과 같아야 합니다.
xml
코드 복사
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd">
<!-- DataSource 설정 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/your_database" />
<property name="username" value="your_username" />
<property name="password" value="your_password" />
</bean>
<!-- SqlSessionFactory 설정 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- SqlSessionTemplate 설정 -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory" />
</bean>
<!-- MyBatis 매퍼 스캔 -->
<mybatis-spring:scan base-package="com.example.ex01.domain.mapper" />
</beans>
오류 해결
그래서 왜그런가 보니 DataSourceConfig 파일에서 2개의 데이터 Connection 을 반환해주고 있어서 생긴 오류였다.
package com.example.ex01.config;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.zaxxer.hikari.HikariDataSource;
@Configuration
public class DataSourceConfig { //데이터 커넥션 자동연결 설정파일
@Autowired
private DataSource dataSource2; //함수명이 자동으로 등록됨
@Bean
public DataSource dataSource2() {
// DriverManagerDataSource dataSource = new DriverManagerDataSource();
BasicDataSource dataSource = new BasicDataSource(); //커넥션 pooling 처리
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/bookdb");
dataSource.setUsername("root");
dataSource.setPassword("1234");
dataSource.setMaxTotal(10); //최대 연결 개수
dataSource.setMaxIdle(8); //최대 유휴 연결개수
dataSource.setInitialSize(5); //초기 연결 개수
dataSource.setMinIdle(3); //최소 유휴 연결 개수
dataSource.setMaxWaitMillis(30000); //CP에서 Connection 객체를 가져오기 위해 기다리는 최대시간
return dataSource;
}
@Autowired
private DataSource dataSource3; //함수명이 자동으로 등록됨
@Bean
public DataSource dataSource3() {
// DriverManagerDataSource dataSource = new DriverManagerDataSource();
HikariDataSource dataSource = new HikariDataSource(); //커넥션 pooling 처리
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/bookdb");
dataSource.setUsername("root");
dataSource.setPassword("1234");
dataSource.setMaximumPoolSize(100);
return dataSource;
}
}
여기서 BasicDataSource 를 그냥 주석처리하고 히카리Cp를 이용한 커넥션을 받아서 사용하니 정상적으로 동작이 되었다.
<?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="com.example.ex01.domain.mapper.MemoMapper">
<insert id="insert_xml" parameterType="com.example.ex01.domain.dto.MemoDto"> <!-- memoDto 를 파라미터로 지정 -->
<selectKey keyProperty="id" order="AFTER" resultType="int">
select max(id) from tbl_memo
</selectKey>
insert into tbl_memo values(null,#{text},#{writer},now())
</insert>
<update id="update_xml"
parameterType="com.example.ex01.domain.dto.MemoDto">
update tbl_memo set text=#{text} , writer=#{writer} where id=#{id}
</update>
<delete id="delete_xml"
parameterType="com.example.ex01.domain.dto.MemoDto">
delete from tbl_memo where id=#{id}
</delete>
<select id="select_xml" parameterType="int"
resultType="com.example.ex01.domain.dto.MemoDto"> <!-- 결과값을 memoDto로 지정 -->
select * from tbl_memo where id=#{id}
</select>
<select id="SelectAll_xml_1" resultType="com.example.ex01.domain.dto.MemoDto">
select * from tbl_memo
</select>
<select id="selectAll_xml_2" resultType="java.util.Map">
select * from tbl_memo </select>
<resultMap type="java.util.HashMap" id="MemoResultMap2">
<id property="id" column="id"></id>
<result property="text" column="text"></result>
</resultMap>
<select id="selectAll_xml_3" resultMap="MemoResultMap2">
select id,text from tbl_memo
</select>
<select id="select_if_xml" parameterType="java.util.Map" resultType="java.util.Map">
select * from tbl_memo
<if test="type!=null and type.equals('text')">
where text like concat('%',#{keyword},'%')
</if>
</select>
<select id="select_when_xml" parameterType="java.util.Map" resultType="java.util.Map">
select * from tbl_memo
<if test="type!=null"> //if test : 조건문. type 이 null 이라면 아래 if 블럭안에 있는 코드들은 실행되지 않아 전체조회가 실행되도록 한다.
where
<choose>
<when test="type.equals('id')">
id like concat('%',#{keyword},'%') type 이 id라면 id 를 전달받은 파라미터 keyword 와 비교한다. (문자열안에 id가 포함되있는지 확인)
</when>
<when test="type.equals('text')">
text like concat('%',#{keyword},'%')
</when>
<when test="type.equals('writer')">
writer like concat('%',#{keyword},'%')
</when>
<otherwise>
createAt < = #{keyword} //위 3개의 조건이 아니라면 otherwise 블럭 실행 createAt <= keyword 값보다 작거나 같은 데이터를 조회한다.
// < = <
</otherwise>
</choose>
</if>
</select>
<!-- 여기서 함수를 선언 -->
</mapper>
xml 파일에서 DB CRUD 를 선언 , 수정도 가능.
그리고 xml 파일에서 함수를 Mapping 시키는 방법을 사용할 때는 아래 코드처럼 조건식으로 사용이 가능하다.
myBatis CRUD 처리 작업방식 복습 !!
- interface 를 사용하는 방식(Mapper.java)
- 인터페이스로 myBatis 메서드를 정의하고 메서드 이름으로 SQL문을 자동으로 매핑한다.
- 비교적 간단한 쿼리문에 사용한다
- @select , @delete , @update , @insert 같은 어노테이션을 사용해서 메서드를 만듬
- xml 파일을 사용하는 방식 (xml 매퍼)
- 쿼리문을 xml 파일에 작성하여 java 코드를 sql 코드와 분리할 수 있다.
- 복잡한 SQL 을 사용할 때 사용한다.
- 조건문 , 동적 쿼리를 사용할 수 있다 (xml의 if , forEach 같은 태그를 사용해 가독성을 좋게 만들 수 있다)
- XML 매퍼를 통해 여러 메서드에서 같은 쿼리를 재사용할 수 있다.
sqlSession 의 crud 함수는 jdbc 코드를 마이바티스 코드로 변환한것
'Developer Note > 국비과정 수업내용 정리&저장' 카테고리의 다른 글
24년 11월 15일 (0) | 2024.11.24 |
---|---|
24년 11월 14일 (0) | 2024.11.24 |
24년 11월 12일 (0) | 2024.11.22 |
24년 11월 11일 (1) | 2024.11.21 |
24년 11월 08일 (2) | 2024.11.21 |