Connectez Java à une base de données MySQL

Haut Java

Je viens d'annoncer le nouveau cours Learn Spring , axé sur les principes de base de Spring 5 et Spring Boot 2:

>> VOIR LE COURS

1. Vue d'ensemble

Il existe de nombreuses façons de se connecter à une base de données MySQL à partir de Java et dans ce tutoriel, nous allons explorer plusieurs options pour voir comment y parvenir.

Nous commencerons par examiner sans doute les options les plus populaires utilisant JDBC et Hibernate.

Ensuite, nous examinerons également certaines bibliothèques externes, notamment MyBatis, Apache Cayenne et Spring Data . En cours de route, nous fournirons un certain nombre d'exemples pratiques.

2. Conditions préalables

Nous supposerons que nous avons déjà un serveur MySQL installé et fonctionnant sur localhost (port par défaut 3306) et que nous avons un schéma de test avec la table person suivante:

CREATE TABLE person ( ID INT, FIRST_NAME VARCHAR(100), LAST_NAME VARCHAR(100) );

Nous aurons également besoin de l' artefact mysql-connector-java qui, comme toujours, est disponible depuis Maven Central:

 mysql mysql-connector-java 8.0.19 

3. Connexion à l'aide de JDBC

JDBC (Java Database Connectivity) est une API permettant de connecter et d'exécuter des requêtes sur une base de données.

3.1. Propriétés communes

Au cours de cet article, nous utiliserons généralement plusieurs propriétés JDBC courantes :

  • URL de connexion - une chaîne que le pilote JDBC utilise pour se connecter à une base de données. Il peut contenir des informations telles que l'emplacement de recherche de la base de données, le nom de la base de données à laquelle se connecter et d'autres propriétés de configuration:
    jdbc:mysql://[host][,failoverhost...] [:port]/[database] [?propertyName1][=propertyValue1] [&propertyName2][=propertyValue2]...

    Nous allons définir cette propriété comme suit : jdbc: mysql: // localhost: 3306 / test? ServerTimezone = UTC

  • Classe de pilote - le nom de classe complet du pilote à utiliser. Dans notre cas, nous utiliserons le pilote MySQL: com.mysql.cj.jdbc.Driver
  • Nom d'utilisateur et mot de passe - les informations d'identification du compte MySQL

3.2. Exemple de connexion JDBC

Voyons comment nous pouvons nous connecter à notre base de données et exécuter un simple select-all via un try-with-multiple-resources:

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 }

Comme nous pouvons le voir, à l'intérieur du corps try , nous parcourons l'ensemble de résultats et extrayons les valeurs de la table person.

4. Connexion à l'aide d'ORM

Plus généralement, nous nous connecterons à notre base de données MySQL à l'aide d'un framework ORM (Object Relational Mapping) . Voyons donc quelques exemples de connexion utilisant le plus populaire de ces frameworks.

4.1. API natives Hibernate

Dans cette section, nous verrons comment utiliser Hibernate pour gérer une connexion JDBC à notre base de données.

Tout d'abord, nous devons ajouter la dépendance Maven hibernate-core :

 org.hibernate hibernate-core 5.4.10.Final 

Hibernate nécessite qu'une classe d'entité soit créée pour chaque table. Allons-y et définissons la classe 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 } 

Un autre aspect essentiel est de créer le fichier de ressources Hibernate, généralement nommé hibernate.cfg.xml , où nous définirons les informations de configuration:

     com.mysql.cj.jdbc.Driver jdbc:mysql://localhost:3306/test?serverTimezone=UTC username password  org.hibernate.dialect.MySQL5Dialect  validate    

Hibernate has many configuration properties. Apart from the standard connection properties, it is worth mentioning the dialect property which allows us to specify the name of the SQL dialect for the database.

This property is used by the framework to correctly convert Hibernate Query Language (HQL) statements into the appropriate SQL for our given database. Hibernate ships with more than 40 SQL dialects. As we're focussing on MySQL in this article, we'll stick with the MySQL5Dialect dialect.

Finally, Hibernate also needs to know the fully-qualified name of the entity class via the mapping tag. Once we complete the configuration, we'll use the SessionFactory class, which is the class responsible for creating and pooling JDBC connections.

Typically, this only needs to be set up once for an application:

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 }

Now that we have our connection set up, we can run a query to select all the people from our person table:

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 was introduced in 2010 and is a SQL mapper framework with simplicity as its strength. In another tutorial, we talked about how to integrate MyBatis with Spring and Spring Boot. Here, we'll focus on how to configure MyBatis directly.

To use it, we need to add the mybatis dependency:

 org.mybatis mybatis 3.5.3 

Assuming that we reuse the Person class above without annotations, we can proceed to create a PersonMapper interface:

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(); }

The next step is all about the MyBatis configuration:

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 }

Avec Spring Data JDBC, nous pouvons également utiliser l' interface CrudRepository . La déclaration sera donc identique à celle que nous avons écrite ci-dessus dans l'exemple Spring Data JPA. De même, la même chose s'applique à l'exemple de sélection de tout.

6. Conclusion

Dans ce tutoriel, nous avons vu plusieurs façons différentes de se connecter à une base de données MySQL depuis Java . Nous avons commencé avec la connexion JDBC essentielle. Ensuite, nous avons examiné les ORM couramment utilisés comme Hibernate, Mybatis et Apache Cayenne. Enfin, nous avons examiné Spring Data JPA et Spring Data JDBC.

L'utilisation d'API JDBC ou Hibernate signifie plus de code standard. L'utilisation de frameworks robustes, tels que Spring Data ou Mybatis, nécessite plus de configuration mais donne un avantage significatif car ils fournissent des implémentations et des fonctionnalités par défaut telles que la mise en cache et le chargement différé.

Fond Java

Je viens d'annoncer le nouveau cours Learn Spring , axé sur les principes de base de Spring 5 et Spring Boot 2:

>> VOIR LE COURS