Reputation: 814
MY STRUCTURE:
All my webApps are developed in Spring Boot, with Java 8.
CASE:
In one of the specified application (called B) I call an API of A.
This API open a connection with the SQL Server, for read an entry and send to B the value of reading entry.
I test it with A and B running in my local machine, and A official and B local.
In test I don't have any problem, the API works fine.
But when I call this API from official to official, after some seconds I had some errors in log and I lost all the connection to my Databases:
Forwarding to error page from request [/mycontroller/request] due to exception
[org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5ec9a879 has been closed already]
java.lang.IllegalStateException: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5ec9a879 has been closed already
or:
EntityManager is closed
After this error I can only restart my Tomcat Server to restore the connection with the databases.
This is my code, that called API:
@Override
public void apiCalled() {
try {
for(Entity c : entityRepository.findEntity()) {
String ftt = keycloakRestTemplate.getForEntity(URI.create(mux+"/api/apiCalled?num="+c.getNumber()), String.class).getBody();
if(ftt == null) {
continue;
}
FttDto f = new ObjectMapper().readValue(ftt, FttDto.class);
c.setNumberF(f.getNumberF());
c.setDateF(convertDate(f.getDateF()));
commessaRepository.save(c);
}
} catch (RestClientException | IOException e) {
LOG.error("Api Service Get error: {}", e.getMessage());
}
}
Code of the API:
@PersistenceContext(unitName="persistenceUnitI24")
private EntityManager emI24;
public FttDto findByNumber(String number) {
Session session = emI24.unwrap(Session.class);
FttI24 fttListI24 = (FttI24) session.createQuery("select f from FttRg r join r.idFttI24 f join r.nota n where n.nota like '%"+number+"%'")
.setCacheMode(CacheMode.IGNORE)
.uniqueResult();
if(fttListI24 == null) {
return null;
}
FttDto ftt = new FttDto();
ftt.setNumberF(fttListI24.getNumberF());
ftt.setDateF(fttListI24.getDateF());
return ftt;
}
Any ideas?
EDIT
This is my server.xml for my DBs connection:
<Resource
name="jdbc/schemaA"
auth="Container"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
type="javax.sql.DataSource"
initialSize="2"
maxActive="4"
maxIdle="2"
minIdle="1"
username="user"
password="password"
driverClassName="net.sourceforge.jtds.jdbc.Driver"
url="jdbc:jtds:sqlserver://sqlServer_ip/schemaA"
testOnBorrow="true"
testWhileIdle="true"
validationQuery="select 1"
validationInterval="300000"/>
<Resource
name="jdbc/schemaB"
auth="Container"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
type="javax.sql.DataSource"
initialSize="4"
maxActive="8"
maxWait="10000"
maxIdle="8"
minIdle="4"
username="userB"
password="passB"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://mysqlserver_ip/schemaB?zeroDateTimeBehavior=convertToNull"
testOnBorrow="true"
testWhileIdle="true"
validationQuery="select 1"
validationInterval="300000" />
Adding DataSource Config in spring.
on WebApp B:
@Configuration
@EnableTransactionManagement
public class DataSourceConfig {
@Bean(name = "dataSource")
@ConfigurationProperties(prefix="spring.datasource")
@Primary
public DataSource dataSource() throws NamingException {
if(Arrays.asList(environment.getActiveProfiles()).contains("dev")) {
return new BasicDataSource();
}else {
Context ctxConfig = new InitialContext();
return (DataSource) ctxConfig.lookup("java:comp/env/jdbc/schemaB");
}
}
@Bean
@Primary
public JpaTransactionManager transactionManager() throws NamingException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
@Bean
public JpaVendorAdapter jpaVendorAdapter(){
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabase(Database.MYSQL);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(false);
jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLInnoDBDialect");
return jpaVendorAdapter;
}
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan("domain.mydomain");
entityManagerFactoryBean.setPersistenceUnitName("persistenceUnit");
return entityManagerFactoryBean;
}
}
on WebApp A:
@Configuration
public class DataSourceI24Config {
@Autowired
private Environment environment;
@Bean(name = "dataSourceI24")
@ConfigurationProperties(prefix = "spring.datasource.i24")
public DataSource dataSourceI24() throws NamingException {
Context ctxConfig = new InitialContext();
return (DataSource) ctxConfig.lookup("java:comp/env/jdbc/schemaA");
}
@Bean(name="transactionManagerI24")
public JpaTransactionManager transactionManagerI24() throws NamingException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryI24().getObject());
return transactionManager;
}
@Bean(name="entityManagerI24")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryI24() throws NamingException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSourceI24());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan("appA.i24.domain");
entityManagerFactoryBean.setPersistenceUnitName("persistenceUnitI24");
[...]
return entityManagerFactoryBean;
}
}
Upvotes: 1
Views: 1315
Reputation: 6705
I had a same problem like this with h2 database. The solution was use db in the multiple connection mode ( more then one possible connection, connection pool).
Upvotes: 1