Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

항목DBJPA객체설명
Table(Class)sample_tableSampleTable헝가리 표기법을따름
Field(member)samplenamesample_namesampleName카멜표기법을 따름




db가 설치된 os에따라 대소문자를 구분하는 경우가 있기때문에

...

JPA에서는 CrudRepository를 이용하여 조금더 객체 지향접근방식을 통해 Database를 제어할수가 있습니다.

User란 테이블을 User테이블을 제어하는 객체를 정의하기 위해서, 여기서는 UserRepository 라고 정의를 하였습니다.

...

Code Block
languagejava
themeEmacs
titleUse Case
package com.psmon.springdb;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class JparestdemoApplicationTests {
	
	@Autowired
	private UserRepository userRepository;

	@Test
	public void contextLoads() {		
		jpaTest1();		
	}
	
	public void jpaTest1() {
		// 사용자 생성
		User addUser = new User();
		addUser.setName("minsu");
		addUser.setEmail("test@x.com");
		userRepository.save(addUser);
		
		// 사용자 조회
		Iterable<User> userList = userRepository.findAll();		
		userList.forEach(item->System.out.println(item.getName() ));		
	}
}


위 코드를 SQL문으로 변환하면 아래와 같으며, 위코드는 실제 아래와같은 SQL문을 실행합니다. 

