Forskellen mellem erklæring og klargjort erklæring

Java Top

Jeg har lige annonceret det nye Lær foråret kursus med fokus på det grundlæggende i Spring 5 og Spring Boot 2:

>> KONTROLLER KURSEN

1. Oversigt

I denne vejledning undersøger vi forskellene mellem JDBC'er Udmelding og PreparedStatement grænseflader. Vi dækker ikke CallableStatement, en JDBC API-grænseflade, der bruges til at udføre lagrede procedurer.

2. JDBC API-interface

Begge Udmelding og PreparedStatement kan bruges til at udføre SQL-forespørgsler. Disse grænseflader ser meget ens ud. De adskiller sig imidlertid markant fra hinanden med hensyn til funktioner og ydeevne:

  • Udmelding Bruges til at udføre strengbaseret SQL forespørgsler
  • PreparedStatement Bruges til at udføre parametriserede SQL-forespørgsler

At kunne bruge Udmelding og PreparedStatement i vores eksempler erklærer vi h2 JDBC-stik som en afhængighed i vores pom.xml fil:

 com.h2database h2 1.4.200 

Lad os definere en enhed, som vi bruger i denne artikel:

offentlig klasse PersonEntity {privat int id; privat strengnavn; // standard settere og getters}

3. Udmelding

For det første Udmelding interface accepterer strenge som SQL-forespørgsler. Dermed, koden bliver mindre læselig når vi sammenkæder SQL-strenge:

public void insert (PersonEntity personEntity) {String-forespørgsel = "INDSÆT I personer (id, navn) VÆRDIER (" + personEntity.getId () + ", '" + personEntity.getName () + "')"; Erklæringserklæring = connection.createStatement (); statement.executeUpdate (forespørgsel); }

For det andet det er sårbart over for SQL-injektion . De næste eksempler illustrerer denne svaghed.

I første linje indstiller opdateringen kolonnen “navn”På alle rækkerne til“hacker“, Som alt efter“ - ”fortolkes som en kommentar i SQL, og betingelserne for opdateringserklæringen ignoreres. I anden linje mislykkes indsatsen, fordi citatet på "navnKolonne er ikke undsluppet:

dao.update (ny PersonEntity (1, "hacker '-")); dao.insert (ny PersonEntity (1, "O'Brien"))

For det tredje JDBC sender forespørgslen med integrerede værdier til databasen. Derfor er der ingen optimering af forespørgsler, og vigtigst af alt, databasemotoren skal sikre alle kontroller. Forespørgslen vises heller ikke som den samme for databasen og det forhindrer cache-brug. På samme måde skal batchopdateringer udføres separat:

public void insert (List personEntities) {for (PersonEntity personEntity: personEntities) {insert (personEntity); }}

For det fjerde det Udmelding interface er velegnet til DDL-forespørgsler som CREATE, ALTER og DROP :

public void createTables () {String query = "create table if not exist PERSONS (ID INT, NAME VARCHAR (45))"; connection.createStatement (). executeUpdate (forespørgsel); }

Langt om længe, det Udmelding interface kan ikke bruges til at gemme og hente filer og arrays.

4. PreparedStatement

For det første PreparedStatement udvider Udmelding interface. Det har metoder til at binde forskellige objekttyper, inklusive filer og arrays. Derfor, koden bliverlet at forstå:

public void insert (PersonEntity personEntity) {Strengeforespørgsel = "INDSÆT I personer (id, navn) VÆRDIER (?,?)"; PreparedStatement preparedStatement = connection.prepareStatement (forespørgsel); preparedStatement.setInt (1, personEntity.getId ()); preparedStatement.setString (2, personEntity.getName ()); preparedStatement.executeUpdate (); }

For det andet det beskytter mod SQL-injektion, ved at slippe for teksten for alle de angivne parameterværdier:

@Test ugyldigt nårInsertAPersonWithQuoteInText_thenItNeverThrowsAnException () {assertDoesNotThrow (() -> dao.insert (ny PersonEntity (1, "O'Brien"))); } @Test ugyldigt, nårAHackerUpdateAPerson_thenItUpdatesTheTargetedPerson () kaster SQLException {dao.insert (Arrays.asList (ny PersonEntity (1, "john"), ny PersonEntity (2, "skeet"))); dao.update (ny PersonEntity (1, "hacker '-")); Listeresultat = dao.getAll (); assertEquals (Arrays.asList (ny PersonEntity (1, "hacker '-"), ny PersonEntity (2, "skeet")), resultat); }

For det tredje, den PreparedStatement bruger præ-kompilering. Så snart databasen får en forespørgsel, kontrollerer den cachen, inden forudgående kompilering af forespørgslen. Følgelig, Hvis den ikke cachelagres, gemmer databasemotoren den til næste brug.

I øvrigt, denne funktion fremskynder kommunikationen mellem databasen og JVM gennem en ikke-SQL binær protokol. Det vil sige, der er færre data i pakkerne, så kommunikationen mellem serverne går hurtigere.

For det fjerde, den PreparedStatement giver en batchudførelse under en enkelt databaseforbindelse. Lad os se dette i aktion:

public void insert (List personEntities) kaster SQLException {String-forespørgsel = "INDSÆT I personer (id, navn) VÆRDIER (?,?)"; PreparedStatement preparedStatement = connection.prepareStatement (forespørgsel); for (PersonEntity personEntity: personEntities) {preparedStatement.setInt (1, personEntity.getId ()); preparedStatement.setString (2, personEntity.getName ()); preparedStatement.addBatch (); } preparedStatement.executeBatch (); }

Dernæst PreparedStatement giver en nem måde at gemme og hente filer ved hjælp af BLOB og CLOB datatyper. På samme måde hjælper det med at gemme lister ved at konvertere java.sql.Array til en SQL Array.

Endelig er det PreparedStatement implementerer metoder som getMetadata () der indeholder oplysninger om det returnerede resultat.

5. Konklusion

I denne vejledning præsenterede vi de vigtigste forskelle mellem PreparedStatement og Udmelding. Begge grænseflader tilbyder metoder til at udføre SQL-forespørgsler, men det er mere passende at bruge Udmelding til DDL-forespørgsler og PreparedStatement til DML-forespørgsler.

Som sædvanligt er alle kodeeksempler tilgængelige på GitHub.

Java bund

Jeg har lige annonceret det nye Lær foråret kursus med fokus på det grundlæggende i Spring 5 og Spring Boot 2:

>> KONTROLLER KURSEN