Acabo de anunciar el nuevo curso Learn Spring , centrado en los fundamentos de Spring 5 y Spring Boot 2:
>> VER EL CURSO1. Información general
Hay muchas formas en que podemos conectarnos a una base de datos MySQL desde Java y, en este tutorial, exploraremos varias opciones para ver cómo lograrlo.
Comenzaremos examinando posiblemente las opciones más populares que utilizan JDBC e Hibernate.
Luego, también veremos algunas bibliotecas externas, incluidas MyBatis, Apache Cayenne y Spring Data . En el camino, proporcionaremos una serie de ejemplos prácticos.
2. Condiciones previas
Asumiremos que ya tenemos un servidor MySQL instalado y ejecutándose en localhost (puerto predeterminado 3306) y que tenemos un esquema de prueba con la siguiente tabla de personas:
CREATE TABLE person ( ID INT, FIRST_NAME VARCHAR(100), LAST_NAME VARCHAR(100) );
También necesitaremos el artefacto mysql-connector-java que, como siempre, está disponible en Maven Central:
mysql mysql-connector-java 8.0.19
3. Conexión mediante JDBC
JDBC (Java Database Connectivity) es una API para conectar y ejecutar consultas en una base de datos.
3.1. Propiedades Comunes
Durante el transcurso de este artículo, normalmente usaremos varias propiedades comunes de JDBC :
- URL de conexión: una cadena que utiliza el controlador JDBC para conectarse a una base de datos. Puede contener información como dónde buscar la base de datos, el nombre de la base de datos a la que conectarse y otras propiedades de configuración:
jdbc:mysql://[host][,failoverhost...] [:port]/[database] [?propertyName1][=propertyValue1] [&propertyName2][=propertyValue2]...
Estableceremos esta propiedad así: jdbc: mysql: // localhost: 3306 / test? ServerTimezone = UTC
- Clase de controlador: el nombre de clase completamente calificado del controlador que se utilizará. En nuestro caso, usaremos el controlador MySQL: com.mysql.cj.jdbc.Driver
- Nombre de usuario y contraseña: las credenciales de la cuenta MySQL
3.2. Ejemplo de conexión JDBC
Veamos cómo podemos conectarnos a nuestra base de datos y ejecutar un simple seleccionar todo a través de un intento con múltiples recursos:
String sqlSelectAllPersons = "SELECT * FROM person"; String connectionUrl = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC"; try (Connection conn = DriverManager.getConnection(connectionUrl, "username", "password"); PreparedStatement ps = conn.prepareStatement(sqlSelectAllPersons); ResultSet rs = ps.executeQuery()) { while (rs.next()) { long id = rs.getLong("ID"); String name = rs.getString("FIRST_NAME"); String lastName = rs.getString("LAST_NAME"); // do something with the extracted data... } } catch (SQLException e) { // handle the exception }
Como podemos ver, dentro del cuerpo de prueba , iteramos a través del conjunto de resultados y extraemos los valores de la tabla de personas.
4. Conexión mediante ORM
Más típicamente, nos conectaremos a nuestra base de datos MySQL usando un marco de mapeo relacional de objetos (ORM) . Entonces, veamos algunos ejemplos de conexión usando el más popular de estos marcos.
4.1. API nativas de Hibernate
En esta sección, veremos cómo usar Hibernate para administrar una conexión JDBC a nuestra base de datos.
Primero, necesitamos agregar la dependencia de Maven del núcleo de hibernación :
org.hibernate hibernate-core 5.4.10.Final
Hibernate requiere que se cree una clase de entidad para cada tabla. Sigamos adelante y definamos la clase Person :
@Entity @Table(name = "Person") public class Person { @Id Long id; @Column(name = "FIRST_NAME") String firstName; @Column(name = "LAST_NAME") String lastName; // getters & setters }
Otro aspecto esencial es crear el archivo de recursos de Hibernate, típicamente llamado hibernate.cfg.xml , donde definiremos la información de configuración:
com.mysql.cj.jdbc.Driver jdbc:mysql://localhost:3306/test?serverTimezone=UTC username password org.hibernate.dialect.MySQL5Dialect validate
Hibernate tiene muchas propiedades de configuración. Aparte de las propiedades de conexión estándar, vale la pena mencionar la propiedad del dialecto que nos permite especificar el nombre del dialecto SQL para la base de datos.
Esta propiedad es utilizada por el framework para convertir correctamente las declaraciones de Hibernate Query Language (HQL) en el SQL apropiado para nuestra base de datos dada. Hibernate se envía con más de 40 dialectos SQL. Como nos enfocamos en MySQL en este artículo, nos quedaremos con el dialecto MySQL5Dialect .
Finalmente, Hibernate también necesita saber el nombre completo de la clase de entidad a través de la etiqueta de mapeo. Una vez que completemos la configuración, usaremos la clase SessionFactory , que es la clase responsable de crear y agrupar las conexiones JDBC.
Normalmente, esto solo debe configurarse una vez para una aplicación:
SessionFactory sessionFactory; // configures settings from hibernate.cfg.xml StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build(); try { sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory(); } catch (Exception e) { // handle the exception }
Ahora que tenemos nuestra conexión configurada, podemos ejecutar una consulta para seleccionar a todas las personas de nuestra tabla de personas:
Session session = sessionFactory.openSession(); session.beginTransaction(); List result = session.createQuery("from Person", Person.class).list(); result.forEach(person -> { //do something with Person instance... }); session.getTransaction().commit(); session.close();
4.2. MyBatis
MyBatis se introdujo en 2010 y es un marco mapeador SQL con la simplicidad como su fortaleza . En otro tutorial, hablamos sobre cómo integrar MyBatis con Spring y Spring Boot. Aquí, nos centraremos en cómo configurar MyBatis directamente.
Para usarlo, necesitamos agregar la dependencia mybatis :
org.mybatis mybatis 3.5.3
Suponiendo que reutilizamos la clase Person anterior sin anotaciones, podemos proceder a crear una interfaz PersonMapper :
public interface PersonMapper { String selectAll = "SELECT * FROM Person"; @Select(selectAll) @Results(value = { @Result(property = "id", column = "ID"), @Result(property = "firstName", column = "FIRST_NAME"), @Result(property = "lastName", column = "LAST_NAME") }) List selectAll(); }
El siguiente paso tiene que ver con la configuración de MyBatis:
Configuration initMybatis() throws SQLException { DataSource dataSource = getDataSource(); TransactionFactory trxFactory = new JdbcTransactionFactory(); Environment env = new Environment("dev", trxFactory, dataSource); Configuration config = new Configuration(env); TypeAliasRegistry aliases = config.getTypeAliasRegistry(); aliases.registerAlias("person", Person.class); config.addMapper(PersonMapper.class); return config; } DataSource getDataSource() throws SQLException { MysqlDataSource dataSource = new MysqlDataSource(); dataSource.setDatabaseName("test"); dataSource.setServerName("localhost"); dataSource.setPort(3306); dataSource.setUser("username"); dataSource.setPassword("password"); dataSource.setServerTimezone("UTC"); return dataSource; }
The configuration consists of creating a Configuration object which is a container for settings such as the Environment. It also contains the data source settings.
We can then use the Configuration object, which is normally set up once for an application to create a SqlSessionFactory:
Configuration configuration = initMybatis(); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); try (SqlSession session = sqlSessionFactory.openSession()) { PersonMapper mapper = session.getMapper(PersonMapper.class); List persons = mapper.selectAll(); // do something with persons list ... }
4.3. Apache Cayenne
Apache Cayenne is a persistence framework whose first release dates back to 2002. To learn more about it, we suggest reading our introduction to Apache Cayenne.
As usual, let's add the cayenne-server Maven dependency:
org.apache.cayenne cayenne-server 4.0.2
We're going to specifically focus on the MySQL connection settings. In this case, we'll configure the cayenne-project.xml:
After the automatic generation of the datamap.map.xml and Person class in the form of a CayenneDataObject, we can execute some queries.
For example, we'll continue as previously with a select all:
ServerRuntime cayenneRuntime = ServerRuntime.builder() .addConfig("cayenne-project.xml") .build(); ObjectContext context = cayenneRuntime.newContext(); List persons = ObjectSelect.query(Person.class).select(context); // do something with persons list...
5.Connecting Using Spring Data
Spring Data is a Spring-based programming model for data access. Technically, Spring Data is an umbrella project which contains many subprojects that are specific to a given database.
Let's see how to use two of these projects to connect to a MySQL database.
5.1. Spring Data / JPA
Spring Data JPA is a robust framework that helps reduce boilerplate code and provides a mechanism for implementing basic CRUD operations via one of several predefined repository interfaces. In addition to this, it has many other useful features.
Be sure to check out our introduction to Spring Data JPA to learn more.
The spring-data-jpa artifact can be found on Maven Central:
org.springframework.data spring-data-jpa 2.2.4.RELEASE
We'll continue using the Person class. The next step is to configure JPA using annotations:
@Configuration @EnableJpaRepositories("packages.to.scan") public class JpaConfiguration { @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/test?serverTimezone=UTC"); dataSource.setUsername( "username" ); dataSource.setPassword( "password" ); return dataSource; } @Bean public JpaTransactionManager transactionManager(EntityManagerFactory emf) { return new JpaTransactionManager(emf); } @Bean public JpaVendorAdapter jpaVendorAdapter() { HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter(); jpaVendorAdapter.setDatabase(Database.MYSQL); jpaVendorAdapter.setGenerateDdl(true); return jpaVendorAdapter; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean lemfb = new LocalContainerEntityManagerFactoryBean(); lemfb.setDataSource(dataSource()); lemfb.setJpaVendorAdapter(jpaVendorAdapter()); lemfb.setPackagesToScan("packages.containing.entity.classes"); return lemfb; } }
To allow Spring Data to implement the CRUD operations, we have to create an interface that extends the CrudRepository interface:
@Repository public interface PersonRepository extends CrudRepository { }
And finally, let's see an example of select-all with Spring Data:
personRepository.findAll().forEach(person -> { // do something with the extracted person });
5.2. Spring Data / JDBC
Spring Data JDBC is a limited implementation of the Spring Data family, with its primary goal to allow simple access to relational databases.
For this reason, it doesn't provide features like caching, dirty tracking, lazy loading, and many other JPA features.
This time the Maven dependency we need is spring-data-jdbc:
org.springframework.data spring-data-jdbc 1.1.4.RELEASE
The configuration is lighter compared to the one we used in the previous section for Spring Data JPA:
@Configuration @EnableJdbcRepositories("packages.to.scan") public class JdbcConfiguration extends AbstractJdbcConfiguration { // NamedParameterJdbcOperations is used internally to submit SQL statements to the database @Bean NamedParameterJdbcOperations operations() { return new NamedParameterJdbcTemplate(dataSource()); } @Bean PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dataSource()); } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/test?serverTimezone=UTC"); dataSource.setUsername("username"); dataSource.setPassword("password"); return dataSource; } }
In the case of Spring Data JDBC, we have to define a new Person class or modify the existing one to add some Spring specific annotations.
This is because Spring Data JDBC will take care directly of the entity mapping instead of Hibernate:
import org.springframework.data.annotation.Id; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Table; @Table(value = "Person") public class Person { @Id Long id; @Column(value = "FIRST_NAME") String firstName; @Column(value = "LAST_NAME") String lastName; // getters and setters }
Con Spring Data JDBC, también podemos usar la interfaz CrudRepository . Entonces, la declaración será idéntica a la que escribimos anteriormente en el ejemplo de Spring Data JPA. Del mismo modo, lo mismo se aplica al ejemplo de seleccionar todo.
6. Conclusión
En este tutorial, hemos visto varias formas diferentes de conectarse a una base de datos MySQL desde Java . Comenzamos con la conexión JDBC esencial. Luego examinamos los ORM de uso común como Hibernate, Mybatis y Apache Cayenne. Finalmente, echamos un vistazo a Spring Data JPA y Spring Data JDBC.
El uso de las API de JDBC o Hibernate significa más código repetitivo. El uso de marcos robustos, como Spring Data o Mybatis, requiere más configuración pero brinda una ventaja significativa porque brindan implementaciones y características predeterminadas como almacenamiento en caché y carga diferida.
Fondo de Java