Code Block
languagesql
themeEmacs
-- 사용자생성
INSERT INTO `spring`.`user`
(`id`,
`email`,
`name`)
VALUES
(<{id:}>,
<{email: >,
<{name:}>);

-- 사용자 조회
SELECT * FROM user

...

일반적으로 DB의 테이블은 하나의 테이블에 모든 정보를 포함하지 않고포함하여 설계하지않고,

데이터의 효율적인 관리를 위해서 몇개의 테이블구조로 나누어 관계를 형성하게 나누어 저장후 외래키로 연관관계 형성을하게 됩니다. 

이렇게 구조적으로 나뉜 테이블을 하나의 테이블정보인것처럼 정보를 머지를 하려면 JOIN을 통해 테이블을 지배해야합니다.

JPA 객체처리모델에서는 SQL문의 JOIN문을 직접적으로 사용하지 않고, 동일한 효과를 내려고 합니다.

그 목적을 달성하기위해 데이터베이스와 데이터베이스의 테이블과 객체지향의 몇가지 차이점을 알아야합니다.

Class VS Table

...

DB는 구조상, 하나의 테이블에서 서브 List형태의 데이터를 가질수가 없습니다.

각각의 테이블에서 그룹정보 / 사용자정보를  각각 따로 입력해야하며 .. 조회시 Join을 통해

그룹정보가 사용자리스트를 가진것처럼 핸들링을 할수 있을뿐이며, 외래키를 통해

실제 이러한 구조에 무결성을 유지할수가 있습니다.

전통적인 방식에서는 대략 아래와같이, 처리하였을것입니다집합을 만들어야합니다.

Code Block
languagesql
themeEmacs
-- 그룹을 추가한다.
INSERT INTO test.group_info(
   group_id
  ,name
) VALUES (
   NULL -- group_id - IN int(11)
  ,''  -- name - IN varchar(255)
)


-- 사용자를 추가할시 그룹을 지정하거나, 나중에 지정한다.
INSERT INTO test.user(
   user_id
  ,email
  ,name
  ,group_id
) VALUES (
   NULL -- user_id - IN int(11)
  ,''  -- email - IN varchar(255)
  ,''  -- name - IN varchar(255)
  ,0   -- group_id - IN int(11)
)


-- 여러명을 등록할시 위 과정이 반복됩니다.




--학생인 사용자만 조회시..Join을 통해 해결
select * from user join group_info gi on gi.name='학생'

...

각종 Join(Inner,Left,Right....)에 대응하는 JPA Relation 키워드기능을  잘 파악해둬야합니다.

SQL Join의 자유로운 표현력만큼 표현력에 비해 ,JPA는 분명 제약적입니다. 

객체 지향적 설계가 어떠한 Join문을 실제 작동시키게될지? 성능적으로 어떠한 전략을 택해야할지?

오브젝트 설계시 고려가 되지 못하면, Join 기능을 사용못하는 사용조차 할수없는 답답함이 생길수도 있습니다.

이것을 장점으로 받아들일지? 단점으로 생각해야할지? JPA를 선택하는 중요한 사안이될수 있습니다.

...

Code Block
languagejava
themeEmacs
titleTest
GroupInfo newGroupA = new GroupInfo("학생");
Set usersA = new HashSet<User>() {{
	add(new User("minsu2","min2@x.com",newGroupA));			
	add(new User("minsu3","min3@x.com",newGroupA));
}};
newGroupA.setUsers(usersA);

GroupInfo newGroupB = new GroupInfo("선생");
Set usersB = new HashSet<User>() {{
	add(new User("tom1","tom1@x.com",newGroupB));			
	add(new User("tom2","tom2@x.com",newGroupB));
}};
newGroupB.setUsers(usersB);

    groupRepository.save(new HashSet<GroupInfo>() {{
    	add(newGroupA);
    	add(newGroupB);        	
    }});
    

GroupInfo groupInfo = groupRepository.findByName("학생");        
    System.out.println( String.format("학생정보: %s", groupInfo.toString() ) );

위 테스트 코드는, 각각의 그룹을 생성을 하고  일괄적인 방법으로 사용자를 추가하였습니다.

마지막에는 Join문 필요없이 학생그룹의 사용자들의 목록을 읽어온는 함수를 실행하였습니다.

일반적으로 사용자에 반응을 하여 1건의 자료 처리가 되는 방식에서 위와같이 한꺼번에

데이터를 넣을 일은 없을것이나, Insert처리 조회처리를 일괄적이고 효과적인 방법으로 할수 있다란 

하고 사용자까지 Group에 포함하여 저장하는 방식을

사용하였습니다. 전형적인 객체 지향적인 접근 방식이며

최종 save명령을 통해, 실질적인 저장쿼리가 순차적으로 모두 반영을 할것입니다.

또한 마지막에는, 그룹명을 통해 학생리스트를 조회하는 명령을 조인을통한 테이블 집합변경

없이 수행하였습니다. ( 물론 , 실제 이 조회명령을 수행하기위해 Join문이 작동됩니다.)예일뿐입니다.


Paging 처리

JPA MODE

Code Block
languagejava
themeEmacs
public interface UserPageRepo extends Repository<User, Long>{

	Optional<User> findOne(Long id);
	
	// 전체 페이징처리
	Page<User> findAll(Pageable pageRequest);
	
	// 검색 확장-그룹명으로 페이지 필터
	Page<User> findByGroupInfoName(String groupName,Pageable pageRequest);
		
	// Update
	void delete(User deleted);
	
	User save(User persisted);
	
	void flush();
}

SQL문 쿼리없이, 검색조건/필터조건등을 지정하여 페이징 처리가 가능합니다.전통적인 방식은, 검색인자값을 결합하여 sql문을 빌드하여 쿼리실행을 하였지만.

JPA에서는 가변적인 함수처리로, SQL문의 복합적인 페이징처리가 고려된 복합 검색 연산조합처리가 연산조합처리 모두가능합니다.

  • JPA함수 : findBy{필드명A}OrfindBy{필드명B}AndfindBy{필드명C}(....인자값);
  • SQL문 : where 필드명A=인자값A or 필드명B=인자값B and 필드명C

...

Code Block
languagejava
themeEmacs
		//Test를 위해 100개의 데이터 인입
		GroupInfo newGroupA = new GroupInfo("학생");
		Set usersA = new HashSet<User>() {{
			for(int i=0; i<100 ; i++) {
				String userName = String.format("minsu%d", i);
				String email = String.format("min%d@x.com", i);
				add(new User(userName,email,newGroupA));
			}					
		}};
		newGroupA.setUsers(usersA);
        groupRepository.save(new HashSet<GroupInfo>() {{
        	add(newGroupA);
        }});


		//원하는 페이지를 조회합니다.( 페이지번호 , 페이지당 처리수)
        PageRequest  pageRequest =  new PageRequest(1,10);                       
        Page<User> sPage = userPageRepo.findAll(pageRequest);
        System.out.println( String.format(" %d:Contents %d:Page", sPage.getNumberOfElements(),sPage.getNumber() ) );
        
        Page<User> sPage2 = userPageRepo.findByGroupInfoName("학생", pageRequest);
        System.out.println( String.format(" %d:Contents %d:Page", sPage2.getNumberOfElements(),sPage2.getNumber() ) );

...


JPQL MODE

Code Block
languagejava
themeEmacs
public interface UserPageRepo extends Repository<User, Long>{

	// QueryMode
	@Query(value="select t from User t "			
			+ "where  t.name =:name  "
			+ "order by t.id " , nativeQuery=false )
	List<User> findBySomeName( @Param("name") String name, Pageable pageable);
	
}

JPA의 함수처리방식이 익숙하지 않다면, SQL방식으로 인터페이스 작성도 가능합니다.

...


JPQL VS SQL(Native)

JQL은 JPQL은 JPA와 연동되어 일반적으로 대부분의 DB에 호환이되는 다소 제약적인 쿼리사용이 가능하지만가능합니다.

JPQL의 공통된 인터페이스, JQL의 준비된 인터페이스 예를 들면 데이터를 나뉘는 파티션 인터페이스인 페이징처리를 SQL문없이

가능합니다. 이것은 이러한 인터페이스가 각 DB특성에 맞게 변환해줄수 있으며

페이징처리를 

각 DB에 맞게끔 모두 처리가가능합니다.

이와 반대로  SQL(Native) 모드로 사용시 특정 DB가가진 SQL특성 사용 가능하지만사용도가능하며, DB변경시 호환이 깨질수 있습니다.

예를 들어 페이징을 위해 Mysql에만 있는 페이징처리를 위해 Limit기능을 사용할수 있지만

공통 인터페이스인 JPA의 페이징 인터페이스를 사용할수 없습니다DB변경시 관련 SQL문을 지원하지 않는다면, 작동하지 않을것입니다.

nativeQuery , true/flase에따라 작동방식이 변경됩니다변경가능하며 , 특수한 경우가 아니면

JPQL사용이 권장됩니다.



Info

다른 진영(.net) 에서도 JPA와 유사하게 데이터를 제어하고 있습니다.

Entity Framework

https://docs.microsoft.com/en-us/ef/core/

...