Tomcat服务器中的任务期间JDBC连接丢失

时间:2018-04-26 15:07:59

标签: java spring-boot scheduler tomcat8 entitymanager

MY STRUCTURE:

  • 使用Keycloak
  • 的身份验证服务器
  • 一个Tomcat 8服务器
  • 一个应用程序(名为 A ),其中包含位于tomcat 8服务器上的所有其他WebApp的公共服务
  • 其他webApps
  • MySQL服务器数据库,w / r具有不同的模式。
  • 可读的SQL Server

我的所有webApp都是使用Java 8在Spring Boot中开发的。

CASE:
在其中一个指定的应用程序(称为 B )中,我调用了 A 的API。 此API打开与SQL Server的连接,用于读取条目并发送到 B 读取条目的值。

我在本地计算机上运行的 A B 以及 A 官方和 B 本地测试

在测试中我没有任何问题,API工作正常。

但是当我把这个API从官方调用到官方时,几秒钟后我在日志中出现了一些错误,我丢失了与数据库的所有连接:

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

或:

EntityManager is closed

发生此错误后,我只能重新启动Tomcat服务器以恢复与数据库的连接。

这是我的代码,名为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());
            }
        }

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;
}

有什么想法吗?

修改

这是我的DBs连接的server.xml:

        <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" />

在春季添加DataSource配置。

在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;
}
}

在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;
    }
}

1 个答案:

答案 0 :(得分:1)

我和h2数据库有同样的问题。解决方案是在多连接模式下使用db(多于一个可能的连接,连接池)。