我有一个基于rest的应用服务器,它构建在嵌入式jetty、spring boot和hibernate上。它使用ms sql后端数据库。
我的@transactional方法可以工作,但似乎没有关闭db连接,最终导致没有可用的hikari池成员:
java.sql.SQLTransientConnectionException: HikariPoolProduct - Connection is not available, request timed out after 30003ms.
在上述内容之后不久,我将看到以下hikari数据:
10:29:24.774 [HikariPoolProduct housekeeper] DEBUG HikariPoolProduct - Pool stats (total=50, active=49, idle=1, waiting=0)
10:29:24.774 [HikariPoolProduct housekeeper] DEBUG HikariPoolProduct - Fill pool skipped, pool is at sufficient level.
我希望active为1或0。
在我的测试用例中,我将hikari池大小设置为50。当我反复让我的客户机通过rest调用服务器certificatepolicyentityresource.get()时,它工作正常,直到它尝试#51,然后失败,如上所示。
我使用@transactional方法,并且我非常确定 Package 器/代理应该在返回之前释放hikari池成员(通过db virtual/proxy close)。这似乎没有发生。
我的代码调用树:
client -> [REST] -> CertificatePolicyEntityResource.get() ->
CertificatePolicyEntityServletAdapter.get() ->
DomainRegistryModelProxy.certificatePolicyService() // Use spring ApplicationContext to retrieve CertificatePolicyServiceRepositoryImpl
CertificatePolicyServiceRepositoryImpl.size() and .allCertificatePolicies() // These are @Transactional
这是我的服务类certificatepolicyservicerepositoryimpl,它具有@transactional方法:
package cmb.domain.model.certpolicy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Accessors( fluent = true )
public class CertificatePolicyServiceRepositoryImpl implements CertificatePolicyService {
@Getter
private CertificatePolicyRepository certificatePolicyRepository;
public CertificatePolicyServiceRepositoryImpl(CertificatePolicyRepository certificatePolicyRepository) {
this.certificatePolicyRepository = certificatePolicyRepository;
}
@Override
@Transactional
public CertificatePolicy certificatePolicyOfId(String id) {
return certificatePolicyRepository().certificatePolicyOfId(id);
}
@Override
@Transactional
public List<CertificatePolicy> allCertificatePolicies() {
return certificatePolicyRepository().allCertificatePolicies();
}
@Override
@Transactional
public List<CertificatePolicy> allActiveCertificatePolicies() {
return certificatePolicyRepository().allActiveCertificatePolicies();
}
@Override
@Transactional(readOnly = true)
public int size() {
return certificatePolicyRepository().size();
}
}
certificatepolicyentityresource.java证书:
package cmb.cabridge.port.servlet.resource;
import javax.ws.rs.BeanParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
@Path(CaBridgeCommandValues.RESOURCE_CERTIFICATEPOLICYENTITY)
public class CertificatePolicyEntityResource extends AbstractCaBridgeResource {
@BeanParam
private NetworkRequestContext requestContext;
@GET
@Path(CaBridgeCommandValues.SUBRESOURCE_CERTIFICATEPOLICYENTITY_GET + "/{id}")
public CertificatePolicyEntityResponse get(@PathParam("id") String idList,
@QueryParam(CertificatePolicyRequestFlags.FLAG_MINIENTITY) boolean miniEntityEnabled) {
final String function = "Get by ID";
ResponseHandler handler = createResponseHandler(m, function);
try {
processRequest(requestContext,
CaBridgeCommand.getInstance().create(CaBridgeCommandValues.CertificatePolicyEntityGet));
CertificatePolicyEntityResponse response = new CertificatePolicyEntityServletAdapter(caBridgeSessionContext())
.get(idList, miniEntityEnabled);
handler.succeeded(response);
return response;
} catch (Throwable e) {
CertificatePolicyEntityResponse response = new CertificatePolicyEntityResponse();
handler.failed(e, response);
return response;
}
}
}
适配器:
package cmb.cabridge.port.servlet.adapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Component
public class CertificatePolicyEntityServletAdapter extends AbstractCaBridgeCommonServletAdapter {
private CertificatePolicyService certificatePolicyService() {
/*
* Retrieve bean using Spring ApplicationContext
*/
return DomainRegistryModelProxy.certificatePolicyService();
}
public CertificatePolicyEntityResponse get(String searchValue, boolean miniEntityEnabled) {
List<CertificatePolicyEntity> results = new ArrayList<>();
entityConverter().setMiniEntityEnabled(miniEntityEnabled);
if (searchValue == null || searchValue.equalsIgnoreCase(GlobalConstantStandard.ALL)) {
if (certificatePolicyService().size() > 0)
certificatePolicyService().allCertificatePolicies().stream().forEach(
item -> results.add(entityConverter.toEntity(item))
);
} else {
List<String> ids = StringTool.splitAsList(searchValue, ",");
for (String id : ids) {
CertificatePolicy item = certificatePolicyService()
.certificatePolicyOfIdOrName(id);
if (item != null)
results.add(entityConverter.toEntity(item));
}
}
CertificatePolicyEntityResponse response = new CertificatePolicyEntityResponse();
if (results.size() == 0) {
String message = "No " + what + " found for ID/Name(s) " + searchValue;
log.info("%s", message);
response.setMessage(message);
response.setResult(Result.FAILED);
response.setFailureType(FailureType.NOTFOUND);
} else {
response.setEntities( results );
response.setResult(Result.SUCCEEDED);
}
return response;
}
}
数据源类:
package cmb.cabridge.infrastructure.persistence.hibernate;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import cmb.common.infrastructure.DatabaseConfigurationTool;
import cmb.domain.model.CmbDomainModelMarker;
import cmb.product.domain.model.CmbProductDomainModelMarker;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.Properties;
/**
* CAB Hibernate Product Database Configuration
*/
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = HibernateProductDatabaseConfiguration.PRODUCT_ENTITY_MANAGER,
transactionManagerRef = HibernateProductDatabaseConfiguration.PRODUCT_TX_MANAGER
)
@EnableTransactionManagement
public class HibernateProductDatabaseConfiguration {
private Trace log = TraceFactory.create(this);
/*
* Packages that Spring should scan to find @Entity classes
*/
private static final String [] PACKAGES_TO_SCAN = {
MangoDomainModelMarker.class.getPackage().getName(),
CmbDomainModelMarker.class.getPackage().getName(),
CmbProductDomainModelMarker.class.getPackage().getName()
};
public static final String PRODUCT_ENTITY_MANAGER = "productEntityManager";
public static final String PRODUCT_TX_MANAGER = "productTransactionManager";
public static final String SESSION_FACTORY_PRODUCT = "sessionFactoryProduct";
// Default size of 10 is too small for CAB
private static final int MAX_POOL_SIZE = 250;
private static final int MAX_LIFETIME_SECONDS = 2 * 60; // XXX debug value
//private static final int MAX_LIFETIME_SECONDS = 60 * 60; // 1 hour
private static final int IDLE_TIMEOUT_SECONDS = 15 * 60;
private static final int LEAK_DETECTION_THRESHOLD_SECONDS = 30;
private static final int CONNECTION_TIMEOUT_SECONDS = 30;
@Bean(name = SESSION_FACTORY_PRODUCT)
@Primary
public SessionFactory sessionFactoryProduct() {
return sessionFactoryProductBean().getObject();
}
@Bean
@Primary
public LocalSessionFactoryBean sessionFactoryProductBean() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(productDataSource());
sessionFactory.setPackagesToScan( PACKAGES_TO_SCAN );
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Bean
@Primary
public DataSource productDataSource() {
/*
* Get the PersistenceConfiguration from persistconfig.properties and
* then build Creator to format the configuration data as needed.
*/
PersistenceConfiguration cf = ProductConfig.getPersistenceConfiguration();
if (cf == null || cf.getDataBaseName() == null)
throw new ConfigurationException("Failed to load persistence configuration");
HibernatePropertiesCreator propCreator = new HibernatePropertiesCreator(cf);
log.info("Creating Product DataSource with url %s", propCreator.createUrl());
/*
* Use Hikari specific config so we can configure maximumPoolSize which
* is critical to having a large enough pool.
*/
HikariConfig config = new HikariConfig();
config.setPoolName("HikariPool" + "Product");
config.setJdbcUrl( propCreator.createUrl() );
config.setUsername( cf.getUserName() );
config.setPassword( cf.getUserPassword() );
config.setDriverClassName( propCreator.getDriverClass() );
config.setMaximumPoolSize( DatabaseConfigurationTool.maxPoolSize("product", MAX_POOL_SIZE) );
config.setConnectionTimeout(CONNECTION_TIMEOUT_SECONDS * 1000);
config.setMaxLifetime(MAX_LIFETIME_SECONDS * 1000);
// config.setIdleTimeout(IDLE_TIMEOUT_SECONDS * 1000);
// Report connection leaks with stacktrace
config.setLeakDetectionThreshold( LEAK_DETECTION_THRESHOLD_SECONDS * 1000 );
return new HikariDataSource( config );
}
@Bean
@Primary
public PlatformTransactionManager productTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactoryProduct());
return transactionManager;
}
private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update");
//hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
// Use new IdentifierGenerator
hibernateProperties.setProperty("hibernate.id.new_generator_mappings", "true");
return hibernateProperties;
}
}
暂无答案!
目前还没有任何答案,快来回答吧!