2017-09-08 19 views
3

Jersey JAX-RS에있는 REST 클라이언트는 요청을 받아서 Hibernate의 JPA 구현을 사용하여 데이터베이스에서 데이터를 검색하고 JSON을 리턴합니다.entitymanager를 사용하는 올바른 방법은 무엇입니까

공유 엔티티 관리자를 사용하면 성능이 상당히 좋아 지지만 여러 요청이있을 경우 Hibernate에서 예외가 발생하며 주로 NullPointerException이 발생합니다.

요청 당 엔티티 관리자를 사용하면 예외가 발생하지 않지만 성능이 떨어집니다.

EntityManager를 적절하게 처리하는 방법은 무엇입니까?

예를 들어

reqUser = entityManager.find(User.class, userId); 

reqUser = EntityManagerHelper.getEntityManager().find(User.class, userId); 
에 내가 EntityManagerHelper.getEntityManager를 사용하는 EntityManager를 참조를 EntityManagerHelper.java 을 사용하고 변경 한 아래 알버트의 코멘트() 다음

:

편집

EDIT 끝

아래 코드는 내가 사용하는 코드입니다.

Jersey.java

package local.domain; 

import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 
import javax.ws.rs.QueryParam; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.Response; 

@Path("/testJersey") 
public class Jersey { 

    static MainClass mainClass = new MainClass(); 

    @GET 
    @Produces("application/json") 
    public Response getAccounts(@QueryParam(value = "userId") final int userId) { 
     String jsonString = mainClass.getAccounts(userId); 
     return Response.ok(jsonString, MediaType.APPLICATION_JSON).build(); 
    }// getJson 


    @Path("/fields/") 
    @GET 
    @Produces("application/json") 
    public Response getAccountFields(@QueryParam(value = "accountId") final int accountId) { 
     String jsonString = mainClass.getAccountFields(accountId); 
     return Response.ok(jsonString, MediaType.APPLICATION_JSON).build(); 
    }// getJson 
} 

MainClass.java

package local.domain; 

import javax.persistence.EntityManager; 
import javax.persistence.EntityManagerFactory; 
import javax.persistence.Persistence; 

import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 

import local.domain.pojos.Account; 
import local.domain.pojos.User; 

public class MainClass { 
    private EntityManagerFactory entityManagerFactory = null; 
    private EntityManager entityManager; 

    boolean sharedEntityManager = true; 

    public MainClass() { 
     entityManagerFactory = Persistence.createEntityManagerFactory("peristenceConfig"); 
     entityManager = entityManagerFactory.createEntityManager(); 
    } 

    public String getAccounts(int userId) { 
     String result = null; 
     try { 
      User reqUser = null; 
      EntityManager entityManagerLocal = null; 

      if (sharedEntityManager) 
       reqUser = entityManager.find(User.class, userId); 
      else { 
       entityManagerLocal = entityManagerFactory.createEntityManager(); 
       reqUser = entityManagerLocal.find(User.class, userId); 
      } 

      Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); 
      result = gson.toJson(reqUser); 
      if (!sharedEntityManager) 
       entityManagerLocal.close(); 
     } catch (Exception exp) { 
      System.err.println("Exception with userId"+userId); 
      exp.printStackTrace(); 
     } 
     return result; 
    } 

    public String getAccountFields(int accountId) { 
     String result = null; 
     try { 
      Account reqAccount = null; 
      EntityManager entityManagerLocal = null; 

      if (sharedEntityManager) 
       reqAccount = entityManager.find(Account.class, accountId); 
      else { 
       entityManagerLocal = entityManagerFactory.createEntityManager(); 
       reqAccount = entityManagerLocal.find(Account.class, accountId); 
      } 

      Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); 
      result = gson.toJson(reqAccount); 
      if (!sharedEntityManager) 
       entityManagerLocal.close(); 
     } catch (Exception exp) { 
      System.err.println("Exception with accountId"+accountId); 
      exp.printStackTrace(); 
     } 
     return result; 
    } 
} 

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.1" 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_1.xsd"> 
    <persistence-unit name="peristenceConfig"> 
     <class>local.domain.pojos.Account</class> 
     <class>local.domain.pojos.AccountField</class> 
     <class>local.domain.pojos.User</class> 
     <properties> 
      <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" /> 
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /> 
      <property name="hibernate.show_sql" value="true" /> 
      <property name="hibernate.connection.url" value="jdbc:mysql://localhost/jpatest" /> 
      <property name="hibernate.default_schema" value="jpatest" /> 
      <property name="hibernate.connection.username" value="username" /> 
      <property name="hibernate.connection.password" value="password" /> 
     </properties> 
    </persistence-unit> 
