Developer Note/국비과정 수업내용 정리&저장

24년 11월 13일

DH_PARK 2024. 11. 24. 20:09

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 &lt; = #{keyword}  //위 3개의 조건이 아니라면 otherwise 블럭 실행 createAt <= keyword 값보다 작거나 같은 데이터를 조회한다.
																			// &lt; = <
				</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