@Repository ํด๋์ค์ ์์ฑ์๋ฅผ ํตํด DB ์ ์ฉ ๋๋ผ์ด๋ฒ ๋ก๋ฉ
-- Class.forName("org.mariadb.jdbc.Driver");
DriverManager.getConnection(url, username, password)๋ก DB์ ์ฐ๊ฒฐํ ํ
Connection.preparedStatement(sql)์ ํตํด sql ์ฟผ๋ฆฌ ์ธํ
PreparedStatement.setLong() ๋ฑ์ ํตํด ์ฟผ๋ฆฌ์ ? ๊ฐ์ ์ธํ
PreparedStatement.update(sql) : ์กฐํ ์ ์ธ
PreparedStatement.query(sql) : ์กฐํ -> ResultSet ๋ฐํ
(์กฐํ์ ๊ฒฝ์ฐ)
while(ResultSet.next()) {
Long field1 = ResultSet.getLong(column1)
new Product(field1, field2)
}
@Repository
public class PersonRepository {
// Database์ ๋ก๊ทธ์ธํ ์ ๋ณด
private String username = "root";
private String password = "joder9141";
// ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ค์น๋ ์ฃผ์ (JDBC URL)
private String url = "jdbc:mariadb://localhost:3306/practice";
// ์ ์ฉ ๋๋ผ์ด๋ฒ ํด๋์ค
private String driverClassName = "org.mariadb.jdbc.Driver";
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ์ฉ ๋๋ผ์ด๋ฒ ๋ก๋ฉ
public PersonRepository() {
try {
// ์ ์ฉ ๋ก๋ฉ ํด๋์ค - DB๋ง๋ค ๋ค๋ฆ
Class.forName(driverClassName);
} catch (ClassNotFoundException e) {
System.out.println("DB ์ฐ๊ฒฐ ์คํจ!");
}
}
// ๋ค์ค SELECT - ๋ชฉ๋ก ์กฐํ
public List<Person> findAll() {
String sql = """
SELECT * FROM tbl_person
""";
List<Person> personList = new ArrayList<>();
try {
// 1. DB์ ์ ์ํ๊ณ ์ ์ ์ ๋ณด๋ฅผ ๋ฐ์์ด
Connection conn = DriverManager.getConnection(url, username, password);
// 2. SQL์ ์คํํ ์ ์๋ ์คํ๊ธฐ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ด
PreparedStatement pstmt = conn.prepareStatement(sql);
// 3. ?๊ฐ์ ์ธํ
// 4. SQL ์คํ ๋ช
๋ น
// 4-a : ๊ฐฑ์ (INSERT, UPDATE, DELETE) ๋ช
๋ น : executeUpdate()
// 4-b : ์กฐํ(SELECT) ๋ช
๋ น : executeQuery()
// ResultSet : ์กฐํ๊ฒฐ๊ณผ๋ก ๋์ค๋ 2์ฐจ์์ ํ
// -> ํ์ ์ ๊ทผํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์กฐ์ํ ์ ์๋ค.
ResultSet rs = pstmt.executeQuery();
// next(): ํฌ์ธํฐ๋ฅผ ํ ํ์ฉ ์ด๋
while (rs.next()) {
// ์ปค์๊ฐ ๊ฐ๋ฆฌํค๋ ํ์ ๋ฐ์ดํฐ ์ถ์ถ
long id = rs.getLong("id");
String personName = rs.getString("person_name");
int age = rs.getInt("age");
Person p = new Person(id, personName, age);
System.out.println("p = " + p);
personList.add(p);
}
} catch (Exception e) {
e.printStackTrace();
}
return personList;
}
}
// maria DB ๊ธฐ์ค
spring:
datasource:
url: jdbc:mariadb://localhost:3306/practice
username: root
password: ์ค์ ๋น๋ฐ๋ฒํธ
driver-class-name: org.mariadb.jdbc.Driver
๐ถ 1) yml ํ์ผ์์ db ์ฐ๊ฒฐ ์ธํ ์ ํ๋ค(id, password, driver, url)
๐ถ 2) JDbcTemplate๋ก DB์ ํต์ ํ๊ธฐ ์ํด JbcTemplate๋ฅผ @Autowired๋ก ์์ฑ
@Autowired
prive final JdbcTemplate jdbcTemplate;
- ํน์ class๋ฅผ @RequiredArgsConstructor๋ก ํ๊ณ , private final JdbcTemplete ๋ณ์๋ช
;
@RequiredArgsConstructor // final ํ๋๋ง ๊ณจ๋ผ๋ด์ ์์ฑ์ ๋ง๋ฌ
public class ProductRepository {
private final JdbcTemplate jdbcTemplate; // ์์กด๊ฐ์ฒด๋ final์ฒ๋ฆฌ
๐ถ 3) DB ๋ช
๋ น์ด๋ฅผ ๋ง๋ค์ด ์ค๋ค.
๐ถ 4) ๋ช
๋ น์ด๋ฅผ DB์ ๋ช
๋ นํด ์ค๋ค.
ย ย ย ย ย ๐นSELECT ์ธ : JdbcTemplate.update(์คํํ SQL ๋ช
๋ น์ด, SQL์์ ?๋ก ํ์๋๋ ์๋ฆฌ์ ๊ฐ)
int result = jdbcTemplate.update(
"DELETE FROM scores WHERE id = ?", // ์คํํ sql ๋ช
๋ น์ด)
Product.getId() // ์์ sql ๋ช
๋ น์ด์์ ? ๋ถ๋ถ์ ๋ค์ด๊ฐ ๊ฐ
);
ย ย ย ย ย ๐นSELECT์์ DB ์ ์ฒด ์กฐํ :
ย ย ย ย ย ย ย ย ย ย
ย ย ย ย ย ย ย ย ย - i. List< T > result = jdbcTemplate.query(String sql, RowMapper< T > rowMapper);
ย ย ย ย ย ย ย ย ย ย => **rowMapper ๋ถ๋ถ ์ฐ๋ ๋ฐฉ๋ฒ์ ์๋ ์ฐธ๊ณ
// 1. ์ต๋ช
ํด๋์ค ์ฌ์ฉ
// - ์๋ ์๋ฆฌ : query๋ก ๋ฐํ๋ REsultSet์ ๊ฐ ํ์ ๋์๊ฐ๋ฉด์,
// product ๊ฐ์ฒด๋ก ๋ง๋ค๊ณ , ๊ทธ product๋ฅผ ๋ด์ list๋ฅผ ๋ง๋ ๋ค.
new RowMapper<Product> {
@Override
public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Product(rs);
});
// 2. ๋๋ค์
(rs, rawNum) -> new Product(rs);
ย ย ย ย ย - ii. JdbcTemplate.query(sql, new BeanPropertyRowMapper(DB์์ ๋ณํํ๊ณ ์ ํ๋ ๊ฐ์ฒดํํ.class)
//jdbcTemplate.query(sql, new BeanPropertyRowMapper(db๋ฅผ ๋ณํํ๊ณ ์ ํ๋ ๊ฐ์ฒด ํ์
.class);
return jdbcTemplate.query("""
SELECT * FROM products
""",
new BeanPropertyRowMapper<>(Product.class));
ย ย ย ย ย ๐นSELECT์์ DB ์ ์ฒด ์กฐํ :
ย ย ย ย ย ย ย ย ย - List< T > result = jdbcTemplate.queryForObject(String sql, RowMapper< T > rowMapper, ํํฐ๋ง ๊ฐ);
public Board findOne(Long id) {
return jdbcTemplate.queryForObject("""
SELECT * FROM tbl_board
WHERE id = ?
""", new BeanPropertyRowMapper<>(Board.class)
, id);
}
๐ถ ์กฐํ ์ต์ ํ๋ฅผ ์ํด, Service ํด๋์ค์ @Transactional(readOnly=true)์ ํด์ค๋ค.
# database setting
Spring:
datasource:
url: jdbc:mariadb://localhost:3306/practice
username: root
password: ****
driver-class-name: org.mariadb.jdbc.Driver
# MyBatis Setting
mybatis:
# sql file location
# - @Mapper๊ฐ ๋ถ์ด ์๋ ์ธํฐํ์ด์ค์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด
# - mapper-locations ํด๋์์ resource>์ ์ด๋์ ๊ฒฝ๋ก>์ ์ด๋๋ ํ์ฅ์์ ํ์ผ์ ์ฐพ์์ ๊ทธ ํ์ผ์์ ํด๋น ๋ฉ์๋์ ์ฐ๊ฒฐ๋๋ ์ฟผ๋ฆฌ๋ฅผ ์ฐพ์์ ์คํํด๋ผ
mapper-locations: classpath:mapper/**/*.xml
# ๋ฐํํ ๊ฐ์ฒด์ package ์ฃผ์
type-aliases-package: com.spring.mvcproject.database.mybatis
# ๋๋ค๊ฐ DB column ์ด๋ฆ์ด aa_bb๋ฉด ๊ฐ์ฒด ํ๋๋ช
์ aaBb๋ก ํ๋ฉด ๋ด๊ฐ ์์์ db๋ ๊ฐ์ฒด๋ mapping ํด์ค๊ป
configuration:
# Java ํ๋๋ช
๊ณผ DB ์นผ๋ผ๋ช
๊ฐ์ ์ด๋ฆ ๋งคํ ์ค์
# DB ์นผ๋ผ๋ช
์ด aa_bb์ธ ๊ฒฝ์ฐ, Java ๊ฐ์ฒด์ ํ๋๋ช
์ aaBb๋ก ์๋ ๋งคํ
map-underscore-to-camel-case: true
๐ถ DB<->๊ฐ์ฒด ๊ฐ์ ๋ณํ์ ์ํ entity ๊ฐ์ฒด ์์ฑ
ย ย ย ย - @EqualAndHashCode(of="id")
ย ย ย ย ย ย : id๊ฐ ๊ฐ์ผ๋ฉด ๊ฐ์ ๊ฐ์ฒด๋ก ํ๋จ
ย ย ย ย - @Builder (lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ)
ย ย ย ย ย ย : Employee.builder.ํ๋๋ช
(ํ๋๊ฐ).build()ํ๋ฉด ์์์ this.ํ๋๋ช
= ํ๋๊ฐ ์์ฑ
๐ถ @Mapper ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ ๋ค.
ย ย ย ย - Repository ์ญํ ์ ํ๋ ์ธํฐํ์ด์ค๋ก,
ย ย ย ย ย ย @Mapper์ ๋ถ์์ผ๋ก์จ ์ด ์ธํฐํ์ด์ค์ ์ ์๋ ๋ฉ์๋๊ฐ ํธ์ถ๋๋ฉด,
ย ย ย ย ย ย resources>application.yml ํ์ผ์ MyBatias:Configuration:mapper-locations์์ ์ง์ ๋ ๊ฒฝ๋ก์์ ๋งคํ๋ SQL๋ฅผ ์ฐพ์ ์คํํ๋ค.
@Mapper
public interface PetRepository {
// Create: spring์ด๋ vanilla code์ ๋ฌ๋ฆฌ, **boolean ์ด ๋ฐํ๋จ**
boolean save(Pet pet);
// Read - Single Matching
Pet findById(Long id);
// Read - Multiple Matching
List<Pet> findAll();
// Read - Count
int petCount();
// Update : spring์ด๋ vanilla code์ ๋ฌ๋ฆฌ, **boolean ์ด ๋ฐํ๋จ**
boolean updatePet(Pet pet);
// Delete - Single : spring์ด๋ vanilla code์ ๋ฌ๋ฆฌ, **boolean ์ด ๋ฐํ๋จ**
boolean deleteById(Long id);
๐ถ resources>application.yml ํ์ผ์ MyBatias:Configuration:mapper-locations์์ ์ง์ ๋ ๊ฒฝ๋ก์ ํ์ผ์ ๋ง๋ค์ด, SQL์ฟผ๋ฆฌ๋ฅผ ๋งคํ
<?xml version="1.0" encoding="UTF-8"?>
<!-- mapper ํ๊ทธ๋ก ์์๋๋ฉฐ, ๊ท์น์ "" ์์ ์๋ ์ฃผ์์ ๊ท์น์ ๋ฐ๋ฅธ๋ค. -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace: ์ฐ๋ํ ์ธํฐํ์ด์ค์ ํ๋ค์ -->
<mapper namespace="com.spring.mvcproject.database.mybatis.repository.PetRepository">
<!-- [๊ตฌ์กฐ]
<์ฟผ๋ฆฌ์ข
๋ฅ(insert/select/update/delete)
id="@Mapper ํด๋์ค์ ์ด๋ค ๋ฉ์๋๊ฐ ํธ์ถ๋ ๋ ์ด ์ฟผ๋ฆฌ๋ฅผ ์คํํ ๊ฒ์ธ๊ฐ"
(DB์ ์ ๋ณด๋ฅผ ์ถ์ถํ์ฌ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌํ ๊ฒฝ์ฐ) resultType="DB ๋ด์ฉ์ ์ด๋ค ํํ(๊ฐ์ฒด, int ๋ฑ)๋ก ๋ณํํ ๊ฒ์ธ๊ฐ"
>
์ฟผ๋ฆฌ๋ฌธ
(ํด๋ผ์ด์ธํธ์๊ฒ ๋ฉ์๋์ ์ธ์๋ก ๋ฐ์ ๊ฐ์ ์ฌ์ฉํ๋ ค๋ฉด, #{์ธ์} ํน์ #{์ธ์์ธ ๊ฐ์ฒด์ ํ๋๋ช
})
</์ฟผ๋ฆฌ๋ซ๊ธฐ>
-->
<insert id="save" keyProperty="id", useGeneratedKeys="true">
INSERT INTO tbl_pet
(pet_name, pet_age, injection)
VALUES
-- ํด๋ผ์ด์ธํธ์๊ฒ ๋ฉ์๋์ ์ธ์๋ก Pet์ ๋ฐ์๋๋ฐ(Pet ํด๋์ค์ save() ๋ฉ์๋ paraemter๋ณด๋ฉด Pet์ ๋ฐ์),
-- DB์ pet_Name ์นผ๋ผ์ ๊ฐ์ Values์ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌ๋ฐ์ Pet ๊ฐ์ฒด์ petName ํ๋ ๊ฐ์ผ๋ก ๋ฃ์ด๋ฌ๋ผ.
(#{petName}, #{petAge}, #{injection})
</insert>
<!-- select๋ resultType(DB๋ฅผ ์ด๋ค ๊ฒ์ผ๋ก ๋ณํํ ๊ฒ์ธ์ง๋ฅผ ํ ๋ค์์ผ๋ก) ํ์ -->
<!-- ์๋๋ com.spring.mvcproject.database.mybatis.Pet์ธ๋ฐ ๊ท์ฐฎ์ผ๋๊น ์ค์ ํ์ผ์์ type-aliases-package์ ์ง์ -->
<select id="findById" resultType="Pet">
SELECT * FROM tbl_pet
WHERE id = #{id}
-- PetRepository ์ธํฐํ์ด์ค์
-- (ํด๋น ์ธํฐํ์ด์ค๋ @Mapper๊ฐ ์ค์ ๋์ด ์์ด์ผ ํ๋ฉฐ, ์ด ํ์ผ์์๋ mapper namespace์ ํด๋น ์ธํฐํ์ด์ค๊ฐ ์ค์ ๋์ด ์์ด์ผ ํจ)
-- findById(Long id) ๋ฉ์๋๊ฐ ํธ์ธจ๋๋ฉด (id = "findById")
-- -> ํด๋น ์ฟผ๋ฆฌ๋ฅผ๋ฅผ ์คํํด๋ผ.
-- -> ์ด ๋, WHERE id = ์ ์กฐ๊ฑด์ findById(Long id)์ ์ธ์์ธ id๋ฅผ ์จ๋ผ.
-- -> ๊ทธ๋ฆฌ๊ณ next()์ ํ๋ฉด์ ํ ์ค ํ ์ค ๋์๊ฐ๋ฉด์ (resultType="Pet"์ด๋ฏ๋ก) Pet ๊ฐ์ฒด๋ก ๋ฐ๊ฟ์ค๋ผ.
</select>
}
</mapper>
๐ถ sql ์ฌํ ๊ณผ์
** 1) if๋ฌธ์ mybatis์ ์ ์ฉํ๊ธฐ ( when test , otherwise, choose )

๐ถ ์กฐํ ์ต์ ํ๋ฅผ ์ํด, Service ํด๋์ค์ @Transactional(readOnly=true)์ ํด์ค๋ค.