Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Bekerja dengan JDBC dan Spring

Dalam skenario aplikasi dunia nyata, sejumlah besar pemrosesan dilakukan di server backend di mana data benar-benar diproses dan disimpan ke dalam repositori. Terlepas dari banyak fitur Spring yang menonjol, seperti DI (Dependency Injection), Aspects, dan pengembangan berorientasi POJO, Spring memiliki dukungan yang sangat baik untuk penanganan data. Ada berbagai cara untuk menulis aplikasi database yang baik. Masih hari ini, sejumlah besar aplikasi ditulis berdasarkan kemampuan akses data JDBC. Artikel ini secara khusus membahas JDBC sehubungan dengan Spring, dukungannya, dan pro dan kontra dengan contoh dan cuplikan kode yang sesuai.

Ikhtisar JDBC

Salah satu keuntungan terbesar masih menggunakan JDBC di dunia ORM adalah tidak perlu menguasai bahasa kueri kerangka kerja lain selain bekerja dengan data pada tingkat yang jauh lebih rendah. Ini memungkinkan seorang programmer untuk mengambil keuntungan dari fitur-fitur milik database. Ini memiliki kekurangannya juga. Sayangnya, kekurangannya seringkali begitu terlihat sehingga tidak perlu disebutkan. Misalnya, salah satunya adalah kode boilerplate . Istilah kode boilerplate pada dasarnya berarti menulis kode yang sama berulang kali tanpa memasukkan nilai apa pun ke dalam kode. Ini biasanya dapat dilihat ketika kita melakukan query data dari database; misalnya, dalam kode berikut, kita cukup mengambil Pengguna merekam dari database.

publik Pengguna getUserById(panjang id) { Pengguna pengguna =null; Koneksi con =null; PreparedStatement pstmt =null; ResultSet rs =null; coba { con =dataSource.getConnection(); pstmt =con.prepareStatement("pilih * dari " + "user_table dimana userid=?"); pstmt.setInt(1, id); rs.pstmt.executeQuery(); jika (rs.next()) { pengguna =baru Pengguna(); user.setId(rs.getInt("userid")); user.setFullName(rs.getString("nama lengkap")); user.setUserType(rs.getString("usertype")); user.setPassword(rs.getString("password")); } } menangkap (SQLException ex1) {} akhirnya { coba { jika (rs !=null ) rs.close(); jika (pstmt !=null ) rs.close(); jika (con !=null ) rs.close(); } tangkap (SQLException ex2) {} } kembalikan pengguna;}

Perhatikan bahwa, setiap kali kita perlu berinteraksi dengan database, kita harus membuat tiga objek—koneksi (Koneksi ), pernyataan (PreparedStatement ), dan resultset (ResultSet ). Semua ini juga harus dilampirkan dalam try…catch yang dipaksakan memblokir. Bahkan penutupan koneksi juga harus dilampirkan dalam try…catch . Ini menggelikan karena kode yang dibutuhkan sebenarnya untuk fungsi tersebut jauh lebih sedikit. Kode hanya dibesar-besarkan dengan kode yang tidak perlu tetapi wajib dan harus diulang di mana pun kita berinteraksi dengan database. Skema pengkodean yang cerdas dapat mengurangi kekacauan ini, namun tidak mungkin untuk menghilangkan masalah kode JDBC boilerplate. Ini bukan hanya masalah dengan JDBC tetapi juga JMS, JNDI, dan REST.

Solusi Musim Semi

Kerangka kerja Spring memberikan solusi untuk kekacauan ini dan menyediakan sarana untuk menghilangkan kode boilerplate dengan menggunakan kelas template. Kelas-kelas ini merangkum kode boilerplate, sehingga membebaskan programmer. Ini berarti bahwa kode boilerplate masih ada, hanya programmer yang menggunakan salah satu kelas template dibebaskan dari kesulitan menulisnya. JdbcTemplate disediakan oleh Spring adalah kelas pusat dari paket inti JDBC.

Ini menyederhanakan penggunaan JDBC dan membantu menghindari kesalahan umum. Ini mengeksekusi alur kerja inti JDBC, meninggalkan kode aplikasi untuk menyediakan SQL dan mengekstrak hasil. Kelas ini mengeksekusi kueri atau pembaruan SQL, memulai iterasi pada ResultSets dan menangkap pengecualian JDBC dan menerjemahkannya ke hierarki pengecualian generik yang lebih informatif yang ditentukan dalam org.springframework.dao paket.

