Usar Cloud SQL para MySQL

En esta página se explica cómo puedes conectarte a una instancia de Cloud SQL para MySQL de segunda generación desde una aplicación de App Engine, y cómo leer y escribir en Cloud SQL. Cloud SQL es una base de datos de SQL que se aloja en la nube de Google.

Para obtener más información sobre Cloud SQL, consulta la documentación de Cloud SQL. Si deseas obtener información sobre los precios y los límites de Cloud SQL, consulta la página de precios de Cloud SQL. Las aplicaciones de App Engine también están sujetas a las cuotas de App Engine.

Antes de comenzar

  1. Crea o selecciona un proyecto de GCP en GCP Console y, luego, asegúrate de que el proyecto incluya una aplicación de App Engine y de que la facturación esté habilitada:
    Ir a App Engine

    El Panel se abre si ya existe una aplicación de App Engine en tu proyecto y si la facturación está habilitada. En caso contrario, sigue las indicaciones para elegir una región y habilitar la facturación.

  2. Habilita las Cloud SQL API necesarias.

    Habilita las API

  3. Para implementar una aplicación de Java en App Engine, primero debes configurar el entorno. Consulta Cómo usar Apache Maven y el complemento de App Engine para obtener información detallada.

Configurar la instancia de Cloud SQL

Para crear y configurar una instancia de Cloud SQL:

  1. Crea una instancia de segunda generación de Cloud SQL.
  2. Si aún no lo hiciste, configura la contraseña para el usuario predeterminado en tu instancia de Cloud SQL:
    gcloud sql users set-password root --host=% --instance [INSTANCE_NAME] --password [PASSWORD]
    
  3. Si no quieres utilizar el usuario predeterminado para conectarte, crea un usuario.
  4. Registra el nombre de conexión correspondiente a la instancia:
    gcloud sql instances describe [INSTANCE_NAME]
    

    Por ejemplo:

    connectionName: project1:us-central1:instance1
    

    También puedes encontrar este valor en la página Detalles de la instancia de Google Cloud Platform Console.

  5. En este ejemplo, crea una base de datos en tu instancia de Cloud SQL denominada sqldemo.
    gcloud sql databases create sqldemo --instance=[INSTANCE_NAME]
    
    Para obtener más información sobre cómo crear y administrar bases de datos, consulta la Documentación de Cloud SQL.

Configurar strings de conexión y agregar una biblioteca

Usa la biblioteca de sockets de la fábrica de sockets de JDBC de Cloud SQL si quieres conectarte a tu instancia de Cloud SQL para las pruebas locales y en la implementación.

  1. Actualiza pom.xml con tu nombre de conexión, nombre de usuario y contraseña:

      <properties>
    <!--
        INSTANCE_CONNECTION_NAME from Cloud Console > SQL > Instance Details > Properties
        or `gcloud sql instances describe <instance> | grep connectionName`
    -->
        <INSTANCE_CONNECTION_NAME>Project:Region:Instance</INSTANCE_CONNECTION_NAME>
        <user>root</user>
        <password>myPassword</password>
        <database>sqldemo</database>
    <!-- ...
        <sqlURL>jdbc:mysql://google/${database}?cloudSqlInstance=${INSTANCE_CONNECTION_NAME}&amp;socketFactory=com.google.cloud.sql.mysql.SocketFactory&amp;user=${user}&amp;password=${password}&amp;useSSL=false</sqlURL>
      </properties>

  2. Agrega los filtros de recursos obligatorios a pom.xml:

    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>

  3. Crea un archivo llamado config.properties que contenga la siguiente línea:

    sqlUrl=${sqlURL}

    Este archivo depende de los filtros de recursos configurados en pom.xml.

  4. Agrega una biblioteca de JDBC y la fábrica de sockets de JDBC de Cloud SQL a tu aplicación. Para ello, agrega la dependencia a pom.xml:

    <dependency>                        <!-- http://dev.mysql.com/doc/connector-j/en/ -->
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>6.0.5</version>
    </dependency>
    <dependency>
      <groupId>com.google.cloud.sql</groupId>
      <artifactId>mysql-socket-factory-connector-j-6</artifactId>
      <version>1.0.11</version>
    </dependency>

Ejecutar el código de muestra

