如何解决Google CloudSQL 8小时超时问题?

时间:2016-03-14 05:51:16

标签: hibernate google-app-engine entitymanager google-cloud-sql apache-commons-dbcp

我正在使用Google Cloud SQL在应用中工作。我正在使用Hibernate 4.2.0.Final,我注意到在8小时不活动后我的连接已关闭。我一直在互联网上搜索,我找不到任何有效的方法来解决这个问题。我发现的所有信息都汇总在这些项目中:

  • 使用连接池,我应指定更高的超时。我已尝试使用c3p0和DBCP 2.1.1库,但没有一个解决了这个问题。
  • 在某些查询之前打开连接,然后在之后关闭它。问题是我想使用EntityManager来使用实体查询。

这是我在DBCP 2.1.1(http://xx.xxx.xxx.xxx:8200/v1/post/wikipedia)中所做的。问题是,当我尝试在ExceptionInInitializerError中使用findAll时,Goggle App Engine日志会显示PersistenceService。日志还显示我的DataSource(见下文)无法转换为String。我不明白为什么。

这是我现在正在使用的PersistenceService

package co.peewah.ems.utils;

import com.google.appengine.api.utils.SystemProperty;

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.AbstractMap.SimpleEntry;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.hibernate.cfg.AvailableSettings;


/**
 *
 * @author Muacito
 */
public class PersistenceService
{
    private static final EntityManagerFactory EMF = createEntityManagerFactory();

    private static EntityManager entityManager = EMF.createEntityManager();

    private static EntityManagerFactory createEntityManagerFactory()
    {
        //String mode = "";
        /*
        if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Development)
        {
            mode = "dev.";
        }
        */

        Map<String, Object> properties = new HashMap<>();

        //Properties properties = new Properties();

        //properties.put("javax.persistence.jdbc.driver", System.getProperty("persistence." + mode + "db.driver"));
        //properties.put("javax.persistence.jdbc.url", System.getProperty("persistence." + mode + "db.url"));
        //properties.put("javax.persistence.jdbc.user", System.getProperty("persistence." + mode + "db.user"));
        //properties.put("javax.persistence.jdbc.password", System.getProperty("persistence." + mode + "db.password"));
        try
        {
            properties.put(AvailableSettings.DATASOURCE, DataSource.getInstance());
        } catch (IOException | SQLException | PropertyVetoException e)
        {
             e.printStackTrace();
        }


        System.out.println("----------------------------");
        System.out.println("----------------------------");
        System.out.println(properties);
        System.out.println("----------------------------");
        System.out.println("----------------------------");

        return Persistence.createEntityManagerFactory("Demo", properties);
    }

    private static EntityManager getEntityManager()
    {
        if (!PersistenceService.entityManager.isOpen())
        {
            PersistenceService.entityManager = PersistenceService.EMF.createEntityManager();
        }

        return PersistenceService.entityManager;
    }

    public static <T> void create(T entity)
    {
        try
        {
            if (entity.getClass().getMethod("getId").invoke(entity) == null)
            {
                entity.getClass().getMethod("setId", String.class).invoke(entity,
                        UUID.randomUUID().toString().replace("-", ""));
            }

            if (entity.getClass().getMethod("getCreated").invoke(entity) == null)
            {
                entity.getClass().getMethod("setCreated", Date.class).invoke(entity,
                        GregorianCalendar.getInstance().getTime());
            }

            getEntityManager().getTransaction().begin();

            getEntityManager().persist(entity);

            getEntityManager().flush();

            getEntityManager().getTransaction().commit();

        } catch (Exception ex)
        {
            Logger.getLogger(PersistenceService.class.getName()).log(Level.SEVERE, null, ex);
            getEntityManager().getTransaction().rollback();
        }
    }

    public static <T> void edit(T entity)
    {
        try
        {
            if (entity.getClass().getMethod("getUpdated").invoke(entity) == null)
            {
                entity.getClass().getMethod("setUpdated", Date.class).invoke(entity,
                        GregorianCalendar.getInstance().getTime());
            }

            getEntityManager().getTransaction().begin();

            getEntityManager().merge(entity);

            getEntityManager().flush();

            getEntityManager().getTransaction().commit();
        } catch (Exception ex)
        {
            Logger.getLogger(PersistenceService.class.getName()).log(Level.SEVERE, null, ex);
            getEntityManager().getTransaction().rollback();
        }
    }

    public static <T> void remove(T entity)
    {
        try
        {
            getEntityManager().getTransaction().begin();

            getEntityManager().remove(entity);

            getEntityManager().flush();

            getEntityManager().getTransaction().commit();

        } catch (Exception ex)
        {
            Logger.getLogger(PersistenceService.class.getName()).log(Level.SEVERE, null, ex);
            getEntityManager().getTransaction().rollback();
        }
    }

    public static <T> List<T> filter(Class<T> entityClass, String query, SimpleEntry<String, Object>... parameters)
    {
        TypedQuery<T> typedQuery = getEntityManager().createQuery(query, entityClass);

        for (SimpleEntry<String, Object> param : parameters)
        {
            typedQuery.setParameter(param.getKey(), param.getValue());
        }

        return typedQuery.getResultList();
    }

    public static <T> T find(Class<T> entityClass, Object id)
    {
        T entity = getEntityManager().find(entityClass, id);

        return entity;
    }

    public static <T> List<T> findBy(Class<T> entityClass, String criteria, Object value)
    {
        String c = criteria.replaceFirst(criteria.charAt(0) + "", (criteria.charAt(0) + "").toLowerCase());

        TypedQuery<T> query = getEntityManager().createNamedQuery(entityClass.getSimpleName() + ".findBy" + criteria,
                entityClass);
        query.setParameter(c, value);

        return query.getResultList();
    }

    public static <T> List<T> findAll(Class<T> entityClass)
    {
        CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));

        return getEntityManager().createQuery(cq).getResultList();
    }

    public static <T> List<T> findRange(Class<T> entityClass, int[] range)
    {
        CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(range[1] - range[0] + 1);
        q.setFirstResult(range[0]);

        return q.getResultList();
    }

    public static <T> int count(Class<T> entityClass)
    {
        CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        Root<T> rt = cq.from(entityClass);
        cq.select(getEntityManager().getCriteriaBuilder().count(rt));
        Query q = getEntityManager().createQuery(cq);

        return ((Long) q.getSingleResult()).intValue();
    }
}

