Entity는 DB의 테이블과 매칭되는 개념이라고 보면 된다.
예를들어 Database에 id, name, age를 필드 값으로 가지고 있는
Member 테이블을 CREATE 하려면 아래와 같은 QUERY로 작성해야한다.
CREATE TABLE `Member` (
`id` BIGINT(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
하지만 JPA를 통해 위의 쿼리문을 Java 코드로 만들면 아래 코드와 같다.
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(nullable = false)
private long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private int age;
... Getter, Setter
}
기본적으로 JPA는 모든 필드(id, name, age)를 불러오게 구현되어있다.
하지만, 모든 케이스에서 모든 필드를 다루지 않고, id, name 필드만 다루는 경우가 있을 수 있다.
@Entity
@Table(name = "Member")
public class MemberOnlyName {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(nullable = false)
private long id;
@Column(nullable = false)
private String name;
... Getter, Setter
}
따라서 Member 테이블은 1개이지만, Entity는 경우에 따라 여러개를 만들 수 있다.

EntityManager는 위에 언급한 Entity를 관리(CRUD = 저장, 조회, 수정, 삭제)하는 역할을 수행하는 클래스이다.
말 그대로 Entity를 저장하는 가상의 DB로 생각하면 된다.
DB를 하나만 사용하는 애플리케이션은 일반적으로 EntityManagerFactory를 1개만 생성한다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("해당이름");
EntityManager em = emf.createEntityManager();
위의 코드를 통해 EntityManagerFactory를 통해 필요할 때마다 EntityManager를 생산할 수 있다.
이렇게 생성된 EntityManager는 DB 연결이 필요하기 전까지 Connection을 얻지 않는다.
Hibernate를 포함한 JPA 구현체들은
EntityManagerFactory를 생성할 때 DB Connection 풀도 함께 만드는데,
해당 정보는 1) maven project인지 2) spring project인지에 따라 설정 방법이 다르다.
Maven Project인 경우 resources - META-INF 폴더 하단에 persistence.xml 파일을 생성하여 DB를 설정해 줘야했다.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="jpa3"> <!-- 프로젝트 이름 -->
<properties>
<!-- DB와 연결하기 위한 필수 속성 -->
<!-- MySQL 설정 -->
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/testdb?serverTimezone=UTC"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
<!-- DB Dialect(방언) 설정(MySQL) -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<!-- 옵션(선택) 속성 -->
<!-- hiberante의 실행 과정에서 콘솔에 테이블 생성, DDL, DML 등 SQL문을 출력하도록 -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
</persistence>
[참고]
<persistence-unit name="jpa3"> 에서 name이 프로젝트 명과 동일해야 한다!
<property name="hibernate.hbm2ddl.auto" value="create"/> 에서 TABLE을 CREATE하고 난 뒤에는, update로 변경해줘야 한다!
: "create"를 사용하면 존재하는 테이블을 DROP한 뒤, 새로운 테이블을 CREATE 한다.
resources 하단의 application.properties 파일에 DB를 설정해줘야했다. (MySQl 사용)

[참고]
spring.datasource.url=jdbc:mysql://localhost:3306/testdb?serverTimezone=UTC 에서 testdb로 설정되어 있기 때문에,testdb DB에 저장된다. 
spring.jpa.hibernate.ddl-auto=create 로 서버를 한 번 실행 해준 뒤, create를 update로 변경해주어야 기존 TABLE이 DROP되지 않는다.EntityManager는 내부에 존재하는 영속성 컨텍스트(Persistence Context) 에 엔티티들을 관리한다.

영속성 컨텍스트 = "엔티티를 영구 저장하는 환경"이라는 뜻이다.
하지만 개발자가 직접 영속성 컨텍스트를 뜯어보거나 그 내부를 들여다 볼 수는 없어서, 약간은 논리적이거나 추상적인 개념으로 바라봐야 한다.
EntityManager로 엔티티를 저장하거나, 조회하면
EntityManager는 영속성 컨텍스트(Persistence Context)에 엔티티를 보관하고 관리한다.
public class Join {
public void join(String name, int age) {
// 아직까지는 해당 엔티티를 엔티티 매니저가 관리하지 않는다.
Member member = new Member();
member.setName(name);
member.setAge(age);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("해당폴더명");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
// 엔티티 매니저에서 수행하는 모든 로직은 트랜잭션 안에서 수행돼야 한다.
tx.begin();
// 이렇게 하면 해당 엔티티 매니저의 영속성 컨텍스트에 위에서 만든 member 객체가 저장된다.
// 이제 member 엔티티는 엔티티 매니저의 관리 대상이 되고, 영속성을 가졌다고 말할 수 있다.
em.persist(member);
// 영속성 컨텍스트에 있던 모든 SQL쿼리가 실행된다.
// Commit하지 않으면 DB에 data가 저장되지 않는다.
tx.commit();
} catch(Exception e) {
// 어떤 이유에서 오류가 났다면 트랜잭션을 롤백 시켜줘야한다.
tx.rollback();
} finally {
// 엔티티 매니저 종료
em.close();
}
}
}
이건 왜 적은지 정확하게 모르겠지만 한번 보면 좋을듯 하다.
EntityManager는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 스레드 간에 절대 공유하면 안 된다.
내가 데이터를 수정하고 있는데 다른 스레드에서 해당 데이터를 미리 수정해버리면 안 되기 때문이다.
따라서 EntityManager는 하나를 공유하면 안 되고, 상황에 따라서 계속해서 만들어줘야한다.
이 EntityManager를 만들어 주는 것이 바로 EntityManagerFactory이다.
public class Join {
public void join(String name, int age) {
// 아직까지는 해당 엔티티를 엔티티 매니저가 관리하지 않는다.
Member member = new Member();
member.setName(name);
member.setAge(age);
// META-INF/persistence.xml에서 이름이 db인 persistence-unit을 찾아서 엔티티 매니저 팩토리를 생성
EntityManagerFatory emf = Persistence.createEntityManagerFactory("db");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
// 엔티티 매니저에서 수행하는 모든 로직은 트랜잭선 안에서 수행돼야 한다.
tx.begin();
// 이렇게 하면 해당 엔티티 매니저의 영속성 컨텍스트에 위에서 만든 member 객체가 저장된다.
// 이제 member 엔티티는 엔티티 매니저의 관리 대상이 되고, 영속성을 가졌다고 말할 수 있다.
em.persist(member);
// 트랜잭션을 커밋한다.
tx.commit();
} catch(Exception e) {
// 어떤 이유에서 오류가 났다면 트랜잭션을 롤백 시켜줘야한다.
tx.rollback();
} finally {
// 엔티티 매니저 종료
em.close();
}
emf.close(); // 마찬가지로 엔티티 매니저 팩토리도 종료
}
}
공장(EntityManagerFatory)에서 제품(EntityManager)를 찍어내는 개념이라고 보면 될 것 같다.
EntityManagerFatory는 엔티티 매니저와 달리 여러 스레드가 동시에 접근해도 안전하다.
비용도 보면 공장을 짓는 비용은 굉장히 큰 것처럼,
EntityManagerFatory는 DB 당 하나 밖에 사용하지 않는다.
출처 : https://perfectacle.github.io/2018/01/14/jpa-entity-manager-factory/
https://sweets1327.tistory.com/60
https://velog.io/@jaeseok-go/JPA-%EC%98%81%EC%86%8D%EC%84%B1