为什么hibernate(JPA)在执行延迟加载查询后不释放数据库连接? 在下面的例子中,如果我评论这个“--System.out.println(user1.getUserOwner());”并使用两次用户量(500 * 2 = 1000个用户)执行JMeter测试。 为什么延迟加载会捕获数据库连接? 抛出许多连接错误。
我正在使用:
EMProducer.java
public class EMProducer implements Serializable {
private static final long serialVersionUID = 1L;
public static final String PESISTENCE_UNIT_NAME = "pfac";
public static EntityManager getEntityManager(){
return Persistence.createEntityManagerFactory(PESISTENCE_UNIT_NAME).createEntityManager();
}
@Produces
@ApplicationScoped
public EntityManagerFactory create() {
return Persistence.createEntityManagerFactory(PESISTENCE_UNIT_NAME);
}
public void destroy(@Disposes EntityManagerFactory factory) {
factory.close();
}
@Produces
public EntityManager createEntityManager(EntityManagerFactory emf) {
return extractEntityManager(emf);
}
private EntityManager extractEntityManager(EntityManagerFactory emf) {
EntityManager em = emf.createEntityManager();
return em;
}
}
的test.xml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
>
<f:view>
<h:head>
<title>Test</title>
</h:head>
<h:body>
#{testView}
</h:body>
</f:view>
</html>
托管视图
@Named
@ViewScoped
public class TestView implements Serializable {
private static final long serialVersionUID = 1L;
@Inject private EntityManager entityManager;
@PostConstruct
private void inicialize(){
User user1 = this.entityManager.find(User.class, 1);
System.out.println(user1.getUserOwner());
}
}
实体
@Entity
@Table(name = User.TABLE_NAME, schema = User.SCHEMA_NAME)
public class User implements Serializable {
private static final long serialVersionUID = 1L;
public static final String SCHEMA_NAME = "public";
public static final String TABLE_NAME = "tb_user";
public static final String SEQUENCE_NAME = "sq_"+TABLE_NAME;
private Integer id;
private User userOwner;
private String name;
public User() {
}
@Id
@Column(name = "id_user", nullable=false, insertable=false, updatable=false)
@SequenceGenerator(name = SEQUENCE_NAME, schema=SCHEMA_NAME, sequenceName = SEQUENCE_NAME, allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = SEQUENCE_NAME)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id_user_owner", nullable = false, updatable=false)
@NotNull
public User getUserOwner() {
return userOwner;
}
public void setUserOwner(User userOwner) {
this.userOwner = userOwner;
}
@Column(name = "ds_name")
@Size(min=5, max=100)
@NotNull
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return getName();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getId() == null) {
return false;
}
if (!(obj instanceof User)) {
return false;
}
User other = (User) obj;
if (!getId().equals(other.getId())) {
return false;
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getId();
return result;
}
}
的persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
version="2.1">
<persistence-unit name="pfac" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
<property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/test" />
<property name="hibernate.connection.username" value="postgres" />
<property name="hibernate.connection.password" value="postgres" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.archive.autodetection" value="class" />
<property name="hibernate.connection.isolation" value="2" />
<property name="hibernate.id.new_generator_mappings" value="true" />
<property name="hibernate.default_batch_fetch_size" value="16" />
<property name="hibernate.max_fetch_depth" value="3" />
<property name="hibernate.connection.release_mode" value="after_statement" />
</properties>
</persistence-unit>
</persistence>
答案 0 :(得分:1)
应使用以下方式注入EntityManager:
@PersistenceContext(unitName = "pfac")
不使用@Inject注释。
EntityManager是上下文绑定的,您可以将它与当前线程事务关联或使用应用程序范围持久性上下文。 The connection release mode始终与当前事务配置相关:JDBC或JTA。
在您的情况下,您正在使用JDBC资源本地事务,但您已配置:
<property name="hibernate.connection.release_mode" value="after_statement" />
您通常用于JTA积极发布模式。在使用JDBC连接时,它不是它的意思。
因为您正在使用DriverManagerConnectionProviderImpl,所以它将使用内部连接池来处理JDBC连接。
在每个语句之后,将调用org.hibernate.engine.jdbc.connections.spi.ConnectionProvider #closeConnection(连接conn)。
对于DriverManagerConnectionProviderImpl,它的外观如下:
@Override
public void closeConnection(Connection conn) throws SQLException {
if (conn == null) {
return;
}
this.connections.offer( conn );
}
所以连接没有关闭,但它们返回到池中,这就是它们没有关闭的原因。您需要关闭EntityManagerFactory以关闭内部连接池,然后所有JDBC连接将在物理上关闭。