spring.jpa.hibernate.ddl-auto=create #테이블 자동생성 해줌. 한 번 테이블 생성된 후에는 주석처리하기
spring.jpa.properties.show_sql:true
spring.jpa.properties.format_sql:true
logging.level.org.hibernate.SQL:debug
(VO와 같은 것)
@Entity
@Data
@Table(name="book")
public class BookVO {
@Id
private int bookid;
private String bookname;
private String publisher;
private int price;
}
@Entity :이 테이블을 만들어줌.
@Table(name=”book") : 테이블 이름을 book으로 지정. 이걸 안 하면 클래스 이름으로 테이블 만들어줌
@Id: 테이블의 pk
@Entity
@Data
@Table(name="customer")
public class CustomerVO {
@Id
private int custid;
private String name;
private String address;
private String phone;
}
(Book, Customer 테이블 join)
@Entity
@Data
@Table(name="orders")
public class OrdersVO {
@Id
private int orderid;
@ManyToOne
@JoinColumn(name="custid",insertable=true,updatable=true)
private CustomerVO customerVO;
@ManyToOne
@JoinColumn(name="bookid",insertable=true,updatable=true)
private BookVO bookVO;
private int saleprice;
private String orderdate;
}
(book, customer 테이블과 join해서 custid, bookid 대신 name(고객이름)과 bookname이 바로 보이게 만든 뷰)
@Entity
@Data
@Table(name="view_listorders")
public class View_ListOrders {
@Id
private int orderid;
private String name;
private String bookname;
private String orderdate;
private int saleprice,price;
}
or
orderid 대신 name과 bookname을 합친 OrdersViewID를 Primary key로 사용할 수도 있다.
그러기 위해 OrdersViewID라는 class를 만들어 준다.
@Embeddable
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrdersViewID implements Serializable {
@Column(name="name")
private String name;
@Column(name="bookname")
private String bookname;
}
❓ Serializable:
JVM에 이 클래스는 직렬화(Serialization)하라고 알려주는 인터페이스.
자바 직렬화: 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술과 바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)을 아울러서 말한다.
간단히 말하면 해당 클래스를 HashMap, ArrayList처럼 만들어 준다.
@Column(name="name") = DB에서의 컬럼 이름이 name이다.
@Embeddable : 여러 개의 칼럼을 합쳐서 하나의 칼럼으로 만들려고 할 때, 그 하나의 칼럼(여기서는 OrdersViewID)을 클래스로 만들어서 이 어노테이션을 붙인다.
Entity에서 이 칼럼을 호출해 멤버변수로 사용할 때에는 @EmbeddedId 라는 어노테이션을 붙인다.
@Entity
@Data
@Table(name="view_listorders2")
public class View_ListOrders2 {
@EmbeddedId
private OrdersViewID id;
private String orderdate;
private int saleprice,price;
}
@Transient: DB에 테이블 자동 생성할 때 들어가지 말아야 할 칼럼을 지정하는 어노테이션
public interface {DAO이름} extends JpaRepository<{엔티티 클래스}, {PK 타입}>
@Repository
public interface BookDAO extends JpaRepository<BookVO, Integer>{
}
기본 CRUD는 메소드를 따로 생성하지 않아도 기본으로 제공함.
bookname이 뫄뫄인 거 찾기 (메소드 내용은 안 써도 됨)
public List<BookVO> findByBookname(String Bookname);
bookname에 뫄뫄가 포함된 것 찾기
public List<BookVO> findByBooknameContaining(String bookname);
bookid가 뫄뫄보다 큰 거 찾기
public List<BookVO> findByBookidGreaterThan(int bookid);
쿼리문 사용
@Query("select nvl(max(orderid),0) +1 from OrdersVO")
public int getNextNo();
@Modifying
@Query(value="insert into orders o(o.orderid,o.custid,o.bookid,o.saleprice,orderdate) values(:#{#o.orderid},:#{#o.customerVO.custid},:#{#o.bookVO.bookid},:#{#o.saleprice},sysdate)",nativeQuery=true)
@Transactional
public void insert(@Param("o") OrdersVO o);
@Param : 파라미터로 넘어온 값을 변수로 지정
nativeQuery=true : 기존의 데이터베이스에서 사용하던 쿼리를 그대로 사용
@Transactional: 데이터베이스의 상태를 변경하는 작업을 할 때 사용. begin, commit을 자동으로 해주고 예외 발생시 rollback 해준다.
파라미터로 넘어온 값을 쿼리문에서 사용할 때 아래처럼 매개변수 순서대로 ?1 ?2 … 이렇게 쓰거나 위 예시처럼 @Param 사용해서 이름을 지정해줌
@Query(value="select c.* from (select rownum r, a.* from (select * from Board b order by b.b_ref desc, b.b_step asc) a) c where c.r between ?1 and ?2", nativeQuery=true)
public List<Board> selectAll(int start,int end);
param을 사용할 때 (1) 객체 자체를 넘길 수도 있고 (2) 필드 값들을 넘겨줄 수도 있음
(1)
쿼리문 안에서 쓸 이름을 지정하기 : @Param(”지정할 객체이름”) 타입 객체명
쿼리문 안에서 쓸 때: :#{#객체이름.칼럼이름}
@Modi..
@Query("update User set name = :#{#paramUser.name}, age = :#{#paramUser.age}, ssn = :#{#paramUser.ssn} where id = :#{#paramUser.id}")
int updateSpecificAttribute(@Param("paramUser") User user );
(2)
쿼리문 안에서 쓸 이름을 지정하기 : @Param(”지정할 객체이름”) 타입 객체명
쿼리문 안에서 쓸 때: :변수명
@Modi..
@Query("update User set name = :name, age = :age, ssn = :ssn where id = :id")
int updateSpecificAttribute(@Param("name") String name, @Param("age") Integer age, @Param("ssn") String ssn, @Param("id") Long id );
public List<BookVO> findAll(){
return dao.findAll();
}
public void save(BookVO b) {
dao.save(b);
}
save: 주어진 vo의 pk값에 해당하는 레코드가 없으면 새로 추가, 있으면 있는 걸 수정해줌
public Optional<BookVO> findById(int bookid) {
return dao.findById(bookid);
}
findById()는 return type이 Optional<VO>임. 해당 id로 vo를 찾을 수 없어도 예외가 발생하지 않음.
Optional 타입의 객체는 get()을 하면 그 안의 vo(or anything in that optional object)를 리턴해줌. (Controller에서 처리)
public void delete(int bookid) {
dao.deleteById(bookid);
}
@RequestMapping("/book/list")
public void list(Model model, String keyword, String col, HttpServletRequest request) {
//Get 방식일 경우
if(request.getMethod().equals("GET")) {
model.addAttribute("list",bs.findAll());
//Post 방식일 경우 (검색어 제출했을 경우)
}else {
model.addAttribute("list",bs.search(keyword,col));
}
}
@GetMapping("/customer/update/{custid}")
public ModelAndView update(@PathVariable int custid) {
ModelAndView mav=new ModelAndView("/customer/update"); //뷰페이지로 다시 돌아가게 해줌. 이거 안 하면 없는 페이지로 돌아감. (예를 들어 전달해준 custid가 5면 /customer/update/5로 가는데 여기에 해당하는 뷰페이지가 없으므로 404에러 뜸)
mav.addObject("c",cs.findById(custid).get());
return mav;
}
Optional<Member> option=dao.findById(id);
if(option.isPresent()) {
//레코드가 존재할 때 수행할 코드
}else {
//레코드가 존재하지 않을 때 수행할 코드
}
view(DB)를 사용하지 않았을 경우 상태유지한 변수 불러오기
<tr th:each="o:${list}">
<td th:text="${o.orderid}"></td>
<td th:text="${o.customerVO.name}"></td>
<td th:text="${o.bookVO.bookname}"></td>
<td th:text="${o.orderdate}"></td>
<td th:text="${o.saleprice}"></td>
<td th:text="${o.bookVO.price}"></td>
</tr>
view 테이블을 만들어서 ordersViewID를 pk로 사용했을 경우 상태유지한 변수 불러오기
<tr th:each="o:${list}">
<td th:text="${o.id.name}"></td>
<td th:text="${o.id.bookname}"></td>
<td th:text="${o.orderdate}"></td>
<td th:text="${o.saleprice}"></td>
<td th:text="${o.price}"></td>
</tr>
view 테이블을 만들고 ordersViewID 사용 x일 경우 (ordersid가 pk)
<tr th:each="v:${list}">
<td th:text="${v.orderid}"></td>
<td th:text="${v.name}"></td>
<td th:text="${v.bookname}"></td>
<td th:text="${v.orderdate}"></td>
<td th:text="${v.saleprice}"></td>
<td th:text="${v.price}"></td>
</tr>
member의 id를 board의 writer와 조인
entity
member의 필드로 board의 리스트를 넣기
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import lombok.Data;
@Entity
@Data
@Table(name="member")
public class Member {
@Id
private String id;
private String pwd,name,role;
@OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
private List<Board> board;
}
FetchType.EAGER: 부모 요청할 때 자식도 읽어들이기
FetchType.LAZY: 나중에 자식 요청할 때 읽어들이기
board의 필드로 Member를 넣기
@Entity
@Data
@Table(name="board")
public class Board {
@Id
private int no;
private String title, pwd, content;
private Date regdate;
private int hit;
private String ip;
private int b_ref,b_step,b_level;
@Transient //DB에는 이 칼럼 만들지 말라는 뜻
private MultipartFile uploadFile;
private String fname;
@ManyToOne
@JoinColumn(name="id", insertable = true, updatable = true)
private Member member;
}
@OneToMany안에 cascade=CascadeType.REMOVE => 부모 레코드를 지우면 자식레코드도 같이 지워짐.
이걸 안 하면 자식 있으면 삭제가 안 됨