javax.sql.DataSourceext{
springVersion = '6.1.10'
}
dependencies {
implementation "org.springframework:spring-context:$springVersion" //Spring context
implementation "org.springframework:spring-jdbc:$springVersion" //Spring jdbc
implementation 'org.apache.tomcat:tomcat-jdbc:10.1.25' //Tomcat jdbc
runtimeOnly 'com.oracle.database.jdbc:ojdbc11:23.4.0.24.05' //ojdbc11
compileOnly 'org.projectlombok:lombok:1.18.34' //lombok
annotationProcessor 'org.projectlombok:lombok:1.18.34' //lombok
implementation 'org.slf4j:slf4j-api:2.0.13' //slf4j api
implementation 'ch.qos.logback:logback-classic:1.5.6' //logback 구현체
testImplementation "org.springframework:spring-test:$springVersion" //Spring test
}
javax.sql.DataSource
데이터를 조회하는 SQL(SELECT)
List query(String sql, RowMapper rowMapper)List query(String sql, Object[] args, RowMapper rowMapper)List query(String sql, RowMapper rowMapper, Object... args)@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppCtx.class)
public class Ex01 {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
void test2(){
List<Member> members = jdbcTemplate.query("SELECT * FROM MEMBER", new BeanPropertyRowMapper<Member>(){
@Override
public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
return Member.builder()
.seq(rs.getLong("SEQ"))
.email(rs.getString("EMAIL"))
.password(rs.getString("PASSWORD"))
.userName(rs.getString("USER_NAME"))
.regDt(rs.getTimestamp("REG_DT").toLocalDateTime())
.build();
}
});
members.forEach(System.out::println);
}
@Test
void test2(){
List<Member> members = jdbcTemplate.query("SELECT * FROM MEMBER",
(rs, num) -> Member.builder()
.seq(rs.getLong("SEQ"))
.email(rs.getString("EMAIL"))
.password(rs.getString("PASSWORD"))
.userName(rs.getString("USER_NAME"))
.regDt(rs.getTimestamp("REG_DT").toLocalDateTime())
.build());
members.forEach(System.out::println);
}
}
단일 데이터 조회, 조회 데이터가 반드시 1개이어야한다. 그렇지 않으면 예외가 발생
그렇기 때문에 try catch를 사용해서 사용
@Test
void test3(){
String email = "user01@test.org";
Member member = jdbcTemplate.queryForObject("SELECT * FROM MEMBER WHERE EMAIL = ?",
(rs, num) -> Member.builder()
.seq(rs.getLong("SEQ"))
.email(rs.getString("EMAIL"))
.password(rs.getString("PASSWORD"))
.userName(rs.getString("USER_NAME"))
.regDt(rs.getTimestamp("REG_DT").toLocalDateTime())
.build(), email);
System.out.println(member);
}
@Test
void test4(){
int total = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM MEMBER", Integer.class);
System.out.println(total);
}
데이터를 변경을 가하는 SQL(INSERT, DELETE, UPDATE : 반환값 - 반영된 레코드 갯수)
int update(String sql)int update(String sql, Object... args)@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppCtx.class)
public class Ex01 {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
void test1(){
String sql = "INSERT INTO MEMBER (SEQ, EMAIL, PASSWORD, USER_NAME) VALUES (SEQ_MEMBER.NEXTVAL, ?, ?, ?)";
int result = jdbcTemplate.update(sql,"user03@test.org","123456","사용자03");
System.out.println(result);
}
}
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppCtx.class)
public class Ex01 {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
void test2(){
List<Member> members = jdbcTemplate.query("SELECT * FROM MEMBER", this::mapper); //메서드참조 이용
members.forEach(System.out::println);
}
@Test
void test3(){
String email = "user01@test.org";
Member member = jdbcTemplate.queryForObject("SELECT * FROM MEMBER WHERE EMAIL = ?", this::mapper, email);
System.out.println(member);
}
private Member mapper(ResultSet rs, int num) throws SQLException {
return Member.builder()
.seq(rs.getLong("SEQ"))
.email(rs.getString("EMAIL"))
.password(rs.getString("PASSWORD"))
.userName(rs.getString("USER_NAME"))
.regDt(rs.getTimestamp("REG_DT").toLocalDateTime())
.build();
}
}
slf4j-api
logback classic
의존성
Connection 객체 매개변수로 정의되어 있는 메서드를 통해서 사용 가능
증감 번호 형태의 PK를 조회
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppCtx.class)
public class Ex01 {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private DataSource dataSource;
@Test
void test1(){
KeyHolder keyHolder = new GeneratedKeyHolder();
int result = jdbcTemplate.update(con -> {
String sql = "INSERT INTO MEMBER (SEQ, EMAIL, PASSWORD, USER_NAME)"+
"VALUES (SEQ_MEMBER.NEXTVAL, ?, ?, ?)";
PreparedStatement pstmt = con.prepareStatement(sql, new String[]{"SEQ"});
pstmt.setString(1,"user05@test.org");
pstmt.setString(2,"12345678");
pstmt.setString(3,"사용자05");
return pstmt;
}, keyHolder);
System.out.println(result);
Number key = keyHolder.getKey();
long seq = key.longValue();
System.out.println(seq);
}
}
각 연동 기술에 따라 발생하는 익셉션을 스프링이 제공하는 익셉션으로 변환함으로써 다음과 같이 구현 기술에 상관없이 동일한 코드로 익셉션을 처리할 수 있게 된다.
SQLExcpetion, HibernateException, PersistenceException 👉 DataAccessException (RuntimeException)
수동관리
@Transactional : 클래스명 위, 메서드명 위
여러 쿼리를 하나로 묶어 하나의 트랜잭션을 처리함.
쿼리 중 하나라도 오류가 발생한다면 모든 쿼리를 커밋하지않는다.Connection setAutoCommit(false) SQL1... SQL2... SQL3... Connection commit();