Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Introduction

  • Eviter que les données disparaissent lorsque le programme se termine
  • Communiquer par l'intermédiaire des données avec d'autres applications

JDBC

Se connecter à une BDD

String url = "jdbc:mysql://localhost:3306/mabase";
String user = "root"; String pwd = "root";
java.sql.Connection connexion = null;
try {
    connexion = java.sql.DriverManager.getConnection(url, user, pwd);
    //L'object connexion va nous permettre d'effectuer des requêtes...
    ...
} catch ( java.sql.SQLException e ) {
    //Problème de connexion à la base !
}

//Lorsqu'on a fini de l'utiliser : 
if(connexion != null) {
  try {
    connexion.close();
  }
  catch ( java.sql.SQLException e ) {
    //Problème de déconnexion, ce n'est pas très grave...
  }
}

Exécuter une requête SELECT

//La variable de type Statement permettra de gérer des requêtes SQL
Statement statement = connexion.createStatement();

//La variable de type ResultSet contiendra les résultats de la requêtes
String query = "SELECT id, marque, modele, date_mise_circulation FROM vehicule";
ResultSet resultSet = statement.executeQuery(query);

//On parcours un à un les résultats grâche à next() qui renvoie un booléen
//précisant s'il y a une ligne suivante dans nos résultats et récupère ce 
//résultat le cas échéant (au début, son curseur est situé avant le premier élément).
while(resultSet.next()){
  System.out.println("Identifiant : " + resultSet.getInt("id"));
  System.out.println("Marque : " + resultSet.getString("marque"));
  System.out.println("Modèle : " + resultSet.getString(3));
  System.out.println("Date MC : " + resultSet.getDate("date_mise_circulation"));
  System.out.println("? : " + resultSet.getBoolean("inconnu"));//SQLException
}

Exécuter une requête UPDATE, DELETE ou INSERT

Statement statement = connexion.createStatement();

String query = "INSERT INTO vehicule(marque, modele) VALUES ('Peugeot', '208')";
int status = statement.executeUpdate(query);//nombre de lignes insérées

query = "DELETE FROM vehicule WHERE marque = 'Renault'";
status = statement.executeUpdate(query);//nombre de lignes supprimées

query = "UPDATE FROM vehicule SET marque = 'Lada' WHERE marque = 'LADA'";
status = statement.executeUpdate(query);//nombre de lignes mises à jour

Requêtes dynamiques

//Soient les variables marque et modele contenant 
//des valeurs renseignée par l'utilisateur
String query = "SELECT * FROM vehicule WHERE marque = '" + 
  marque + "')";
statement.executeQuery(query);//OK !
//Que se passe-t-il si modele vaut "test' OR '1' = '1" ?

//La solution ? Les Prepared Statements
String queryPrep = "SELECT * FROM vehicule WHERE marque = ? AND modele = ?)";
PreparedStatement statement = connexion.prepareStatement(queryPrep);
statement.setString(1, marque);
statement.setString(2, modele);
statement.executeQuery();

Avantages/Inconvénients

  • Contrôle
  • Au plus prêt du SGBD
  • Performances
  • Récupération des résultats pas pratique
  • Totalement dépendant du SGBD
  • Tres verbeux
  • Gestion manuelle des connexions fastidieuse
  • Maintenabilité et évolutivité

JPA et Hibernate

Les Entités

import javax.persistence.*;

@Entity
@Table(name = "vehicule")
public class Vehicule {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(name = "marque")//superflu car noms identiques
  private String marque;

  private String modele;

  private String immatriculation;

  @Column(name = "date_mise_circulation")
  private Date dateMiseCirculation;
}

Spring

Les Repository

  • En fournissant des méthodes toute prêtes
  • En permettant de générer des requêtes sans écrire une ligne de SQL
  • En proposant des fonctionnalités de pagination
  • En permettant d'écrire des requêtes en pseudo-langage SQL
  • En permettant d'écrire des requêtes en SQL natif

JpaRepository