Kami hanya perlu mengimplementasikan antarmuka panggilan balik dan memberi mereka kontrak yang jelas dan terdefinisi. Misalnya, PreparedStatementCreator antarmuka panggilan balik digunakan untuk membuat pernyataan yang disiapkan. ResultsetExtractor antarmuka bertindak seperti ResultSet .

Oleh karena itu, cuplikan kode sebelumnya dapat ditulis ulang dengan JdbcTemplate sebagai berikut:

@Autowiredpribadi JdbcTemplate jdbcTemplate;publik Pengguna getUserById(panjang id) { kembali jdbcTemplate.queryForObject( "pilih * dari user_table dimana userid=?", baru UserRowMapper(),id); }kelas UserRowMapper menerapkan RowMapper{ @Override publik Pengguna mapRow(ResultSet rs, int runNumber) melempar SQLException { Pengguna pengguna=baru Pengguna(); user.setId(rs.getInt("userid")); user.setFullName(rs.getString("nama lengkap")); user.setUserType(rs.getString("usertype")); user.setPassword(rs.getString("password")); kembali pengguna; }}

RowMapper adalah antarmuka yang biasanya digunakan oleh JdbcTemplate untuk memetakan satu baris per basis baris ResultSet . RowMapper objek tidak memiliki kewarganegaraan dan oleh karena itu dapat digunakan kembali. Mereka sempurna untuk menerapkan logika pemetaan baris apa pun. Perhatikan bahwa, pada kode sebelumnya, kami tidak menangani pengecualian secara eksplisit seperti yang telah kami lakukan pada kode yang tidak menggunakan JdbcTemplate . Implementasi RowMapper melakukan implementasi aktual dari pemetaan setiap baris ke objek hasil tanpa perlu khawatir tentang penanganan pengecualian oleh programmer. Ini akan dipanggil dan ditangani dengan memanggil JdbcTemplate .

Pengecualian

Pengecualian yang diberikan oleh JDBC seringkali terlalu memaksakan dari yang diperlukan, dengan sedikit nilai. Hirarki pengecualian akses data Spring lebih ramping dan masuk akal dalam hal ini. Ini berarti bahwa ia memiliki serangkaian kelas pengecualian yang konsisten di gudang senjatanya, berbeda dengan JDBC yang satu ukuran cocok untuk semua pengecualian yang disebut SQLException untuk semua masalah yang berkaitan dengan akses data. Pengecualian akses data Spring di-root dengan DataAccessException kelas. Oleh karena itu, kita dapat memiliki pilihan pengecualian yang dicentang vs. tidak dicentang yang tertanam ke dalam kerangka kerja. Ini terdengar lebih praktis karena sebenarnya tidak ada solusi untuk banyak masalah yang terjadi selama akses data runtime dan tidak ada gunanya kita menangkapnya ketika kita tidak dapat mengatasi situasi dengan alternatif yang sesuai.

Cara Musim Semi Menyederhanakan Akses Data

Apa yang sebenarnya dilakukan Spring adalah membedakan bagian tetap dan variabel dari mekanisme akses data menjadi dua set kelas yang disebut kelas template dan kelas panggilan balik , masing-masing. Bagian kode yang tetap mewakili bagian akses data yang asal-asalan dan bagian variabel adalah metode akses data yang bervariasi sesuai dengan kebutuhan yang berubah.

Singkatnya, kelas template menangani:

  • Kontrol transaksi
  • Pengelolaan sumber daya
  • Penanganan pengecualian

Dan, kelas panggilan balik menangani:

  • Membuat pernyataan kueri
  • Pengikatan parameter
  • Pengaturan hasil menyusun

Kita dapat memilih satu di antara banyak kelas template, sesuai dengan pilihan teknologi persisten yang digunakan. Misalnya, untuk JDBC kita dapat memilih JdbcTemplate , atau untuk ORM kami dapat memilih JpaTemplate , Templat Hibernasi , dan seterusnya.

Sekarang, saat menghubungkan ke database, kami memiliki tiga opsi untuk mengonfigurasi sumber data, seperti:

  • Didefinisikan oleh driver JDBC
  • Dicari oleh JNDI
  • Diambil dari kumpulan koneksi

