dependencies {
// Hibernate
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("mysql:mysql-connector-java")
...
}
spring:
datasource:
url: jdbc:mysql://<host>:<port>/<dbname>
username: <username>
password: <password>
jpa:
hibernate:
ddl-auto: update # ์ด์์์๋ validate ์ถ์ฒ
show-sql: true
- spring.jpa.hibernate.ddl-auto : sessionFactory๊ฐ ์ฌ๋ผ๊ฐ ๋, DBMS์ ์คํค๋ง๋ฅผ ์๋์ผ๋ก ์์ ํ๊ฑฐ๋ ๊ฒ์ฆํ๋ ์ค์ ๊ฐ (none/create/create-drop/update/validate)
- spring.jpa.hibernate.format_sql : ์ค์ JPA์ ๊ตฌํ์ฒด์ธ hibernate๊ฐ ๋์ํ๋ฉด์ ๋ฐ์ํ๋ SQL์ ํฌ๋งทํ
ํ์ฌ ์ถ๋ ฅ (์คํ๋๋ SQL์ ๊ฐ๋
์ฑ์ ๋์ฌ์ค)
- spring.jpa.show-sql : JPA ์ฒ๋ฆฌ ์ ๋ฐ์ํ๋ SQL Log ์ ๋ฌด (true/false)
@Entity
@Table(name="employee")
@Getter
@Setter
public class Employee {
@id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name", length = 30, nullable = false)
private String name;
}
2-1. ๊ฐ์ฒด์ ํ
์ด๋ธ ๋งคํ
- JPA๊ฐ Entity๋ก์ ๊ด๋ฆฌํ๋ค๋ ๊ฒ์ ์๋ฏธ
- ๋ค๋ฅธ Entity์ ์ถฉ๋์ด ์ฐ๋ ค๋ ๊ฒฝ์ฐ ์ด๋ฆ์ ๋ฐ๊ฟ๋ ๋๋, ๊ธฐ๋ณธ์ ์ผ๋ก๋ Class๋ช
์ ๋ฐ๋ฆ
- ๊ธฐ๋ณธ ์์ฑ์ ํ์
- final, enum, interface, inner ํด๋์ค ์ฌ์ฉ ๋ชปํจ
- ์ ์ฅ ํ๋์ final ์ฌ์ฉ ๋ชปํจ
- Entity์ ๋งคํํ DB Table์ ์ง์
- ์์ฑ
- name : ๋งคํํ table ์ด๋ฆ, ๊ธฐ๋ณธ์ Entity ์ด๋ฆ์ ์ฌ์ฉ
- catalog : catalog ๊ธฐ๋ฅ์ด ์๋ DB์์ catalog๋ฅผ ๋งคํ
- schema : schema ๊ธฐ๋ฅ์ด ์๋ DB์์ schema๋ฅผ ๋งคํ
- ์๋์ผ๋ก ์คํค๋ง๋ฅผ ์์ฑํ๋ ๊ธฐ๋ฅ์ ์๋ ๊ฐ์ ์ค์ ํจ์ผ๋ก์จ ๊ฐ๋ฅ
<property name="hibernate.hbm2ddl.auto" value="create"/>
- uniqueConstraints ์์ฑ : DDL ์์ฑ ์์ ์ ๋ํฌ ์ ์ฝ์กฐ๊ฑด์ ๋ง๋ฆ
value ์์ฑ๊ฐ ๋๋ณด๊ธฐ
- value
- create : ๊ธฐ์กด Table Drop + ์์ฑ
- create-drop : create ํ ์ข
๋ฃ ์ drop๊น์ง ์คํ
- update : ๋ณ๊ฒฝ๋ ๋ด์ฉ๋ง ์์ (JPA ์คํฉ์๋ ์๊ณ hibernate์๋ง ์๋ ์ค์ )
- validate : ๊ธฐ์กด DB Table ์ ๋ณด์ ๋น๊ตํด์ ์ฐจ์ด๊ฐ ์๋ค๋ฉด ๊ฒฝ๊ณ ํ๊ณ ์ ํ๋ฆฌ์ผ์ด์
์ ์คํํ์ง ์์(JPA ์คํฉ์๋ ์๊ณ hibernate์๋ง ์๋ ์ค์ )
- none : ์ค์ ์ด ์๊ฑฐ๋ ์ ํจํ์ง ์์ ๊ฐ์ ์ค์ ํ๋ฉด ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ์๊ฒ ๋จ
- primary key๋ฅผ ์ค์ ํ๋ ๊ฒ
- em.persist()๋ฅผ ํธ์ถํ๊ธฐ ์ ์ ์ฌ์ฉ์๊ฐ ์ง์ ID๋ฅผ ์ค์ ํ๋ ๊ฒ
Board board = new Board();
board.setId("board1");
em.persist(board);
- IDENTITY
- ๊ธฐ๋ณธํค์ ์์ฑ์ DB์ ์์ํ๋ ๊ฒ
- MySQL์ AUTO_INCREMENT์ ๊ฐ์ ๊ฒ
- @GeneratedValue(strategy = GenerationType.IDENTITY) ๋ก ์ค์ ๊ฐ๋ฅ
- SEQUENCE
- ์ ์ผํ ๊ฐ์ ์์๋๋ก ์์ฑํ๋ ํน๋ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๋ธ์ ํธ๋ฅผ ์ด์ฉํ๋ ๋ฐฉ๋ฒ
- @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = โBOARD_SEQ_GENERATORโ) ๋ก ์ค์ ๊ฐ๋ฅ
@Entity
@SequenceGenerator(
name = "BOARD_SEQ_GENERATOR",
sequenceName = "BOARD_SEQ", // ์ค์ DB์ Sequence Name
initialValue = 1,
allocationSize = 1 )
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BOARD_SEQ_GENERATOR")
private Long id;
}
- TABLE
- ํค ์์ฑ ์ ์ฉ Table์ ๋ง๋ค์ด์ ์ด๋ฅผ SEQUENCE์ฒ๋ผ ์ฌ์ฉํ๋ ๊ฒ
@Entity
@TableGenerator(
name = "BOARD_SEQ_GENERATOR",
table = "MY_SEQUENCE", // ์ค์ DB์ Table name
pkColumnValue = "BOARD_SEQ",
allocationSize = 1 )
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "BOARD_SEQ_GENERATOR")
private Long id;
}
- AUTO
- DB ์ข
๋ฅ์ ๋ฐ๋ผ JPA๊ฐ ์๋ง์ ๊ฒ์ ์ ํํ๋ ๊ฒ
- Oracle์ ๊ฒฝ์ฐ SEQUENCE, MySQL์ ๊ฒฝ์ฐ IDENTITY๋ฅผ ์ ํํ๊ฒ ๋จ
- DB ์ข
๋ฅ๊ฐ ๋ฐ๋์ด๋ ์์ค๋ฅผ ์์ ํ์ง ์์๋ ๋๋ค๋ ์ฅ์
- @GeneratedValue(strategy = GenerationType.AUTO)
2-3. ํ๋์ ์ปฌ๋ผ ๋งคํ
- ์ฌ์ฉ๋๋ ์ด๋
ธํ
์ด์
: @Column, @Enumerated, @Temporal, @Lob, @Transient, @Access
- ๊ฐ์ฒด ํ๋๋ฅผ ํ
์ด๋ธ ์ปฌ๋ผ๊ณผ ๋งคํํด์ฃผ๋ ๊ฐ์ฅ ๋ํ์ ์ธ ์ด๋
ธํ
์ด์
- name, nullable์ด ์ฃผ๋ก ์ฌ์ฉ๋จ
- ์์ฑ
- name : ๋งคํํ table ์ปฌ๋ผ ์ด๋ฆ, ๊ธฐ๋ณธ์ ๊ฐ์ฒด์ ํ๋ ์ด๋ฆ์ ์ฌ์ฉ
- insertable : ์ํฐํฐ ์ ์ฅ์ ์ด ํ๋๋ ์ ์ฅํ๋ผ๋ ์๋ฏธ๋ก ๊ธฐ๋ณธ์ true (false๋ก ํ๋ฉด Readonly์ผ๋ ์ฌ์ฉ ๊ฐ๋ฅ, ๊ฑฐ์ ์ฌ์ฉ์๋จ)
- updatable : ์ํฐํฐ ์์ ์ ์ด ํ๋๋ ์์ ํ๋ผ๋ ์๋ฏธ๋ก ๊ธฐ๋ณธ์ true (false๋ก ํ๋ฉด Readonly์ผ๋ ์ฌ์ฉ ๊ฐ๋ฅ, ๊ฑฐ์ ์ฌ์ฉ์๋จ)
- table : ํ๋์ ์ํฐํฐ๋ฅผ ๋ ๊ฐ ์ด์์ ํ
์ด๋ธ์ ๋งคํํ ๋ ์ฌ์ฉ (๊ฑฐ์ ์ฌ์ฉ์๋จ)
- nullable : false๋ก ์ค์ ํ๋ฉด DDL ์์ฑ ์์ 'NOT NULL' ์ ์ฝ์กฐ๊ฑด์ ์ถ๊ฐํด์ค
- unique : @Table ์ uniqueConstraints์ ๊ฐ์ง๋ง ํ ์ปฌ๋ผ์ ๋ํด์ ์ ์ฉํ ๋๋ ๊ฐ๋จํ๊ฒ ์ด๊ฑธ ์ด์ฉ ๊ฐ๋ฅ (๋จ ์ฌ๋ฌ ์ปฌ๋ผ์ ์ฌ์ฉํ ๋๋ @Table์ uniqueConstraints๋ฅผ ์ฌ์ฉํด์ผ ํจ)
- columnDefinition : ์ฌ์ฉ์๊ฐ ์ง์ ์ปฌ๋ผ์ ์ ๋ณด๋ฅผ ์
๋ ฅํด์ค
- length : ๋ฌธ์ ๊ธธ์ด์ ๋ํ ์ ์ฝ์กฐ๊ฑด (String ํ์
์๋ง ์ ์ฉ๋๋ฉฐ ๊ธฐ๋ณธ๊ฐ์ 255)
- precision, scale : BigDecimal ํ์
์์ ์ฌ์ฉ๋จ (precision์ ์์์ ์ ํฌํจํ ์ ์ฒด ์ง๋ฆฟ์, scale์ ์์ ์๋ฆฌ์๋ฅผ ์๋ฏธ) (0float, double์๋ ํด๋น๋์ง ์์)
์ด๋
ธํ
์ด์
๋๋ณด๊ธฐ
- enum ํ์
์ ๋งคํํ ๋ ์ฌ์ฉ
- ์์ฑ
- name
- EnumType.ORDINAL : enum์ ์์๋ฅผ DB์ ์ ์ฅ, ์ด๊ฐ์ด Default (์ซ์๋ก ์ ์ฅ๋๋ฏ๋ก ๋ฐ์ดํฐ ํฌ๊ธฐ๊ฐ ์์์ง๊ณ ๋น ๋ฅด์ง๋ง enum์ ์์๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ ๋จ์ )
- EnumType.STRING : enum ์ด๋ฆ์ DB์ ์ ์ฅ (๋ฌธ์๋ก ์ ์ฅ๋๋ฏ๋ก ๋ฐ์ดํฐ ํฌ๊ธฐ๊ฐ ์ปค์ง๊ณ ๋๋ฆฌ์ง๋ง enum์ ์์์ ์๊ด ์์ด ์ฌ์ฉ ๊ฐ๋ฅ) (Default๋ ORDINAL์ด์ง๋ง STRING์ ๋ ์ถ์ฒ)
- ๋ ์ง ํ์
๋งคํ ์ ์ฌ์ฉ ์์ฑ์ ์
๋ ฅํ์ง ์์ผ๋ฉด ์๋ฐ์ Date๊ณผ ๊ฐ์ฅ ์ ์ฌํ Timestamp๋ก ์ ์ฅ๋จ(H2, Oracle, PostgreSQL)
- DB์ ์ข
๋ฅ์ ๋ฐ๋ผ Datetime์ผ๋ก ์ ์ฅ๋๊ธฐ๋ ํจ(MySQL)
- ์์ฑ
- value
- TemporalType.DATE : 2013-01-23 ์ ๊ฐ์ ๋ ์ง ํ์
- TemporalType.TIME : 11:23:18 ๊ณผ ๊ฐ์ ์๊ฐ ํ์
- TemporalType.TIMESTAMP : 2013-01-23 11:23:18 ๊ณผ ๊ฐ์ด DB์ Timestamp ํ์
๊ณผ ๋งคํ
- ๋ณ๋์ ์์ฑ์ ์์
- ๋ฌธ์์ด์ด๋ฉด CLOB, ๊ทธ์ธ์ ํ์
์๋ BLOB์ผ๋ก ๋งคํ
- ์ด ํ๋๋ ๋งคํํ์ง ๋ง๋ผ๋ ์๋ฏธ (์์๋ก ์ค๊ฐ ๊ฐ์ ์ ์ฅํ๋ ์ฉ๋๋ก ์ฌ์ฉ ๊ฐ๋ฅ)
- JPA๊ฐ ์ํฐํฐ ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ ๋ฐฉ์
- @Access๋ฅผ ์ค์ ํ์ง ์์ผ๋ฉด @Id์ ์ค์ ์์น์ ๋ฐ๋ผ ์ ๊ทผ ๋ฐฉ์์ด ๊ฒฐ์ ๋จ
- @Id๊ฐ ํ๋์ ๋ถ์ด ์์ผ๋ฉด FIELD์ ๊ทผ ๋ฐฉ์์ ์๋ฏธํ๋ฏ๋ก Getter๊ฐ ์์ด๋ ๋๋ฉฐ, ํ๋กํผํฐ์ ์์ผ๋ฉด PROPERTY์ ๊ทผ ๋ฐฉ์์ ์๋ฏธ
- ์์ ๋ ๊ฐ์ง ๋ฐฉ์์ ์์ด์ ์ฌ์ฉ๋ ๊ฐ๋ฅ
- AccessType.FIELD : ํ๋ ์ ๊ทผ, Private์ด์ด๋ ์ ๊ทผ ๊ฐ๋ฅํ๋ค.
- AccessType.PROPERTY : ํ๋กํผํฐ ์ ๊ทผ, ์ ๊ทผ์(Getter)๋ฅผ ์ด์ฉํ๋ค.
3. EmployeeController.java
@Controller
public class EmployeeController {
private EmployeeService employeeService;
@Autowired
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
@PostMapping("/employee")
public @ResponseBody Result addEmployee(@RequestBody Employee employee) {
return employeeService.addEmployee(employee);
}
@GetMapping("/employees")
public @ResponseBody Result getEmployees() {
return employeeService.getEmployees();
}
@GetMapping("/employees/{id}")
public @ResponseBody Result getEmployeeById(@PathVariable Long id) {
return employeeService.getEmployeeById(id);
}
@PutMapping("/employees/{id}")
public @ResponseBody Result updateEmployeeById(@PathVariable Long id, @RequestBody Employee employee) {
return employeeService.updateEmployeeById(id, employee);
}
@DeleteMapping("/employees/{id}")
public @ResponseBody Result deleteEmployeeById(@PathVariable Long id) {
return employeeService.deleteEmployeeById(id);
}
}
4. EmployeeServiceImplement.java
@Service
public class EmployeeServiceImplement implements EmployeeService {
private EmployeeRepository employeeRepository;
@Autowired
public EmployeeServiceImplement(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
@Override
public Result addEmployee(Employee employee) {
employeeRepository.save(employee);
return new Result(ResultCode.OK);
}
@Override
public Result getEmployees() {
Result result = new Result(ResultCode.OK);
result.setData(employeeRepository.findAll());
return result;
}
@Override
public Result getEmployeeById(Long id) {
Result result = new Result(ResultCode.OK);
result.setData(employeeRepository.findEmployeeById(id));
return result;
}
@Override
public Result updateEmployeeById(Long id, Employee employee) {
employee.setId(id);
employeeRepository.save(employee);
return new Result(ResultCode.OK);
}
@Override
public Result deleteEmployeeById(Long id) {
employeeRepository.deleteById(id);
return new Result(ResultCode.OK);
}
}
5. EmployeeRepository.java
- CrudRepository : ๊ธฐ๋ณธ CRUD ์ ๊ณต (extends Repository)
- PagingAndSortingRepository : pagination, sorting ์ ๊ณต (extends CrudRepository)
- JpaRepository : flush, deleting records in a batch ์ ๊ฐ์ ํจ์ ์ ๊ณต (extends PagingAndSortingRepository, QueryByExampleExecutor)
@Transactional
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
Employee findEmployeeById(Long id);
List<Employee> findEmployeeByName(String name);
}
- Unable to build Hibernate SessionFactory
- hibernate.ddl-auto ์ validate ์ค์ ์ ์ฌ์ฉํ๋ค๋ณด๋ฉด [PersistenceUnit: default] Unable to build Hibernate SessionFactory ์๋ฌ๋ฅผ ๋ณด๊ฒ ๋จ
- PersistenceUnit ์๋ฌ๋ ๋์ฒด์ ์ผ๋ก ์ฝ๋ ๋ถ๋ถ๊ณผ DB์ ํ๋ ๋ถ๋ถ์ด ์ผ์นํ์ง ์์ ๋ ๋ฐ์
- create table ์์ type ์ int ๋ก ํด๋จ๋๋ฐ Entity๋ Long ์ผ๋ก ์ค์ ํ์ ๋ (Long => bigint)
- type char ์ธ๋ฐ, Entity๋ String (String => varchar)
- auto_increment ์ค์ ์ธ๋ฐ AUTO๋ฅผ ์ฌ์ฉํจ (ENTITY => auto_increment)