public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
  <S extends T> S save(S entity);
  <S extends T> List<S> saveAll(Iterable<S> var1);
  Optional<T> findById(ID id);
  T getOne(ID var1);
  List<T> findAllById(Iterable<ID> var1);
  List<T> findAll();
  boolean existsById(ID id);
  long count();
  void deleteById(ID id);
  void delete(T entity);
  void deleteAll(Iterable<? extends T> entities);
  void deleteAll();
  //...
}
//Fichier VehiculeRepository.java
public interface VehiculeRepository extends JpaRepository<Vehicule,Integer> {}

Opérations de C(R)UD

@Service
public class VehiculeService {
  @Autowired
  private VehiculeRepository vehiculeRepository;
  ...
  public void test(){
    //Create
    Vehicule v = vehiculeRepository.save(new Vehicule("Peugeot", "208"));
    
    //Read
    Vehicule v2 = vehiculeRepository.findById(5).get();
    ...
    v2.setDateMiseCirculation(new Date());
    
    //Update
    v2 = vehiculeRepository.save(v2);
    ...
    
    //Delete
    vehiculeRepository.delete(v2);
  }

Pagination et tri

public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
  Iterable<T> findAll(Sort sort);
  Page<T> findAll(Pageable pageable);
}
//Fichier VehiculeRepository.java
public interface VehiculeRepository extends JpaRepository<Vehicule,Integer> {}
//Classe VehiculeService
@Autowired
private VehiculeRepository vehiculeRepository;
...
public Page<Vehicule> findAllVehiculesPaging(Integer page, Integer size){
  PageRequest pageRequest = PageRequest.of(page, size, Sort.Direction.ASC, "immatriculation");
  return vehiculeRepository.findAll(pageRequest);
}
public List<Vehicule> findAllVehiculesSortingDesc(String attribute){
  return vehiculeRepository.findAll(Sort.by(Sort.Direction.DESC, attribute));
}
//Autre classe utilisant VehiculeService
vehiculeService.findAllVehiculesPaging(0,5).forEach(System.out::println);
vehiculeService.findAllVehiculesSortingDesc("immatriculation").forEach(System.out::println);

Génération de requête

public interface VehiculeRepository extends CrudRepository<Vehicule,Integer> {
  //SELECT * FROM vehicule WHERE immatriculation = ?;
  Vehicule findByImmatriculation(String immatriculation);
  //SELECT * FROM vehicule WHERE marque = ? AND modele = ?;
  List<Vehicule> findByMarqueAndModele(String marque, String modele);
  //SELECT * FROM vehicule WHERE lower(marque) = ?;
  List<Vehicule> findByMarqueIgnoreCase(String nom);
  //Idem mais avec pagination
  Page<Vehicule> findByMarqueIgnoreCase(String nom, Pageable pageable);
  //SELECT * FROM vehicule WHERE date_mise_circulation < ?;
  List<Vehicule> findByDateMiseCirculationBefore(LocalDate date);
  //SELECT * FROM vehicule WHERE puissance > ? ORDER BY immatriculation DESC;
  List<Vehicule> findByPuissanceGreaterThanOrderByImmatriculationDesc(Integer puissance);
}

Mots supportés dans les noms des méthodes