</persistence> 

의 pom.xml의 persistence.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>Snippet</groupId> 
    <artifactId>Snippet</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <packaging>war</packaging> 
    <build> 
    <sourceDirectory>src</sourceDirectory> 
    <plugins> 
     <plugin> 
     <artifactId>maven-compiler-plugin</artifactId> 
     <version>3.5.1</version> 
     <configuration> 
      <source>1.8</source> 
      <target>1.8</target> 
     </configuration> 
     </plugin> 
     <plugin> 
     <artifactId>maven-war-plugin</artifactId> 
     <version>3.0.0</version> 
     <configuration> 
      <warSourceDirectory>WebContent</warSourceDirectory> 
     </configuration> 
     </plugin> 
    </plugins> 
    </build> 
    <properties> 
     <jersey.version>2.26-b02</jersey.version> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    </properties> 
    <dependencyManagement> 
     <dependencies> 
      <dependency> 
       <groupId>org.glassfish.jersey</groupId> 
       <artifactId>jersey-bom</artifactId> 
       <version>${jersey.version}</version> 
       <type>pom</type> 
       <scope>import</scope> 
      </dependency> 
     </dependencies> 
    </dependencyManagement> 
    <repositories> 
     <repository> 
      <id>JBoss repository</id> 
      <url>http://repository.jboss.org/nexus/content/groups/public/</url> 
     </repository> 
    </repositories> 
    <dependencies> 
     <dependency> 
      <groupId>org.glassfish.jersey.containers</groupId> 
      <artifactId>jersey-container-servlet-core</artifactId> 
     </dependency> 
     <dependency> 
     <groupId>javax.ws.rs</groupId> 
     <artifactId>jsr311-api</artifactId> 
     <version>1.1.1</version> 
    </dependency> 
    <dependency> 
     <groupId>org.hibernate.javax.persistence</groupId> 
     <artifactId>hibernate-jpa-2.1-api</artifactId> 
     <version>1.0.0.Final</version> 
    </dependency> 
    <dependency> 
     <groupId>com.google.code.gson</groupId> 
     <artifactId>gson</artifactId> 
     <version>2.8.0</version> 
    </dependency> 
    <dependency> 
     <groupId>mysql</groupId> 
     <artifactId>mysql-connector-java</artifactId> 
     <version>5.1.6</version> 
    </dependency> 
    <dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-core</artifactId> 
     <version>5.2.6.Final</version> 
    </dependency> 
    </dependencies> 
</project> 

POJO를 User.java Account.java AccountField.java

package local.domain.pojos; 

import java.io.Serializable; 
import java.util.List; 

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.JoinColumn; 
import javax.persistence.ManyToOne; 
import javax.persistence.NamedQuery; 
import javax.persistence.OneToMany; 
import javax.persistence.Table; 

import com.google.gson.annotations.Expose; 


/** 
* The persistent class for the tbl_account database table. 
* 
*/ 
@Entity 
@Table(name="tbl_account") 
@NamedQuery(name="Account.findAll", query="SELECT a FROM Account a") 
public class Account implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Id 
    @Column(name="account_id") 
    @Expose 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private int accountId; 

    @Column(name="account_status") 
    @Expose 
    private String accountStatus; 

    //bi-directional many-to-one association to User 
    @ManyToOne 
    @JoinColumn(name="user_id") 
    private User tblUser; 

    //bi-directional many-to-one association to AccountField 
    @OneToMany(mappedBy="tblAccount") 
    @Expose 
    private List<AccountField> tblAccountFields; 

    public Account() { 
    } 

    public int getAccountId() { 
     return this.accountId; 
    } 

    public void setAccountId(int accountId) { 
     this.accountId = accountId; 
    } 

    public String getAccountStatus() { 
     return this.accountStatus; 
    } 

    public void setAccountStatus(String accountStatus) { 
     this.accountStatus = accountStatus; 
    } 

    public User getTblUser() { 
     return this.tblUser; 
    } 

    public void setTblUser(User tblUser) { 
     this.tblUser = tblUser; 
    } 

    public List<AccountField> getTblAccountFields() { 
     return this.tblAccountFields; 
    } 

    public void setTblAccountFields(List<AccountField> tblAccountFields) { 
     this.tblAccountFields = tblAccountFields; 
    } 

    public AccountField addTblAccountField(AccountField tblAccountField) { 
     getTblAccountFields().add(tblAccountField); 
     tblAccountField.setTblAccount(this); 

     return tblAccountField; 
    } 

    public AccountField removeTblAccountField(AccountField tblAccountField) { 
     getTblAccountFields().remove(tblAccountField); 
     tblAccountField.setTblAccount(null); 

     return tblAccountField; 
    } 

} 

