JPA - CommunicationsException: Communications link failure at second connection
<p>I have an application using JPA EclipseLInk 2.5.2 which contacts every minute a mysql to do things. The first thing that has to be done is to say it's alive to the DB. To do this I use a ScheuledExecutorService running a busioness object every minute. This object opens an closes DAOs each time. </p>

<p>On my dev environment (my computer), with Wamp64 bits and mysql configured by default, everything is OK. When I put on a preprod server (CentOS 7, mysql  Ver 14.14 Distrib 5.7.16), the first loop is OK, but the next ones fail with this message when trying to execute a sql query with a DAO :</p>

<pre><code>[EL Warning]: 2016-12-13 09:35:01.936--UnitOfWork(1778154389)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

The last packet successfully received from the server was 57 316 milliseconds ago.  The last packet sent successfully to the server was 4 milliseconds ago.
Error Code: 0
Call: SELECT id, lastDateAliveChargement, lastDateAliveDechargement FROM LastAlive
Query: ReportQuery(referenceClass=LastAlive sql="SELECT id, lastDateAliveChargement, lastDateAliveDechargement FROM LastAlive")
</code></pre>

<p>On preprod I used first a mariaDB used with the mariaDB jdbc driver. Then I switched to mysql with mysql jdbc driver, and I still got the problem. When I list the pending connections on the mysql they still appear with <strong>command Sleep</strong> until the wait_timeout is expired.
I tried to configure mysql with these settings (my.cnf)</p>

<pre><code>[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
max_connections=100
port=3306
wait_timeout=3600   
</code></pre>

<p>On my computer (wamp, so windows) :
    [mysql]
    no-auto-rehash //fails to start with this param on the server
    [mysqld]
    port = 3306</p>

<p>Here are the params for JPA initialization :</p>

<pre><code>persistenceMapInitiales.put("javax.persistence.jdbc.driver","com.mysql.cj.jdbc.Driver");            
persistenceMapInitiales.put("javax.persistence.jdbc.url","jdbc:mysql://MY_REMOTE_IP/myDB?characterEncoding=utf-8&amp;useLegacyDatetimeCode=false&amp;serverTimezone=UTC&amp;autoReconnect=true&amp;useSSL=false");
persistenceMapInitiales.put("javax.persistence.jdbc.user","toto");
persistenceMapInitiales.put("javax.persistence.jdbc.password","toto");
persistenceMapInitiales.put("eclipselink.ddl-generation","create-or-extend-tables");
persistenceMapInitiales.put("eclipselink.create-ddl-jdbc-file-name","createDDL_ddlGeneration.jdbc"); 
persistenceMapInitiales.put("eclipselink.drop-ddl-jdbc-file-name","dropDDL_ddlGeneration.jdbc"); 
persistenceMapInitiales.put("eclipselink.ddl.default-table-suffix","engine=InnoDB");
persistenceMapInitiales.put("eclipselink.ddl-generation.output-mode","both");

persistenceMapInitiales.put("eclipselink.connection-pool.default.initial","1" );
persistenceMapInitiales.put("eclipselink.connection-pool.default.min","64" );
persistenceMapInitiales.put("eclipselink.connection-pool.default.max","64" );  
</code></pre>

<p>The declaration of the scheduledExectorService :</p>

<pre><code>public static void main(String[] args)
{
    final Integer CRON_PERIOD = 1; // every minute
    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    scheduler.scheduleAtFixedRate(new MyWork(), 0, CRON_PERIOD, TimeUnit.MINUTES);
}
</code></pre>

<p>The Business class</p>

<pre><code>public class MyWork() implements Runnable{

    private LastAliveDao lastAliveDao;
    //...

    public void run()
    {
        sayIsAlive();
        //...
    }

    private void sayIsAlive()
    {
        logger.info("upadet isAlive");
        try{
            lastAliveDao = new JpaLastAliveDao();
            lastAliveDao.sayChargementIsAlive();
        }catch(Exception e){
            logger.error("", e);
        }finally{
            try{
                lastAliveDao.close();
            }catch(Exception e)
            {
                logger.warn("Exception closing dao : ", e);
            }
            lastAliveDao = null;
        }
    }
}
</code></pre>

<p>The DAO code :</p>

<pre><code>public class JpaLastAliveDao extends JpaDao&lt;LastAlive, Integer&gt; implements LastAliveDao {

@Override
public void sayChargementIsAlive() {
    List&lt;LastAlive&gt; alives = this.list();
    if(alives.size() == 0){
        LastAlive alive = new LastAlive();
        alive.setLastDateAliveChargement(Calendar.getInstance().getTime());
        this.persist(alive);
    }else{
        LastAlive alive = alives.get(0);
        alive.setLastDateAliveChargement(Calendar.getInstance().getTime());
        this.update(alive);
    }
}
</code></pre>

<p>And the JpaDAO code :</p>

<pre><code>public abstract class JpaDao&lt;T, PK extends Serializable&gt;
    implements Dao&lt;T, PK&gt;{

    protected Class&lt;T&gt; entityClass;

    protected EntityManagerFactory emf;
    protected EntityManager em;

    @SuppressWarnings("unchecked")
    public JpaDao()
    {
        emf = JPAUtils.getInstance("facturator").getEmf();
        em = emf.createEntityManager();
        ParameterizedType genericSuperclass = (ParameterizedType) 
                getClass().getGenericSuperclass();
        this.entityClass = (Class&lt;T&gt;) genericSuperclass.getActualTypeArguments()[0];
    }

    public T persist(T t) {
        this.em.getTransaction().begin();
        this.em.persist(t);
        this.em.getTransaction().commit();
        return t;
    }

    public T findById(PK id) {
        return this.em.find(entityClass, id);
    }

    public T update(T t) {
        this.em.getTransaction().begin();
        T entityPersist = this.em.merge(t);
        this.em.getTransaction().commit();
        return entityPersist;
    }

    @SuppressWarnings("unchecked")
    public List&lt;T&gt; list()
    {
        return this.em.createQuery("SELECT t FROM "+entityClass.getName()+" t ").getResultList();
    }

    public void delete(T t) {
        this.em.getTransaction().begin();
        this.em.remove(t);
        this.em.getTransaction().commit();
    }

    public void close(){
        em.close();
    }

}
</code></pre>