Mot-clé Exemple Equivalent JPQL
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (paramètre + %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (% + paramètre)
Containing findByFirstnameContaining … where x.firstname like ?1 (paramètre entre deux %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

Requêtes JPQL

public interface VehiculeRepository extends CrudRepository<Vehicule,Integer> {
  
  @Query("select v from Vehicule v where length(v.marque) = ? ")
  List<Vehicule> findByLongueurMarque(Integer longueur);
}

Requêtes natives

public interface ProprietaireRepository extends CrudRepository<Proprietaire,Integer> {
  
  @Query(value = "SELECT p.* FROM proprietaire p " +
  "INNER JOIN vehicule v ON v.proprietaire_id = p.id " +
  "WHERE v.marque = :marque1 " +
  "AND EXISTS ( " +
    "SELECT p2.* FROM proprietaire p2 " +
    "INNER JOIN vehicule v2 ON v2.proprietaire_id = p2.id " +
    "WHERE p2.id = p.id" +
    "AND v2.marque = :marque2 " +
  ")", nativeQuery = true)
  List<Proprietaire> findByDeuxMarques(@Param("marque1") String marque1, @Param("marque2") String marque2);
}

Relations

Relations OneToOne unidirectionnel

@Entity
public class Vehicule {
  ...

  @OneToOne
  @JoinColumn(name = "contrat_id", nullable = false)
  //Le nullable = false est nécessaire si la FK a été
  //définie en NOT NULL. Sinon on peut l'enlever.
  private ContratAssurance contrat;
}

@Entity
public class ContratAssurance {
  ...
  
}

Relations OneToOne bidirectionnel

@Entity
public class Vehicule {
  ...

  @OneToOne
  @JoinColumn(name = "contrat_id", nullable = false)
  //Le nullable = false est nécessaire si la FK a été
  //définie en NOT NULL. Sinon on peut l'enlever.
  private ContratAssurance contrat;
}

@Entity
public class ContratAssurance {
  ...
  @OneToOne( mappedBy = "contrat" )
  private Vehicule vehicule;
}

Relations OneToMany unidirectionnel

@Entity
public class Vehicule {
  ...

  @OneToMany
  @JoinColumn( name = "vehicule_id")
  private List<Entretien> entretiens;
}

@Entity
public class Entretien {
  ...
}

Relations OneToMany bidirectionnel

@Entity
public class Vehicule {
  ...

  @OneToMany( mappedBy = "vehicule" )
  private List<Entretien> entretiens;
}

@Entity
public class Entretien {
  ...

  @ManyToOne
  @JoinColumn( name = "vehicule_id" )
  private Vehicule vehicule;
}

Relations ManyToMany

@Entity
public class Vehicule {
  ...
  @ManyToMany(mappedBy = "vehicules")
  private List<Proprietaire> proprietaires;
}

@Entity
public class Proprietaire {
  ...
  @ManyToMany
  @JoinTable(name = "Vehicules_Proprietaires",
    joinColumns = @JoinColumn(name = "proprietaire_id"), 
    inverseJoinColumns = @JoinColumn(name = "vehicule_id")
  )
  private List<Vehicule> vehicules;
}

Héritage

  • Mapped superclass
  • Table per class
  • Single table
  • Joined

Mapped Superclass

@MappedSuperclass
public abstract class Publication {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  protected Long id;
  protected String title;
  private int version;
  private Date publishingDate;
}

@Entity
public class Book extends Publication {
  private int pages;
}

@Entity
public class BlogPost extends Publication {
  private String url;
}

Table Per Class

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Publication {
  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  protected Long id;
  protected String title;
  private int version;
  @ManyToMany @JoinTable(name = "PublicationAuthor"...)
  private Set authors = new HashSet();
  private Date publishingDate;
}
@Entity
public class Book extends Publication {
  private int pages;
}
@Entity
public class BlogPost extends Publication {
  private String url;
}

Single Table

@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "Publication_Type")
public abstract class Publication {
  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  protected Long id;
  protected String title;
  private int version;
  @ManyToMany @JoinTable(name = "PublicationAuthor"...)
  private Set authors = new HashSet();
  private Date publishingDate;
}
@Entity @DiscriminatorValue("Book")
public class Book extends Publication {
  private int pages;
}
@Entity @DiscriminatorValue("Blog")
public class BlogPost extends Publication {
  private String url;
}

Joined

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Publication {
  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  protected Long id;
  protected String title;
  private int version;
  @ManyToMany
  @JoinTable(name = "PublicationAuthor"...)
  private Set authors = new HashSet();
  private Date publishingDate;
}
@Entity
public class Book extends Publication {
  private int pages;
}
@Entity
public class BlogPost extends Publication {
  private String url;
}