这是我的DataSource

package co.peewah.ems.utils;

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import org.apache.commons.dbcp.BasicDataSource;

import com.google.appengine.api.utils.SystemProperty;

/**
 *
 * @author csacanam
 *
 */
public class DataSource
{

    private static DataSource datasource;
    private BasicDataSource ds;

    private DataSource() throws IOException, SQLException, PropertyVetoException
    {
        ds = new BasicDataSource();


        String mode = "";

        if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Development)
        {
            mode = "dev.";
        }

        String user = System.getProperty("persistence." + mode + "db.user");
        String password = System.getProperty("persistence." + mode + "db.password");
        String address = System.getProperty("persistence." + mode + "db.url");
        String driver = System.getProperty("persistence." + mode + "db.driver");

        // Create and configure DBCP DataSource
        ds.setDriverClassName(driver);
        ds.setUrl(address);
        ds.setUsername(user);
        ds.setPassword(password);

        ds.setMinIdle(5);
        ds.setMaxIdle(20);

        ds.setMaxOpenPreparedStatements(180);
    }

    public static DataSource getInstance() throws IOException, SQLException, PropertyVetoException
    {
        if(datasource == null)
        {
            datasource = new DataSource();    
        }

        return datasource;
    }

    public Connection getConnection() throws SQLException
    {
        return this.ds.getConnection();
    }




}

3 个答案:

答案 0 :(得分:0)

为mysql连接添加autoReconnect=true选项。最简单的方法是将其添加到连接URL本身:

persistence.db.url=jdbc:mysql://x.x.x.x:3306/y?autoReconnect=true

答案 1 :(得分:0)

8小时空闲连接超时来自mysql服务器,而不是客户端,因此更改客户端上的超时时间不会太大。可以通过更改wait_timeout标志在服务器上调整此设置。 8小时是默认值。

您应该将连接池配置为在一段时间后自动删除空闲连接。在DBCP中,您可以通过timeBetweenEvictionRunsMillis选项启用空闲连接逐出器。

答案 2 :(得分:0)

在Vadim的答案中添加一点,在CloudSQL上,您可以通过云控制台Edit实例设置标志。在Google上,您无法通过运行类似SET GLOBAL wait_timeout=60;的内容来执行此操作,因为它不支持SUPER权限。

我花了一段时间才找到这个,所以我想这可能会帮助其他人在这里添加它。