package local.domain.pojos; 

import java.io.Serializable; 

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.JoinColumn; 
import javax.persistence.ManyToOne; 
import javax.persistence.NamedQuery; 
import javax.persistence.Table; 

import com.google.gson.annotations.Expose; 


/** 
* The persistent class for the tbl_account_field database table. 
* 
*/ 
@Entity 
@Table(name="tbl_account_field") 
@NamedQuery(name="AccountField.findAll", query="SELECT a FROM AccountField a") 
public class AccountField implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Id 
    @Column(name="account_field_id") 
    @Expose 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private int accountFieldId; 

    @Column(name="account_field_label") 
    @Expose 
    private String accountFieldLabel; 

    //bi-directional many-to-one association to Account 
    @ManyToOne 
    @JoinColumn(name="account_id") 
    private Account tblAccount; 

    public AccountField() { 
    } 

    public int getAccountFieldId() { 
     return this.accountFieldId; 
    } 

    public void setAccountFieldId(int accountFieldId) { 
     this.accountFieldId = accountFieldId; 
    } 

    public String getAccountFieldLabel() { 
     return this.accountFieldLabel; 
    } 

    public void setAccountFieldLabel(String accountFieldLabel) { 
     this.accountFieldLabel = accountFieldLabel; 
    } 

    public Account getTblAccount() { 
     return this.tblAccount; 
    } 

    public void setTblAccount(Account tblAccount) { 
     this.tblAccount = tblAccount; 
    } 

} 

package local.domain.pojos; 

import java.io.Serializable; 
import java.sql.Timestamp; 
import java.util.List; 

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.Lob; 
import javax.persistence.NamedQuery; 
import javax.persistence.OneToMany; 
import javax.persistence.Table; 

import com.google.gson.annotations.Expose; 


/** 
* The persistent class for the tbl_user database table. 
* 
*/ 
@Entity 
@Table(name="tbl_user") 
@NamedQuery(name="User.findAll", query="SELECT u FROM User u") 
public class User implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Id 
    @Column(name="user_id") 
    @Expose 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private int userId; 

    @Lob 
    @Column(name="user_email") 
    @Expose 
    private String userEmail; 

    @Column(name="user_last_login") 
    @Expose 
    private Timestamp userLastLogin; 

    @Column(name="user_name") 
    @Expose 
    private String userName; 

    //bi-directional many-to-one association to Account 
    @OneToMany(mappedBy="tblUser") 
    @Expose 
    private List<Account> tblAccounts; 

    public User() { 
    } 

    public int getUserId() { 
     return this.userId; 
    } 

    public void setUserId(int userId) { 
     this.userId = userId; 
    } 

    public String getUserEmail() { 
     return this.userEmail; 
    } 

    public void setUserEmail(String userEmail) { 
     this.userEmail = userEmail; 
    } 

    public Timestamp getUserLastLogin() { 
     return this.userLastLogin; 
    } 

    public void setUserLastLogin(Timestamp userLastLogin) { 
     this.userLastLogin = userLastLogin; 
    } 

    public String getUserName() { 
     return this.userName; 
    } 

    public void setUserName(String userName) { 
     this.userName = userName; 
    } 

    public List<Account> getTblAccounts() { 
     return this.tblAccounts; 
    } 

    public void setTblAccounts(List<Account> tblAccounts) { 
     this.tblAccounts = tblAccounts; 
    } 

    public Account addTblAccount(Account tblAccount) { 
     getTblAccounts().add(tblAccount); 
     tblAccount.setTblUser(this); 

     return tblAccount; 
    } 

    public Account removeTblAccount(Account tblAccount) { 
     getTblAccounts().remove(tblAccount); 
     tblAccount.setTblUser(null); 

     return tblAccount; 
    } 

} 

답변

2

은 "올바른"방법은 응용 프로그램의 유형에 따라 다를 수 있습니다. 귀하의 경우에는 EntityManager을 공유하면 원치 않는 행동이 발생할 것입니다.

요청 방식은 구현하기에 안전한 방법이라고 생각합니다. 또 다른 방법은 ThreadEntityManager을 사용하고, ThreadLocal을 사용하여이를 관리하는 것입니다. 이것이 Spring의 기능입니다. 하지만 이로 인해 구현이 더욱 복잡해 질 수 있습니다.

편집 : 같은 Thread 내에서 여러 요청을 처리, NIO를 사용하는 경우 문제가 발생할 수 있습니다 EntityManagerThread 당을 사용하여 언급하는 것이 좋다.