Back to feed
Renewal·서른의 생활코딩

Following Toby's Spring 3.1 on Spring Boot: Chapter 1 - 1.2 DAO Separation

NS
normalstory
cover image

Following Toby's Spring 3.1 on Spring Boot: Chapter 1 Objects and Dependencies - 1.2 DAO Separation 


0. Development Environment 

- OS : mac

- STS : 4.0.1

- MySQL : Server version: 8.0.13 Homebrew

- Frame-Work : For now, running with minimal dependencies, built only as jar


Related links 

- Spring User Group_Homepage     http://www.ksug.org/

- Spring User Group Q&A     https://groups.google.com/forum/#!topic/ksug/13vB4tCFqrI

- 2017 Spring Camp                       https://www.youtube.com/playlist?list=PLdHtZnJh1KdZ6NDO9zc9hF4tONDLTSEUV




Chapter 1. Objects and Dependencies 

1.2 DAO Separation 

Separation of concerns. You can think of it as gathering things with the same concern into one object or closely related objects, while separating different concerns as far apart as possible so they don't affect each other. 


01-1. Extracting the Connection Creation 

     1. Identifying UserDao's concerns

1) How to get a connection for the DB

2) Execute the statement holding the SQL to be sent to the DB 

(1) Bind the user info passed as parameter into the statement

(2) How to run the SQL in the statement through the DB 

(3) Close resources after use 

2. Dao Separation Work 

1) Removing duplicated code 

(1) Extract the duplicated code that gets the connection 

- Code = UserDao.java 

 
package springbook.user.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import springbook.user.domain.User;

/**
 * 토비의 스피링 3.1 예제 따라하기 
 * 1장 - 02 DAO 분리
 * 
 * @since 	2019.02.19 
 * @author 	친절한 찰쓰씨 http://normalstory.tistory.com
 */
public class UserDao {
	public void add(User user) throws ClassNotFoundException, SQLException {

		Connection c = getConnection();
		
		PreparedStatement ps = c.prepareStatement(
				"insert into users(id,name,password) values(?,?,?)");
		ps.setString(1, user.getId());
		ps.setString(2, user.getName());
		ps.setString(3, user.getPassword());
		
		ps.executeUpdate();
		
		ps.close();
		c.close();
	}
	
	public User get(String id) throws ClassNotFoundException, SQLException {
		
		Connection c = getConnection();
		
		PreparedStatement ps = c.prepareStatement(
				"select * from users where id =?");
		ps.setString(1, id);
		
		ResultSet rs = ps.executeQuery();
		rs.next();
		User user = new User();
		user.setId(rs.getNString("id"));
		user.setName(rs.getString("name"));
		user.setPassword(rs.getString("password"));

		rs.close();
		ps.close();
		c.close();
		
		return user;
	}
	
