678 lines
23 KiB
Markdown
678 lines
23 KiB
Markdown
# JDBC
|
|
|
|
```sh
|
|
mysql -u <user> -h <host> -p
|
|
```
|
|
|
|
```sql
|
|
CREATE DATABASE control_de_stock;
|
|
USE control_de_stock;
|
|
|
|
CREATE TABLE producto(
|
|
id INT AUTO_INCREMENT,
|
|
nombre VARCHAR(50) NOT NULL,
|
|
descripcion VARCHAR(255),
|
|
cantidad INT NOT NULL DEFAULT 0,
|
|
PRIMARY KEY(id)
|
|
)Engine=InnoDB;
|
|
|
|
INSERT INTO producto(
|
|
nombre, descripcion, cantidad)
|
|
values('Mesa', 'Mesa de 4 lugares', 10);
|
|
|
|
INSERT INTO producto(
|
|
nombre, descripcion, cantidad)
|
|
values( 'Celular', 'Celular Samsung', 50);
|
|
|
|
SELECT * FROM producto;
|
|
|
|
+----+----------+-------------------+----------+
|
|
| id | nombre | descripcion | cantidad |
|
|
+----+----------+-------------------+----------+
|
|
| 1 | Mesa | Mesa de 4 lugares | 10 |
|
|
| 2 | Celuclar | Celular Samsung | 50 |
|
|
+----+----------+-------------------+----------+
|
|
```
|
|
|
|
<br/>
|
|
|
|
```mermaid
|
|
%%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}}}%%
|
|
flowchart
|
|
subgraph "Conexión a base de datos"
|
|
DB1[(MySQL)]
|
|
DB2[(SQL Server)]
|
|
DB3[(MariaDB)]
|
|
app1["Aplicación
|
|
Java"]
|
|
DV1[/"Driver MySQL
|
|
MySqlConnector.getConnection()"\]
|
|
DV2[/"Driver SQL Server
|
|
SqlServerConnection.Provider.connect()"\]
|
|
DV3[/MariaDB Driver\]
|
|
DBC{{"JDBC
|
|
DriverManager.getConnection()"}}
|
|
app1-->DBC
|
|
DBC-->DV1-->DB1
|
|
DV1-->DB3
|
|
DBC-->DV3-->DB3
|
|
DBC-->DV2-->DB2
|
|
end
|
|
```
|
|
|
|
### Url de conexión
|
|
|
|
**`jdbc:<tipo_db>://<host:puerto>/<nombre_db>?<opc_params>`**
|
|
|
|
ejm. `jdbc:mysql//localhost:3306/control_de_stock`
|
|
|
|
## Proyecto
|
|
|
|
### Configuración de maven - [pom.xml](./java_jdbc/control-de-stock/pom.xml)
|
|
|
|
```xml
|
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
<modelVersion>4.0.0</modelVersion>
|
|
<groupId>com.alura</groupId>
|
|
<artifactId>control-de-stock</artifactId>
|
|
<version>0.0.1-SNAPSHOT</version>
|
|
<name>Control de Stock</name>
|
|
<description>Proyecto para trabajar con bases de datos con JDBC</description>
|
|
<properties>
|
|
<java.version>17</java.version>
|
|
</properties>
|
|
<dependencies>
|
|
<dependency>
|
|
<groupId>mysql</groupId>
|
|
<artifactId>mysql-connector-java</artifactId>
|
|
<version>8.0.33</version>
|
|
</dependency>
|
|
</dependencies>
|
|
<build>
|
|
<plugins>
|
|
<plugin>
|
|
<groupId>org.apache.plugins</groupId>
|
|
<artifactId>maven.compiler.plugin</artifactId>
|
|
<version>4.0.0</version>
|
|
<configuration>
|
|
<source>${java.version}</source>
|
|
<target>${java.version}</target>
|
|
<optimize>true</optimize>
|
|
</configuration>
|
|
</plugin>
|
|
</plugins>
|
|
</build>
|
|
</project>
|
|
```
|
|
|
|
### Prueba del conector
|
|
|
|
```java
|
|
package com.alura.tests;
|
|
|
|
import java.sql.Connection;
|
|
import java.sql.DriverManager;
|
|
import java.sql.SQLException;
|
|
|
|
public class PruebaConexion {
|
|
|
|
private static String dbname = "control_de_stock";
|
|
private static String dbuser = "alura";
|
|
private static String dbpass = "alura";
|
|
private static String dburl = "192.168.0.8:3306";
|
|
private static String params = "useTimeZone=true&serverTimeZone=UTC";
|
|
|
|
public static void main(String[] args) throws SQLException {
|
|
System.out.println("hola");
|
|
Connection con = DriverManager.getConnection(
|
|
"jdbc:mysql://"+dburl+"/"+dbname+"?"+params, dbuser, dbpass);
|
|
con.close();
|
|
System.out.println("chao");
|
|
}
|
|
|
|
}
|
|
```
|
|
|
|
### Uso de Clase
|
|
[ConnectionFactory](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/factory/ConnectionFactory.java)
|
|
|
|
```java
|
|
package com.alura.jdbc.factory;
|
|
|
|
import java.sql.Connection;
|
|
import java.sql.DriverManager;
|
|
import java.sql.SQLException;
|
|
|
|
public class ConnectionFactory {
|
|
|
|
private static String dbdriver = "jdbc:mysql://";
|
|
private static String dburl = dbdriver+"192.168.0.8:3306/";
|
|
private static String params = "?useTimeZone=true&serverTimeZone=UTC";
|
|
private static String dbname = "control_de_stock";
|
|
private static String dbuser = "alura";
|
|
private static String dbpass = "alura";
|
|
|
|
public Connection recuperaConexion() throws SQLException {
|
|
return DriverManager.getConnection(dburl + dbname + params, dbuser, dbpass);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Uso de try with resources para las conexiones
|
|
|
|
En clase
|
|
[ProductoController](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/controller/ProductoController.java)
|
|
para cierre automático de recursos `Statement`, `ResultSet`, `Connection`.
|
|
|
|
Y tratamiento de *querys* con `PreparedStatement`
|
|
|
|
```java
|
|
...
|
|
|
|
public void guardar(Map<String,String> producto) throws SQLException {
|
|
String nombre = producto.get("NOMBRE");
|
|
String descripcion = producto.get("DESCRIPCION");
|
|
int cantidad = Integer.valueOf(producto.get("CANTIDAD"));
|
|
int max_cantidad = 50;
|
|
|
|
final Connection con = new ConnectionFactory().recuperaConexion();
|
|
try (con) {
|
|
con.setAutoCommit(false);
|
|
final PreparedStatement statement = con.prepareStatement(
|
|
"INSERT INTO producto(nombre, descripcion, cantidad) VALUES(?,?,?)",
|
|
Statement.RETURN_GENERATED_KEYS);
|
|
|
|
try (statement) {
|
|
do {
|
|
int cantidad_a_guardar = Math.min(cantidad, max_cantidad);
|
|
ejecutaRegistro(nombre, descripcion, cantidad_a_guardar, statement);
|
|
cantidad -= max_cantidad;
|
|
} while (cantidad > 0);
|
|
con.commit();
|
|
} catch (Exception e) {
|
|
con.rollback();
|
|
}
|
|
}
|
|
}
|
|
|
|
...
|
|
```
|
|
|
|
## Pool de conexiones
|
|
|
|
```mermaid
|
|
%%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}}}%%
|
|
flowchart
|
|
subgraph "Conexión a base de datos"
|
|
DB1[(MySQL)]
|
|
DB2[(SQL Server)]
|
|
DB3[(MariaDB)]
|
|
app1("Aplicación
|
|
Java")
|
|
app2>"Connection
|
|
Factory"]
|
|
app1-->app2
|
|
subgraph DS[Datasource]
|
|
subgraph C3P0
|
|
pl("Pool de
|
|
Conexiones")
|
|
end
|
|
end
|
|
app2-->DS-->DBC
|
|
DV1[/"Driver MySQL
|
|
MySqlConnector.getConnection()"\]
|
|
DV2[/"Driver SQL Server
|
|
SqlServerConnection.Provider.connect()"\]
|
|
DV3[/MariaDB Driver\]
|
|
DBC{{"JDBC
|
|
DriverManager.getConnection()"}}
|
|
DBC-->DV1-->DB1
|
|
DV1-->DB3
|
|
DBC-->DV3-->DB3
|
|
DBC-->DV2-->DB2
|
|
end
|
|
```
|
|
|
|
### Implentando Pool Datasource en [ConnectionFactory](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/factory/ConnectionFactory.java)
|
|
|
|
|
|
- [c3p0](https://www.mchange.com/projects/c3p0/) - DJBC3 Connection and Statement
|
|
Pooling
|
|
|
|
- [mchange-commons-java](https://www.mchange.com/projects/mchange-commons-java/index.html)
|
|
|
|
Dependencias [pom.xml](./java_jdbc/control-de-stock/pom.xml)
|
|
|
|
```xml
|
|
...
|
|
<dependency>
|
|
<groupId>com.mchange</groupId>
|
|
<artifactId>c3p0</artifactId>
|
|
<version>0.9.5.5</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>com.mchange</groupId>
|
|
<artifactId>mchange-commons-java</artifactId>
|
|
<version>0.2.20</version>
|
|
</dependency
|
|
...
|
|
```
|
|
|
|
```java
|
|
package com.alura.jdbc.factory;
|
|
|
|
import java.sql.Connection;
|
|
import java.sql.SQLException;
|
|
import javax.sql.DataSource;
|
|
import com.mchange.v2.c3p0.ComboPooledDataSource;
|
|
|
|
public class ConnectionFactory {
|
|
|
|
private final static String driver = "jdbc:mysql://";
|
|
private final static String dbaddr = "192.168.0.8:3306/";
|
|
private final static String params = "?useTimeZone=true&serverTimeZone=UTC";
|
|
private final static String dbname = "control_de_stock";
|
|
private final static String dburl = driver+dbaddr+dbname+params;
|
|
private final static String dbuser = "alura";
|
|
private final static String dbpass = "alura";
|
|
|
|
private DataSource datasource;
|
|
|
|
public ConnectionFactory() {
|
|
var pooledDataSource = new ComboPooledDataSource();
|
|
pooledDataSource.setJdbcUrl(dburl);
|
|
pooledDataSource.setUser(dbuser);
|
|
pooledDataSource.setPassword(dbpass);
|
|
pooledDataSource.setMaxPoolSize(10);
|
|
this.datasource = pooledDataSource;
|
|
}
|
|
|
|
public Connection recuperaConexion() throws SQLException {
|
|
return this.datasource.getConnection();
|
|
}
|
|
}
|
|
```
|
|
|
|
```txt
|
|
Aug 14, 2023 11:33:59 PM com.mchange.v2.log.MLog
|
|
INFO: MLog clients using java 1.4+ standard logging.
|
|
Aug 14, 2023 11:34:00 PM com.mchange.v2.c3p0.C3P0Registry
|
|
INFO: Initializing c3p0-0.9.5.5 [built 11-December-2019 22:18:33 -0800; debug? true; trace: 10]
|
|
Aug 14, 2023 11:34:00 PM com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
|
|
INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> z8kfsxax1wlsb2gfqn07n|10dba097, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> null, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> z8kfsxax1wlsb2gfqn07n|10dba097, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://192.168.0.8:3306/control_de_stock?useTimeZone=true&serverTimeZone=UTC, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {password=******, user=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
|
|
Abriendo conexión nro: 1
|
|
Abriendo conexión nro: 2
|
|
Abriendo conexión nro: 3
|
|
Abriendo conexión nro: 4
|
|
Abriendo conexión nro: 5
|
|
Abriendo conexión nro: 6
|
|
Abriendo conexión nro: 7
|
|
Abriendo conexión nro: 8
|
|
Abriendo conexión nro: 9
|
|
Abriendo conexión nro: 10
|
|
```
|
|
|
|
```sql
|
|
SHOW PROCESSLIST;
|
|
|
|
+-----+-------+--------------------+------------------+---------+------+----------+------------------+----------+
|
|
| Id | User | Host | db | Command | Time | State | Info | Progress |
|
|
+-----+-------+--------------------+------------------+---------+------+----------+------------------+----------+
|
|
| 193 | alura | 192.168.0.10:36856 | control_de_stock | Sleep | 15 | | NULL | 0.000 |
|
|
| 194 | alura | 192.168.0.10:36854 | control_de_stock | Sleep | 15 | | NULL | 0.000 |
|
|
| 195 | alura | 192.168.0.10:36852 | control_de_stock | Sleep | 15 | | NULL | 0.000 |
|
|
| 196 | alura | 192.168.0.10:36882 | control_de_stock | Sleep | 15 | | NULL | 0.000 |
|
|
| 197 | alura | 192.168.0.10:36896 | control_de_stock | Sleep | 15 | | NULL | 0.000 |
|
|
| 198 | alura | 192.168.0.10:36880 | control_de_stock | Sleep | 15 | | NULL | 0.000 |
|
|
| 199 | alura | 192.168.0.10:36902 | control_de_stock | Sleep | 15 | | NULL | 0.000 |
|
|
| 200 | alura | 192.168.0.10:36918 | control_de_stock | Sleep | 15 | | NULL | 0.000 |
|
|
| 201 | alura | 192.168.0.10:36920 | control_de_stock | Sleep | 15 | | NULL | 0.000 |
|
|
| 202 | alura | 192.168.0.10:36934 | control_de_stock | Sleep | 15 | | NULL | 0.000 |
|
|
| 203 | alura | 192.168.0.8:42234 | NULL | Query | 0 | starting | show processlist | 0.000 |
|
|
+-----+-------+--------------------+------------------+---------+------+----------+------------------+----------+
|
|
11 rows in set (0.001 sec)
|
|
```
|
|
|
|
## Dao
|
|
|
|
Data Access Object [wiki](https://en.wikipedia.org/wiki/Data_access_object) en
|
|
clase
|
|
[ProductoDAO](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/dao/ProductoDAO.java)
|
|
|
|
|
|
```mermaid
|
|
%%{init: {'theme': 'dark','themeVariables': {'clusterBkg': '#2b2f38'}}}%%
|
|
flowchart
|
|
subgraph "Conexión a base de datos"
|
|
DB1[(MySQL)]
|
|
DB2[(SQL Server)]
|
|
DB3[(MariaDB)]
|
|
app1("Aplicación
|
|
Java")
|
|
CF("Connection
|
|
Factory")
|
|
subgraph DAO
|
|
direction RL
|
|
MD[Modelo]
|
|
CT[Controlador]
|
|
CT-->CF
|
|
CT-->MD
|
|
end
|
|
app1-->CT
|
|
app1-->MD
|
|
subgraph DS[Datasource]
|
|
subgraph C3P0
|
|
PC("Pool de
|
|
Conexiones")
|
|
end
|
|
end
|
|
CF-->DS-->DBC
|
|
DV1[/"Driver MySQL
|
|
MySqlConnector.getConnection()"\]
|
|
DV2[/"Driver SQL Server
|
|
SqlServerConnection.Provider.connect()"\]
|
|
DV3[/MariaDB Driver\]
|
|
DBC{{"JDBC
|
|
DriverManager.getConnection()"}}
|
|
DBC-->DV1-->DB1
|
|
DV1-->DB3
|
|
DBC-->DV3-->DB3
|
|
DBC-->DV2-->DB2
|
|
end
|
|
```
|
|
|
|
```java
|
|
package com.alura.jdbc.dao;
|
|
|
|
import java.sql.Connection;
|
|
import java.sql.PreparedStatement;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.sql.Statement;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import com.alura.jdbc.modelo.Producto;
|
|
|
|
public class ProductoDAO {
|
|
private final Connection con;
|
|
|
|
public ProductoDAO(Connection conexion) {
|
|
this.con = conexion;
|
|
}
|
|
|
|
public void guardar(Producto producto) {
|
|
try {
|
|
final PreparedStatement statement = con.prepareStatement(
|
|
"INSERT INTO producto(nombre, descripcion, cantidad) VALUES(?,?,?)",
|
|
Statement.RETURN_GENERATED_KEYS);
|
|
try (statement) {
|
|
ejecutaRegistro(producto, statement);
|
|
}
|
|
} catch (SQLException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
private void ejecutaRegistro(Producto producto, PreparedStatement statement)
|
|
throws SQLException {
|
|
statement.setString(1, producto.getNombre());
|
|
statement.setString(2, producto.getDescripcion());
|
|
statement.setInt(3, producto.getCantidad());
|
|
statement.execute();
|
|
final ResultSet resultSet = statement.getGeneratedKeys();
|
|
try (resultSet) {
|
|
while (resultSet.next()) {
|
|
producto.setId(resultSet.getInt(1));
|
|
System.out.println(String.format("Producto insertado %s: ", producto));
|
|
}
|
|
}
|
|
}
|
|
|
|
public List<Producto> listar() {
|
|
List<Producto> resultado = new ArrayList<>();
|
|
try {
|
|
final PreparedStatement statement = con.prepareStatement(
|
|
"SELECT ID, NOMBRE, DESCRIPCION, CANTIDAD FROM producto;");
|
|
try (statement) {
|
|
statement.execute();
|
|
ResultSet resultSet = statement.getResultSet();
|
|
while (resultSet.next()) {
|
|
Producto fila = new Producto(
|
|
resultSet.getInt("ID"),
|
|
resultSet.getString("NOMBRE"),
|
|
resultSet.getString("DESCRIPCION"),
|
|
resultSet.getInt("CANTIDAD")
|
|
);
|
|
resultado.add(fila);
|
|
}
|
|
return resultado;
|
|
}
|
|
} catch (SQLException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
public int modificar(Producto producto) {
|
|
try {
|
|
final String query = "UPDATE producto SET NOMBRE=?, DESCRIPCION=?, CANTIDAD=? WHERE ID=?;";
|
|
final PreparedStatement statement = con.prepareStatement(query);
|
|
try (statement) {
|
|
statement.setString(1, producto.getNombre());
|
|
statement.setString(2, producto.getDescripcion());
|
|
statement.setInt(3, producto.getCantidad());
|
|
statement.setInt(4, producto.getId());
|
|
statement.execute();
|
|
int resultado = statement.getUpdateCount();
|
|
return resultado;
|
|
}
|
|
} catch (SQLException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
public int eliminar(Integer id) {
|
|
try {
|
|
final PreparedStatement statement = con.prepareStatement("DELETE FROM producto WHERE ID=?;");
|
|
try (statement) {
|
|
statement.setInt(1, id);
|
|
statement.execute();
|
|
int resultado = statement.getUpdateCount();
|
|
return resultado;
|
|
}
|
|
} catch (SQLException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
}
|
|
```
|
|
|
|
### MVC
|
|
|
|
El proyecto sigue el patrón **M**odelo **V**ista **Controlador**
|
|
|
|
Ejm. Producto
|
|
|
|
- [Modelo](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/modelo/Producto.java)
|
|
- [Vista](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/view/ControlDeStockFrame.java)
|
|
- [Controlador](./java_jdbc/control-de-stock/src/main/java/com/alura/jdbc/controller/ProductoController.java)
|
|
|
|
```java
|
|
package com.alura.jdbc.controller;
|
|
|
|
import java.util.List;
|
|
|
|
import com.alura.jdbc.dao.ProductoDAO;
|
|
import com.alura.jdbc.factory.ConnectionFactory;
|
|
import com.alura.jdbc.modelo.Producto;
|
|
|
|
public class ProductoController {
|
|
|
|
private ProductoDAO productoDAO;
|
|
|
|
public ProductoController() {
|
|
this.productoDAO = new ProductoDAO(new ConnectionFactory().recuperaConexion());
|
|
}
|
|
|
|
public int modificar(Producto producto) {
|
|
return productoDAO.modificar(producto);
|
|
}
|
|
|
|
public int eliminar(Integer id) {
|
|
return productoDAO.eliminar(id);
|
|
}
|
|
|
|
public List<Producto> listar() {
|
|
return productoDAO.listar();
|
|
}
|
|
|
|
public void guardar(Producto producto) {
|
|
productoDAO.guardar(producto);
|
|
}
|
|
|
|
|
|
}
|
|
```
|
|
|
|
- Para cada tabla del modelo hay una clase de dominio
|
|
- Para la tabla de `producto` hay una clase `Producto` asociada
|
|
- Los objetos del tipo `Producto` representan un registro de la tabla
|
|
- Para acceder a la tabla se utiliza el estándar **Data Access Object (DAO)**
|
|
- Para cada clase de dominio hay un **DAO** asociado. Ejm, la clase
|
|
`Producto` posee la clase `ProductoDAO`
|
|
- Todos los métodos JDBC relacionados al producto están encapsulados en `ProductoDAO`
|
|
- Aplicación escrita en capas
|
|
- Las capas más conocidas son las de **view**, **controller**, **modelo** y
|
|
**persistencia**, que componen el estándar **MVC**
|
|
- El flujo de una consulta entre las capas es el siguiente
|
|
- `view` <--> `controller` <--> `persistencia`
|
|
|
|
> **Note** No es buena práctica dejar los detalles de implementación de una capa en otras
|
|
que no tienen esta responsabilidad (ejm. la capa de controller lanzar una
|
|
SQLException)
|
|
>
|
|
> Esta es una aplicación desktop embebida, pero hay otros tipos de aplicaciones
|
|
con otros tipos de view, como html para aplicaciones web.
|
|
|
|
## Relación entre tablas
|
|
|
|
Creación tabla `categoria` + 4 categorías
|
|
|
|
```sql
|
|
CREATE TABLE categoria(id INT AUTO_INCREMENT,
|
|
nombre VARCHAR(50) NOT NULL,
|
|
PRIMARY KEY(id)
|
|
)Engine=InnoDB;
|
|
|
|
INSERT INTO categoria(nombre)
|
|
VALUES('Muebles'),('Tecnología'),('Menaje'),('Calzado');
|
|
```
|
|
|
|
Modifcando tabla para agregar la columna `categoria_id`
|
|
|
|
```sql
|
|
ALTER TABLE producto ADD COLUMN categoria_id INT;
|
|
```
|
|
|
|
Creando **llave foranea**
|
|
|
|
```sql
|
|
ALTER TABLE producto ADD FOREIGN KEY(categoria_id) REFERENCES categoria(id);
|
|
```
|
|
|
|
Asignación de categoría a productos
|
|
|
|
```sql
|
|
UPDATE producto SET categoria_id=1 WHERE id=1;
|
|
...
|
|
UPDATE producto SET categoria_id=1 WHERE id>11 AND id<17;
|
|
...
|
|
```
|
|
|
|
```sql
|
|
SELECT * FROM categoria;
|
|
|
|
+----+-------------+
|
|
| id | nombre |
|
|
+----+-------------+
|
|
| 1 | Muebles |
|
|
| 2 | Tecnología |
|
|
| 3 | Menaje |
|
|
| 4 | Calzado |
|
|
+----+-------------+
|
|
```
|
|
|
|
```sql
|
|
SELECT * FROM producto;
|
|
|
|
+----+------------+--------------------------------+----------+--------------+
|
|
| id | nombre | descripcion | cantidad | categoria_id |
|
|
+----+------------+--------------------------------+----------+--------------+
|
|
| 1 | Mesa | Mesa de 4 lugares | 10 | 1 |
|
|
| 2 | Celular | Celular Samsung | 50 | 2 |
|
|
| 3 | Vaso | Vaso de cristal | 10 | 3 |
|
|
| 5 | Cuchara | Cuchara de plastico | 100 | 3 |
|
|
| 7 | Mouse | Mouse inálambrico | 100 | 2 |
|
|
| 9 | Linterna | Linterna con pilas recargables | 50 | 2 |
|
|
| 11 | Zapatillas | Zapatillas de futbol | 40 | 4 |
|
|
| 12 | Botellas | Botellas de vidrio | 50 | 1 |
|
|
| 13 | Botellas | Botellas de plástico | 24 | 1 |
|
|
| 14 | Platos | Platos de plastico | 50 | 1 |
|
|
| 15 | Platos | Platos de plastico | 10 | 1 |
|
|
| 16 | Platos | Platos de loza | 50 | 1 |
|
|
| 30 | Teclado | Teclado inalámbrico | 6 | 2 |
|
|
+----+------------+--------------------------------+----------+--------------+
|
|
```
|
|
|
|
## Inner JOIN
|
|
|
|
Cuando se tiene una relación entre tablas se debe cuidar de no crear el problema
|
|
de quieries `N+1`. Es decir, no buscar los datos de una relación en otras queries.
|
|
|
|
Esto puede producir problemas de performance tanto en la aplicación como en la DB.
|
|
|
|
Para ello utilizar ***join*** en la query SQL
|
|
|
|
```java
|
|
...
|
|
public List<Categoria> listarConProductos() {
|
|
List<Categoria> resultado = new ArrayList<>();
|
|
final String query = "SELECT C.ID, C.NOMBRE, P.ID, P.NOMBRE, P.CANTIDAD"
|
|
+ "FROM categoria C INNER JOIN producto P ON C.ID = P.CATEGORIA_ID ";
|
|
System.out.println(query);
|
|
try {
|
|
final PreparedStatement statement = con.prepareStatement(query);
|
|
try (statement) {
|
|
statement.execute();
|
|
final ResultSet resultSet = statement.getResultSet();
|
|
try (resultSet){
|
|
while (resultSet.next()) {
|
|
Integer categoriaId = resultSet.getInt("C.ID");
|
|
String categoriaNombre = resultSet.getString("C.NOMBRE");
|
|
var categoria = resultado
|
|
.stream()
|
|
.filter(cat -> cat.getId().equals(categoriaId))
|
|
.findAny().orElseGet(() -> {
|
|
Categoria cat = new Categoria(categoriaId,
|
|
categoriaNombre);
|
|
resultado.add(cat);
|
|
return cat;
|
|
});
|
|
Producto producto = new Producto(resultSet.getInt("P.ID"),
|
|
resultSet.getString("P.NOMBRE"),
|
|
resultSet.getInt("P.CANTIDAD"));
|
|
categoria.agregar(producto);
|
|
}
|
|
};
|
|
}
|
|
} catch (SQLException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
return resultado;
|
|
}
|
|
...
|
|
```
|
|
|
|
Aplicación [Control de Stock](./java_jdbc/control-de-stock/)
|
|
|