La muestra siguiente escribe la información de la visita en Cloud SQL y, luego, lee y muestra las últimas diez visitas:
@SuppressWarnings("serial")
@WebServlet(name = "cloudsql", value = "")
public class CloudSqlServlet extends HttpServlet {
  Connection conn;

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,
      ServletException {
    final String createTableSql = "CREATE TABLE IF NOT EXISTS visits ( visit_id INT NOT NULL "
        + "AUTO_INCREMENT, user_ip VARCHAR(46) NOT NULL, timestamp DATETIME NOT NULL, "
        + "PRIMARY KEY (visit_id) )";
    final String createVisitSql = "INSERT INTO visits (user_ip, timestamp) VALUES (?, ?)";
    final String selectSql = "SELECT user_ip, timestamp FROM visits ORDER BY timestamp DESC "
        + "LIMIT 10";

    String path = req.getRequestURI();
    if (path.startsWith("/favicon.ico")) {
      return; // ignore the request for favicon.ico
    }

    PrintWriter out = resp.getWriter();
    resp.setContentType("text/plain");

    // store only the first two octets of a users ip address
    String userIp = req.getRemoteAddr();
    InetAddress address = InetAddress.getByName(userIp);
    if (address instanceof Inet6Address) {
      // nest indexOf calls to find the second occurrence of a character in a string
      // an alternative is to use Apache Commons Lang: StringUtils.ordinalIndexOf()
      userIp = userIp.substring(0, userIp.indexOf(":", userIp.indexOf(":") + 1)) + ":*:*:*:*:*:*";
    } else if (address instanceof Inet4Address) {
      userIp = userIp.substring(0, userIp.indexOf(".", userIp.indexOf(".") + 1)) + ".*.*";
    }

    Stopwatch stopwatch = Stopwatch.createStarted();
    try (PreparedStatement statementCreateVisit = conn.prepareStatement(createVisitSql)) {
      conn.createStatement().executeUpdate(createTableSql);
      statementCreateVisit.setString(1, userIp);
      statementCreateVisit.setTimestamp(2, new Timestamp(new Date().getTime()));
      statementCreateVisit.executeUpdate();

      try (ResultSet rs = conn.prepareStatement(selectSql).executeQuery()) {
        stopwatch.stop();
        out.print("Last 10 visits:\n");
        while (rs.next()) {
          String savedIp = rs.getString("user_ip");
          String timeStamp = rs.getString("timestamp");
          out.print("Time: " + timeStamp + " Addr: " + savedIp + "\n");
        }
        out.println("Elapsed: " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
      }
    } catch (SQLException e) {
      throw new ServletException("SQL error", e);
    }
  }

  @Override
  public void init() throws ServletException {
    try {
      String url;

      Properties properties = new Properties();
      try {
        properties.load(
            getServletContext().getResourceAsStream("/WEB-INF/classes/config.properties"));
        url = properties.getProperty("sqlUrl");
      } catch (IOException e) {
        log("no property", e);  // Servlet Init should never fail.
        return;
      }

      log("connecting to: " + url);
      try {
        Class.forName("com.mysql.jdbc.Driver");
        conn = DriverManager.getConnection(url);
      } catch (ClassNotFoundException e) {
        throw new ServletException("Error loading JDBC Driver", e);
      } catch (SQLException e) {
        throw new ServletException("Unable to connect to PostGre", e);
      }

    } finally {
      // Nothing really to do here.
    }
  }
}

Implementar y realizar pruebas

  1. Para probar tu aplicación de manera local:

    mvn clean jetty:run
    
  2. Después de la prueba local, implementa tu aplicación en App Engine:

    mvn clean appengine:deploy
    

  3. Para iniciar el navegador y ver la aplicación en http://[YOUR_PROJECT_ID].appspot.com, ejecuta el siguiente comando:

    gcloud app browse
    

Ejecutar Cloud SQL y App Engine en proyectos diferentes

Si la aplicación de App Engine y la instancia de Cloud SQL se encuentran en distintos proyectos de Google Cloud Platform, debes usar una cuenta de servicio para permitir el acceso de la aplicación de App Engine a Cloud SQL.

Esta cuenta de servicio representa tu aplicación de App Engine y se genera de forma predeterminada cuando creas un proyecto de Google Cloud Platform.

  1. Si tu aplicación de App Engine se encuentra en el mismo proyecto que tu instancia de Cloud SQL, puedes omitir esta sección y acceder a Configurar strings de conexión y agregar una biblioteca. De lo contrario, continúa con el siguiente paso.
  2. Identifica la cuenta de servicio asociada a tu aplicación de App Engine. A la cuenta de servicio de App Engine predeterminada se le asigna el nombre [PROJECT-ID]@appspot.gserviceaccount.com.

    Puedes verificar la cuenta de servicio de App Engine en la página Permisos de IAM. Asegúrate de seleccionar el proyecto para tu aplicación de App Engine, no tu instancia de Cloud SQL.

    Ir a la página Permisos de IAM

  3. Ve a la página IAM y proyectos del administrador en Google Cloud Platform Console.

    Ir a la página IAM y proyectos del administrador

  4. Selecciona el proyecto que contiene la instancia de Cloud SQL.
  5. Busca el nombre de la cuenta de servicio.
  6. Si la cuenta de servicio ya está ahí y tiene una función que incluye el permiso cloudsql.instances.connect, puedes continuar a Configurar strings de conexión y agregar una biblioteca.

    Las funciones Cloud SQL Client, Cloud SQL Editor y Cloud SQL Admin, y las funciones del proyecto heredadas Editor y Owner otorgan los permisos necesarios.

  7. De lo contrario, haz clic en Agregar para incluir la cuenta de servicio.
  8. En el diálogo Agregar miembros, ingresa el nombre de la cuenta de servicio y selecciona una función que incluya el permiso cloudsql.instances.connect (cualquier función predefinida de Cloud SQL funcionará, excepto la de Lector).

    O bien, puedes seleccionar Proyecto > Editor para usar la función básica de Editor, pero esta función requiere permisos en Google Cloud Platform.

    Si no ves estas funciones, es posible que tu usuario de Google Cloud Platform no tenga el permiso resourcemanager.projects.setIamPolicy. Puedes verificar tus permisos en la página de IAM en Google Cloud Platform Console y buscar tu ID de usuario.

  9. Haz clic en Agregar.

    Ahora deberías ver que la cuenta de servicio aparece con la función especificada.

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Entorno flexible de App Engine para documentos de Java