	/**
         * 토비의 스피링 3.1 예제 따라하기 
         * 1장 - 02 DAO 분리 : ReFactoring
         *
         * @since 	2019.02.19
         * @author 	친절한 찰쓰씨 http://normalstory.tistory.com
	 * 
	 * @return c 
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	private Connection getConnection() throws ClassNotFoundException, SQLException {
		Class.forName("com.mysql.jdbc.Driver");
		
		String ConnectUrl = "jdbc:mysql://localhost:3306/sample?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC";
		String ConnectId = "root";
		String ConnectPass = "ever1227";
		
		Connection c = DriverManager.getConnection(
				ConnectUrl, ConnectId, ConnectPass);
		
		return c;
	}

}


(2) Incremental test of changes  

If you only change the setId value corresponding to the PK, it works properly just as before.

(3) Review 

The work we just did didn't change UserDao's functionality at all. But there was an important change. What we did was extracting the code carrying a specific concern that appeared duplicated across multiple methods into a separate method. This work only changes the structure without affecting functionality. The code is now better prepared for future changes. This kind of work is called refactoring. Also, the technique of extracting duplicated code into a method that handles a common function, as in this example, is called the extract method technique.



3) Making DB connection independent = 
Creating a dedicated DB connection class

According to this example, this feature cannot be delivered to two companies with different DB environments. To deliver in the current state, we might have to expose the getConnection() that may contain core logic and say "modify it yourself". What would be a better way?


(1) Extension via inheritance 

We separate UserDao one more time. We remove the implementation code and turn getConnection() into an abstract method. Even though there's no code, the method itself still exists, so the code that calls add(), get(), and getConnection() can stay the same. 


(2) Dedicated DAO for getConnection()

We remove the previous implementation code in the getConnection() method and change it to an abstract method. Now the method implementation is handled by the subclass (class NUserDao extends UserDao). The code is as follows. For the contents of User.java, refer to the execution result screenshot. We changed UserDao to NUserDao.


Code = UserDao.java : Adjusting the getConnection() here into an abstract class and 

 
package springbook.user.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import springbook.user.domain.User;

/**
 * 토비의 스피링 3.1 예제 따라하기 
 * 1장 - 01 초난감 DAO
 * 
 * @since 	2019.02.17 
 * @author 	친절한 찰쓰씨 http://normalstory.tistory.com
 */
public abstract class UserDao {
	public void add(User user) throws ClassNotFoundException, SQLException {

		Connection c = getConnection();
		
		PreparedStatement ps = c.prepareStatement(
				"insert into users(id,name,password) values(?,?,?)");
		ps.setString(1, user.getId());
		ps.setString(2, user.getName());
		ps.setString(3, user.getPassword());
		
		ps.executeUpdate();
		
		ps.close();
		c.close();
	}
	
	public User get(String id) throws ClassNotFoundException, SQLException {
		
		Connection c = getConnection();
		
		PreparedStatement ps = c.prepareStatement(
				"select * from users where id =?");
		ps.setString(1, id);
		
		ResultSet rs = ps.executeQuery();
		rs.next();
		User user = new User();
		user.setId(rs.getNString("id"));
		user.setName(rs.getString("name"));
		user.setPassword(rs.getString("password"));

		rs.close();
		ps.close();
		c.close();
		
		return user;
	}
	
	/**
         * 토비의 스피링 3.1 예제 따라하기 
         * 1장 - 02 DAO 분리 : 추상 메소드로 조정, 
         *                   메소드 구현은 서브 클래스(NUserDao.class)가 담당
         *
         * @since 	2019.02.19
         * @author 	친절한 찰쓰씨 http://normalstory.tistory.com
	 * 
	 * @return c 
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public abstract Connection getConnection() 
			throws ClassNotFoundException, SQLException;

}


Code = NUserDao. java : We brought over the getConnection() from UserDao. java. To do this, we first extends UserDao was applied.

 
package springbook.user.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class NUserDao extends UserDao{
	
	public Connection getConnection() throws ClassNotFoundException, SQLException {
		Class.forName("com.mysql.jdbc.Driver");
		
		String ConnectUrl = "jdbc:mysql://localhost:3306/sample?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC";
		String ConnectId = "root";
		String ConnectPass = "ever1227";
		
		Connection c = DriverManager.getConnection(
				ConnectUrl, ConnectId, ConnectPass);
		
		return c;
	}
}

(3) Execution result 


3. Project File  

study_spring190219.zip
Download

1) Inside the project list area on the left -> Right click on empty space ->  import -> Existing Projects into Workspace -> Select the downloaded file

2) If you imported files from previous posts, you need to either delete or rename the previous project before importing again.



4. Update( Came back while doing section 1.4.2 Inversion of Control IoC ! ) 

What we did just now is actually Inversion of Control !

The template method in this example can be said to be a design pattern that solves problems using the concept of Inversion of Control. 

For details, see the link~ ( 1.4.2 section )


This English version was translated by Claude.

zipstudy_spring190219.zip
친절한 찰쓰씨
Written by
친절한 찰쓰씨

Pleasant Charles — UI/UX researcher at AIT. Keeping notes on design, planning, and slow days here since 2010.

More on the author's page

Keep reading

Renewal

Steadily, for the long haul, without burning out

Mar 31, 2026·9 min
Renewal

Tech-life balance

Feb 7, 2026·3 min
Renewal

Humanality, by Park Jeong-ryeol

Feb 7, 2026·11 min