Aplikasi siap produksi biasanya menggunakan kumpulan koneksi atau JNDI. Sumber data yang ditentukan driver JDBC sejauh ini adalah yang paling sederhana, meskipun sebagian besar digunakan untuk tujuan pengujian. Spring menawarkan tiga kelas dalam paket org.springframework.jdbc.datasource dari kategori ini; mereka adalah:

  • DriverManagerDataSource: Implementasi sederhana dari JDBC standar DataSource antarmuka, mengonfigurasi JDBC lama yang polos DriverManager melalui properti kacang, dan mengembalikan Koneksi baru dari setiap permintaan.
  • SingleConnectionDataSource: Mengembalikan koneksi yang sama pada setiap permintaan. Jenis koneksi ini terutama ditujukan untuk pengujian.
  • SimpleDriverDataSource: Sama seperti DriverManagerDataSource kecuali bahwa ia memiliki masalah pemuatan kelas khusus seperti OSGi; kelas ini langsung bekerja dengan Driver JDBC.

Konfigurasi sumber data ini serupa. Kita dapat mengonfigurasinya dalam kelas kacang atau melalui XML.

// Mengonfigurasi sumber data MySQL@Beanpublik DataSource dataSource() { DriverManagerDataSource ds=baru DriverManagerDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/testdb"); ds.setUsername("root"); ds.setPassword("rahasia"); kembali ds;} encoding="UTF-8" ?>"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 http://maven.Apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.mano.springbootjdbc.demo spring-boot-jdbc-demo 0.0.1-SNAPSHOT jar spring-boot-jdbc-demo Proyek demo untuk Spring Boot jdbc  org.springframework.boot spring-boot-starter-parent 1.5.10.RELEASE     UTF-8  UTF-8  1.8    org.springframework.boot spring-boot-starter-jdbc   mysql mysql-connector-java runtime   org.springframework.boot spring-boot-starter-test test      org.springframework.boot spring-boot-maven- plugin   

Kelas Model:Candidate.java

paket org.mano.springbootjdbc.demo.model;kelas publik Kandidat { int pribadi Indo; pribadi String nama lengkap; pribadi string email; pribadi Tali telepon; publik Kandidat() { super (); } publik Kandidat(int id, String nama lengkap, String email, String telepon) { super (); setId(id); setNama lengkap(nama lengkap); setEmail(email); setTelepon(telepon); } kedalaman publik getId() { kembali Indo; } kekosongan publik setId(int id) { ini .id =identitas; } publik String getFullname() { kembali nama lengkap; } kekosongan publik setFullname(String fullname) { ini .nama lengkap =nama lengkap; } publik String getEmail() { kembali surel; } kekosongan publik setEmail(String email) { ini .email =email; } publik String getPhone() { kembali telepon; } kekosongan publik setPhone(Telepon string) { ini .telepon =telepon; } @Ganti publik String toString() { kembali "Calon [id=" + id + ", nama lengkap=" + nama lengkap + ", email=" + email + ", telepon=" + telepon + "]"; }}

Antarmuka Objek Akses Data:CandidateDao.java

paket org.mano.springbootjdbc.demo.dao;impor java.util.List;impor org.mano.springbootjdbc.demo.model.Candidate;antarmuka publik CandidateDao { kekosongan publik addCandidate(Calon kandidat); kekosongan publik modidateCandidate(Calon kandidat, int calonId); kekosongan publik deleteCandidate(int calonId); publik Temukan kandidat(int calonId); publik Daftar findAll();}

Kelas Implementasi Objek Akses Data:CandidateDaoImpl.java

paket org.mano.springbootjdbc.demo.dao;impor java.util.ArrayList;impor java.util.List;impor org.mano.springbootjdbc.demo.model.Candidate;impor org.springframework.beans.factory.annotation.Autowired;impor org.springframework.beans.factory.annotation.Qualifier;impor org.springframework.jdbc.core.BeanPropertyRowMapper;impor org.springframework.jdbc.core.JdbcTemplate;impor org.springframework.stereotype.Repository;@Repository@Qualifier("candidateDao")kelas publik CandidateDaoImpl menerapkan KandidatDao { @Autowired JdbcTemplate jdbcTemplate; @Override kekosongan publik addCandidate(Calon kandidat) { jdbcTemplate.update("masukkan ke kandidat (id,nama lengkap,email,telepon) " + "nilai (?,?,?,?)", kandidat.getId(), kandidat.getFullname(), kandidat.getEmail(), kandidat.getPhone()); Sistem.keluar  .println(calon+" berhasil ditambahkan!"); } @Override kekosongan publik modidateCandidate(Calon kandidat, int kandidatId) { jdbcTemplate.update("perbarui nama lengkap kandidat=?, email=?,telepon=? " + "di mana id=? nilai (?,?,?,?)",candidate.getFullname(), kandidat.getEmail( ), calonId); Sistem.keluar  .println("Calon dengan id="+candidateId+ " berhasil diubah!"); } @Override kekosongan publik deleteCandidate(int kandidatId) { jdbcTemplate.update("hapus dari kandidat dimana id=?", CandidateId); Sistem.keluar  .println("Calon dengan id="+candidateId+ " berhasil dihapus!"); } @Ganti publik Temukan kandidat(int kandidatId) { Kandidat c =null; c =(Calon) jdbcTemplate.queryForObject("pilih * dari kandidat " + "di mana id=?", baru Objek[] { calonId }, baru BeanPropertyRowMapper(Calon. kelas )); kembali c; } @Ganti publik Daftar findAll() { Daftar kandidat =baru Daftar Array<>(); kandidat =jdbcTemplate.query("pilih * dari kandidat", baru BeanPropertyRowMapper (Calon.kelas )); kembali calon; }}

