{
 "tarjetas": [
  {
   "sub": "JDBC y localización",
   "nivel": "basico",
   "clave": true,
   "q": "¿Qué es JDBC?",
   "a": "Java Database Connectivity: la API estándar de Java para hablar con bases de datos relacionales.\nEstructura: DriverManager/DataSource → Connection → Statement → ResultSet.\nCada motor (Postgres, MySQL...) provee su DRIVER (jar) que implementa la API.\nEs la base sobre la que trabajan JPA/Hibernate y JdbcTemplate."
  },
  {
   "sub": "JDBC y localización",
   "nivel": "intermedio",
   "clave": false,
   "q": "JDBC: flujo básico de una consulta (código)",
   "a": "try (Connection cn = DriverManager.getConnection(url, user, pass);\n     PreparedStatement ps = cn.prepareStatement(\"SELECT nombre FROM users WHERE id = ?\")) {\n  ps.setLong(1, id);\n  try (ResultSet rs = ps.executeQuery()) {\n    while (rs.next()) System.out.println(rs.getString(\"nombre\"));\n  }\n}\nRecursos AutoCloseable → try-with-resources obligatorio."
  },
  {
   "sub": "JDBC y localización",
   "nivel": "intermedio",
   "clave": true,
   "q": "PreparedStatement vs Statement: ¿por qué SIEMPRE PreparedStatement?",
   "a": "PreparedStatement: la consulta se PRE-COMPIILA y los parámetros van aparte (?) → immune a SQL Injection y más rápida si se reutiliza.\nStatement con concatenación: 'WHERE nombre = \"' + input + '\"' → input='; DROP TABLE users; -- = desastre.\nRegla de seguridad: jamás concatenar input del usuario en SQL."
  },
  {
   "sub": "JDBC y localización",
   "nivel": "intermedio",
   "clave": false,
   "q": "Transacciones en JDBC plano",
   "a": "Por defecto está en autocommit (cada sentencia es su tx).\nControl manual:\ncn.setAutoCommit(false);\ntry { ...updates...; cn.commit(); }\ncatch (Exception e) { cn.rollback(); }\nEs lo que @Transactional hace por ti debajo (con DataSourceTransactionManager)."
  },
  {
   "sub": "JDBC y localización",
   "nivel": "basico",
   "clave": false,
   "q": "Localización (i18n): Locale, ResourceBundle y NumberFormat",
   "a": "Locale: identifica idioma+país (new Locale(\"es\", \"PE\"), Locale.getDefault()).\nResourceBundle: archivos messages_es.properties, messages_en.properties → bundle.getString(\"saludo\") según el Locale.\nNumberFormat/DateFormat: formatean números, monedas y fechas según el locale (1.234,56 vs 1,234.56).\nOCP lo pregunta poco, pero aparece en apps multi-idioma."
  },
  {
   "sub": "Sintaxis y tipos",
   "nivel": "basico",
   "clave": false,
   "q": "varargs: sintaxis y reglas",
   "a": "void sumar(int... nums) — acepta 0 o más ints (llega como array).\nReglas: solo UNO por método y debe ser el ÚLTIMO parámetro.\nSobrecarga con varargs es ambigua con facilidad: sumar(int...) y sumar(int, int...) → llamar sumar(5) no compila.\nEs azúcar sobre String[] args."
  },
  {
   "sub": "Sintaxis y tipos",
   "nivel": "basico",
   "clave": false,
   "q": "¿Cómo se compila y ejecuta un programa Java? ¿Qué es el classpath?",
   "a": "javac Hola.java → Hola.class (bytecode). java Hola → la JVM lo ejecuta.\nVarias clases/jars: java -cp \"lib/*:clases\" MiApp (classpath = dónde busca clases).\nCon Maven/Gradle esto lo automatiza el build; en un jar ejecutable: java -jar app.jar.\n-classpath mal puesto → ClassNotFoundException."
  },
  {
   "sub": "Sintaxis y tipos",
   "nivel": "basico",
   "clave": false,
   "q": "Paquetes e imports: convención y propósito",
   "a": "Paquete = namespace + organización: package com.empresa.proyecto.servicio;\nConvención: dominio invertido en minúsculas (com.google.x).\nimport com.empresa.util.Fechas; o import estático: import static java.lang.Math.max;\nSin import → nombre completo (java.util.List) o error de compilación.\nLos paquetes también definen el acceso package-private."
  },
  {
   "sub": "Sintaxis y tipos",
   "nivel": "basico",
   "clave": false,
   "q": "Convenciones de nombres en Java (JavaBeans)",
   "a": "Clases/Interfaces/interfaces funcionales: PascalCase (MiServicio).\nMétodos y variables: camelCase (obtenerUsuario).\nConstantes: UPPER_SNAKE (MAX_INTENTOS).\nPaquetes: todo.minuscula.\nGetters/setters: getNombre/setNombre (isActivo para boolean) — los frameworks (Jackson, Spring) confían en estas convenciones."
  }
 ]
}