Kelas Spring Boot Loader:SpringBootJdbcDemoApplication.java

paket org.mano.springbootjdbc.demo;impor java.util.List;impor org.mano.springbootjdbc.demo.dao.CandidateDao;impor org.mano.springbootjdbc.demo.model.Candidate;impor org.springframework.beans.factory.annotation.Autowired;impor org.springframework.boot.CommandLineRunner;impor org.springframework.boot.SpringApplication;impor org.springframework.boot.autoconfigure. SpringBootApplication;@SpringBootApplicationkelas publik SpringBootJdbcDemoApplication menerapkan CommandLineRunner { @Autowired pribadi CalonDao cdao; kekosongan statis publik main(String[] args) { Aplikasi Musim Semi.jalankan (SpringBootJdbcDemoApplication. kelas , argumen); } @Override kekosongan publik lari(String... arg0) melempar Pengecualian { Kandidat c1 =baru Kandidat(1, "Sachin Tendulkar", "[email protected]", "1234567890"); Kandidat c2 =baru Kandidat(2, "Amit Saha", "[email protected]", "9632587410"); Kandidat c3 =baru Kandidat(3, "Sandip Paul", "[email protected]", "8527419630"); Kandidat c4 =baru Kandidat(4, "Rajib Kakkar", "[email protected]", "9876543210"); Kandidat c5 =baru Kandidat(5, "Rini Simon", "[email protected]", "8624793150"); cdao.addCalon(c1); cdao.addCandidate(c2); cdao.addKandidat(c3); cdao.addCalon(c4); cdao.addCalon(c5); List kandidat =cdao.findAll(); untuk (Calon kandidat :​​kandidat) { System.keluar  .println(calon); } cdao.deleteCandidate(3); kandidat =cdao.findAll(); untuk (Calon cc :kandidat) { System.keluar  .println(cc); } }}

Application.properties

spring.driverClassName=com.mysql.jdbc.Driverspring.url=jdbc:mysql://localhost:3306/testdbspring.username=rootspring.password=secret

Jalankan Aplikasi

Untuk menjalankan aplikasi, klik kanan proyek di Project Explorer panel dan pilih Jalankan Sebagai -> Aplikasi Boot Musim Semi . Itu saja.

Kesimpulan

Kami memiliki tiga opsi untuk bekerja dengan pemrograman Database Relasional dengan Spring:

  • JDBC kuno dengan Musim Semi. Ini berarti menggunakan kerangka kerja Spring untuk semua tujuan praktis dalam program kecuali dukungan data Spring.
  • Menggunakan kelas template JDBC. Spring menawarkan kelas abstraksi JDBC untuk mengkueri database relasional; ini jauh lebih sederhana daripada bekerja dengan kode JDBC asli.
  • Spring juga memiliki dukungan yang sangat baik untuk kerangka kerja ORM (Object Relational Mapping) dan dapat berintegrasi dengan baik dengan implementasi JPA (Java Persistent Annotation) API yang menonjol seperti Hibernate. Ia juga memiliki bantuan Spring Data JPA sendiri yang dapat secara otomatis menghasilkan implementasi repositori dengan cepat saat runtime.

Jika seseorang memilih JDBC karena alasan tertentu, lebih baik menggunakan dukungan template Spring seperti JdbcTemplate selain menggunakan ORM.

Referensi

  • Dinding, Tebing. Aksi Musim Semi 4 , Publikasi Manning
  • Dokumentasi Spring 5 API

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pelajari Cara Menggunakan Pernyataan CASE Dalam SQL

  2. Notasi Kaki Gagak

  3. Cara menghapus kolom dalam tabel

  4. Denormalisasi:Kapan, Mengapa, dan Bagaimana

  5. Pernyataan SQL SELECT