JavaRush /Java Blog /Random-ID /JDBC atau tempat semuanya dimulai
Viacheslav
Level 3

JDBC atau tempat semuanya dimulai

Dipublikasikan di grup Random-ID
Di dunia modern, tidak ada cara tanpa penyimpanan data. Dan sejarah bekerja dengan database dimulai sejak lama, dengan munculnya JDBC. Saya mengusulkan untuk mengingat sesuatu yang tanpanya tidak ada kerangka kerja modern yang dibangun di atas JDBC. Selain itu, bahkan ketika bekerja dengan mereka, terkadang Anda mungkin memerlukan kesempatan untuk “kembali ke asal Anda”. Saya harap ulasan ini dapat membantu sebagai pengenalan atau membantu menyegarkan ingatan Anda.
JDBC atau tempat semuanya dimulai - 1

Perkenalan

Salah satu tujuan utama bahasa pemrograman adalah menyimpan dan memproses informasi. Untuk lebih memahami cara kerja penyimpanan data, ada baiknya meluangkan sedikit waktu untuk mempelajari teori dan arsitektur aplikasi. Misalnya saja Anda dapat membaca literatur yaitu buku “ Software Architect's Handbook: Menjadi seorang arsitek perangkat lunak yang sukses dengan menerapkan lengkungan yang efektif... ” oleh Joseph Ingeno. Seperti yang dikatakan, ada Tingkat Data atau “Lapisan Data” tertentu. Ini mencakup tempat untuk menyimpan data (misalnya, database SQL) dan alat untuk bekerja dengan penyimpanan data (misalnya, JDBC, yang akan dibahas). Ada juga artikel di situs web Microsoft: “ Merancang lapisan persistensi infrastruktur ,” yang menjelaskan solusi arsitektur untuk memisahkan lapisan tambahan dari Tingkat Data - Lapisan Persistensi. Dalam hal ini, Data Tier adalah tingkat penyimpanan data itu sendiri, sedangkan Persistence Layer adalah beberapa tingkat abstraksi untuk bekerja dengan data dari penyimpanan dari tingkat Data Tier. Lapisan Persistensi dapat menyertakan template "DAO" atau berbagai ORM. Tapi ORM adalah topik untuk diskusi lain. Seperti yang mungkin sudah Anda pahami, Tingkat Data muncul pertama kali. Sejak JDK 1.1, JDBC (Java DataBase Connectivity - koneksi ke database di Java) telah muncul di dunia Java. Ini adalah standar interaksi aplikasi Java dengan berbagai DBMS, diimplementasikan dalam bentuk paket java.sql dan javax.sql yang disertakan dalam Java SE:
JDBC atau tempat semuanya dimulai - 2
Standar ini dijelaskan dengan spesifikasi " JSR 221 JDBC 4.1 API ". Spesifikasi ini memberitahu kita bahwa JDBC API menyediakan akses terprogram ke database relasional dari program yang ditulis dalam Java. Ini juga memberitahukan bahwa JDBC API adalah bagian dari platform Java dan oleh karena itu termasuk dalam Java SE dan Java EE. JDBC API disediakan dalam dua paket: java.sql dan javax.sql. Kalau begitu, mari kita kenali mereka.
JDBC atau tempat semuanya dimulai - 3

Awal pekerjaan

Untuk memahami apa itu JDBC API secara umum, kita memerlukan aplikasi Java. Paling mudah menggunakan salah satu sistem perakitan proyek. Misalnya, mari kita gunakan Gradle . Anda dapat membaca lebih lanjut tentang Gradle dalam ulasan singkat ini: " Pengantar Singkat tentang Gradle ". Pertama, mari kita inisialisasi proyek Gradle baru. Karena fungsionalitas Gradle diimplementasikan melalui plugin, kita perlu menggunakan “ Gradle Build Init Plugin ” untuk inisialisasi:
gradle init --type java-application
Setelah ini, mari kita buka skrip build - file build.gradle , yang menjelaskan proyek kita dan cara bekerja dengannya. Kami tertarik pada blok " dependencies ", di mana dependensi dijelaskan - yaitu, perpustakaan/kerangka/api tersebut, yang tanpanya kami tidak dapat bekerja dan menjadi sandaran kami. Secara default kita akan melihat sesuatu seperti:
dependencies {
    // This dependency is found on compile classpath of this component and consumers.
    implementation 'com.google.guava:guava:26.0-jre'
    // Use JUnit test framework
    testImplementation 'junit:junit:4.12'
}
Mengapa kita melihat ini di sini? Ini adalah dependensi proyek kita yang dibuat secara otomatis oleh Gradle untuk kita saat membuat proyek. Dan juga karena jambu biji adalah perpustakaan terpisah yang tidak disertakan dengan Java SE. JUnit juga tidak disertakan dengan Java SE. Tapi kami memiliki JDBC, yaitu bagian dari Java SE. Ternyata kami memiliki JDBC. Besar. Apa lagi yang kita butuhkan? Ada diagram yang luar biasa:
JDBC atau tempat semuanya dimulai - 4
Seperti yang bisa kita lihat, dan ini logis, database adalah komponen eksternal yang bukan asli Java SE. Penjelasannya sederhana - ada banyak sekali database dan Anda dapat bekerja dengan database mana pun. Misalnya ada PostgreSQL, Oracle, MySQL, H2. Masing-masing database ini disediakan oleh perusahaan terpisah yang disebut vendor database. Setiap database ditulis dalam bahasa pemrogramannya sendiri (tidak harus Java). Agar dapat bekerja dengan database dari aplikasi Java, penyedia database menulis driver khusus, yang merupakan adaptor gambarnya sendiri. Database yang kompatibel dengan JDBC (yaitu database yang memiliki driver JDBC) juga disebut “Database Sesuai JDBC”. Di sini kita dapat menganalogikannya dengan perangkat komputer. Misalnya di notepad ada tombol "Cetak". Setiap kali Anda menekannya, program akan memberitahu sistem operasi bahwa aplikasi notepad ingin mencetak. Dan Anda memiliki printer. Untuk mengajarkan sistem operasi Anda berkomunikasi secara seragam dengan printer Canon atau HP, Anda memerlukan driver yang berbeda. Namun tidak ada yang berubah bagi Anda sebagai pengguna. Anda masih akan menekan tombol yang sama. Sama dengan JDBC. Anda menjalankan kode yang sama, hanya saja database yang berbeda mungkin berjalan di bawah tenda. Saya pikir ini adalah pendekatan yang sangat jelas. Setiap driver JDBC tersebut adalah semacam artefak, perpustakaan, file jar. Ini adalah ketergantungan untuk proyek kami. Misalnya, kita dapat memilih database " H2 Database " dan kemudian kita perlu menambahkan ketergantungan seperti ini:
dependencies {
    implementation 'com.h2database:h2:1.4.197'
Cara menemukan ketergantungan dan cara mendeskripsikannya ditunjukkan di situs resmi penyedia database atau di " Maven Central ". Driver JDBC bukanlah database, seperti yang Anda pahami. Tapi dia hanya panduan untuk itu. Tapi ada yang namanya " Database dalam memori ". Ini adalah database yang ada di memori selama masa pakai aplikasi Anda. Biasanya, ini sering digunakan untuk tujuan pengujian atau pelatihan. Hal ini memungkinkan Anda menghindari instalasi server database terpisah pada mesin. Yang sangat cocok untuk kita berkenalan dengan JDBC. Jadi kotak pasir kita sudah siap dan kita mulai.
JDBC atau tempat semuanya dimulai - 5

Koneksi

Jadi, kami memiliki driver JDBC, kami memiliki JDBC API. Seperti yang kita ingat, JDBC adalah singkatan dari Java DataBase Connectivity. Oleh karena itu, semuanya dimulai dengan Konektivitas - kemampuan untuk membuat koneksi. Dan koneksi adalah Koneksi. Mari kita kembali ke teks spesifikasi JDBC dan melihat daftar isi. Pada bab " BAB 4 Ikhtisar " (ikhtisar) kita beralih ke bagian " 4.1 Membangun Koneksi " (membuat koneksi) dikatakan bahwa ada dua cara untuk terhubung ke database:
  • Melalui DriverManager
  • Melalui Sumber Data
Mari kita berurusan dengan DriverManager. Seperti yang dikatakan, DriverManager memungkinkan Anda untuk terhubung ke database di URL yang ditentukan, dan juga memuat Driver JDBC yang ditemukan di CLASSPATH (dan sebelumnya, sebelum JDBC 4.0, Anda harus memuat sendiri kelas driver). Ada bab terpisah “BAB 9 Koneksi” tentang koneksi ke database. Kami tertarik dengan cara mendapatkan koneksi melalui DriverManager, jadi kami tertarik pada bagian "9.3 Kelas DriverManager". Ini menunjukkan bagaimana kita dapat mengakses database:
Connection con = DriverManager.getConnection(url, user, passwd);
Parameternya bisa diambil dari website database yang kita pilih. Dalam kasus kami, ini adalah H2 - " Lembar Cheat H2 ". Mari beralih ke kelas AppTest yang disiapkan oleh Gradle. Ini berisi tes JUnit. Tes JUnit adalah metode yang ditandai dengan anotasi @Test. Pengujian unit bukanlah topik ulasan ini, jadi kami akan membatasi diri pada pemahaman bahwa ini adalah metode yang dijelaskan dengan cara tertentu, yang tujuannya adalah untuk menguji sesuatu. Menurut spesifikasi JDBC dan situs H2, kami akan memeriksa apakah kami telah menerima koneksi ke database. Mari tulis metode untuk mendapatkan koneksi:
private Connection getNewConnection() throws SQLException {
	String url = "jdbc:h2:mem:test";
	String user = "sa";
	String passwd = "sa";
	return DriverManager.getConnection(url, user, passwd);
}
Sekarang mari kita tulis tes untuk metode ini yang akan memeriksa apakah koneksi benar-benar dibuat:
@Test
public void shouldGetJdbcConnection() throws SQLException {
	try(Connection connection = getNewConnection()) {
		assertTrue(connection.isValid(1));
		assertFalse(connection.isClosed());
	}
}
Tes ini, ketika dijalankan, akan memverifikasi bahwa koneksi yang dihasilkan valid (dibuat dengan benar) dan tidak ditutup. Dengan menggunakan try-with-resources kita akan melepaskan sumber daya ketika kita tidak lagi membutuhkannya. Ini akan melindungi kita dari koneksi yang kendur dan kebocoran memori. Karena tindakan apa pun dengan database memerlukan koneksi, mari berikan metode pengujian lainnya yang ditandai @Test dengan Koneksi di awal pengujian, yang akan kami rilis setelah pengujian. Untuk melakukan ini, kita memerlukan dua anotasi: @Sebelum dan @Setelah Mari tambahkan bidang baru ke kelas AppTest yang akan menyimpan koneksi JDBC untuk pengujian:
private static Connection connection;
Dan mari tambahkan metode baru:
@Before
public void init() throws SQLException {
	connection = getNewConnection();
}
@After
public void close() throws SQLException {
	connection.close();
}
Sekarang, metode pengujian apa pun dijamin memiliki koneksi JDBC dan tidak harus membuatnya sendiri setiap saat.
JDBC atau tempat semuanya dimulai - 6

Pernyataan

Selanjutnya kita tertarik pada Pernyataan atau ekspresi. Hal tersebut dijelaskan dalam dokumentasi pada bab " BAB 13 Pernyataan ". Pertama, disebutkan bahwa ada beberapa jenis atau tipe pernyataan:
  • Pernyataan: Ekspresi SQL yang tidak berisi parameter
  • PreparedStatement : Pernyataan SQL yang disiapkan berisi parameter input
  • CallableStatement: Ekspresi SQL dengan kemampuan untuk mendapatkan nilai kembalian dari Prosedur Tersimpan SQL.
Jadi, dengan memiliki koneksi, kita dapat menjalankan beberapa permintaan dalam kerangka koneksi ini. Oleh karena itu, logis jika kita awalnya memperoleh contoh ekspresi SQL dari Connection. Anda harus mulai dengan membuat tabel. Mari kita gambarkan permintaan pembuatan tabel sebagai variabel String. Bagaimana cara melakukannya? Mari kita gunakan beberapa tutorial seperti " sqltutorial.org ", " sqlbolt.com ", " postgresqltutorial.com ", " codecademy.com ". Mari kita gunakan, misalnya, contoh dari kursus SQL di khanacademy.org . Mari tambahkan metode untuk mengeksekusi ekspresi di database:
private int executeUpdate(String query) throws SQLException {
	Statement statement = connection.createStatement();
	// Для Insert, Update, Delete
	int result = statement.executeUpdate(query);
	return result;
}
Mari tambahkan metode untuk membuat tabel pengujian menggunakan metode sebelumnya:
private void createCustomerTable() throws SQLException {
	String customerTableQuery = "CREATE TABLE customers " +
                "(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)";
	String customerEntryQuery = "INSERT INTO customers " +
                "VALUES (73, 'Brian', 33)";
	executeUpdate(customerTableQuery);
	executeUpdate(customerEntryQuery);
}
Sekarang mari kita uji ini:
@Test
public void shouldCreateCustomerTable() throws SQLException {
	createCustomerTable();
	connection.createStatement().execute("SELECT * FROM customers");
}
Sekarang mari kita jalankan permintaannya, dan bahkan dengan parameter:
@Test
public void shouldSelectData() throws SQLException {
 	createCustomerTable();
 	String query = "SELECT * FROM customers WHERE name = ?";
	PreparedStatement statement = connection.prepareStatement(query);
	statement.setString(1, "Brian");
	boolean hasResult = statement.execute();
	assertTrue(hasResult);
}
JDBC tidak mendukung parameter bernama untuk PreparedStatement, jadi parameternya sendiri ditentukan oleh pertanyaan, dan dengan menentukan nilainya, kami menunjukkan indeks pertanyaan (mulai dari 1, bukan nol). Pada tes terakhir yang kami terima benar sebagai indikasi ada tidaknya hasil. Namun bagaimana hasil kueri direpresentasikan dalam JDBC API? Dan itu disajikan sebagai ResultSet.
JDBC atau tempat semuanya dimulai - 7

Kumpulan Hasil

Konsep ResultSet dijelaskan dalam spesifikasi JDBC API di bab "BAB 15 Kumpulan Hasil". Pertama-tama, dikatakan bahwa ResultSet menyediakan metode untuk mengambil dan memanipulasi hasil kueri yang dieksekusi. Artinya, jika metode eksekusi mengembalikan nilai true kepada kita, maka kita bisa mendapatkan ResultSet. Mari kita pindahkan panggilan ke metode createCustomerTable() ke metode init, yang ditandai sebagai @Before. Sekarang mari kita selesaikan pengujian mustSelectData kita:
@Test
public void shouldSelectData() throws SQLException {
	String query = "SELECT * FROM customers WHERE name = ?";
	PreparedStatement statement = connection.prepareStatement(query);
	statement.setString(1, "Brian");
	boolean hasResult = statement.execute();
	assertTrue(hasResult);
	// Обработаем результат
	ResultSet resultSet = statement.getResultSet();
	resultSet.next();
	int age = resultSet.getInt("age");
	assertEquals(33, age);
}
Perlu dicatat di sini bahwa selanjutnya adalah metode yang menggerakkan apa yang disebut “kursor”. Kursor di ResultSet menunjuk ke beberapa baris. Jadi, untuk membaca sebuah baris, Anda perlu menempatkan kursor ini di atasnya. Saat kursor digerakkan, metode perpindahan kursor mengembalikan nilai true jika kursor valid (benar, benar), yaitu menunjuk ke data. Jika hasilnya salah, maka tidak ada data, artinya kursor tidak menunjuk ke data tersebut. Jika kita mencoba untuk mendapatkan data dengan kursor yang tidak valid, kita akan mendapatkan kesalahan: Tidak ada data yang tersedia Menarik juga bahwa melalui ResultSet Anda dapat memperbarui atau bahkan menyisipkan baris:
@Test
public void shouldInsertInResultSet() throws SQLException {
	Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
	ResultSet resultSet = statement.executeQuery("SELECT * FROM customers");
	resultSet.moveToInsertRow();
	resultSet.updateLong("id", 3L);
	resultSet.updateString("name", "John");
	resultSet.updateInt("age", 18);
	resultSet.insertRow();
	resultSet.moveToCurrentRow();
}

Set Baris

Selain ResultSet, JDBC memperkenalkan konsep RowSet. Anda dapat membaca lebih lanjut di sini: " Dasar-Dasar JDBC: Menggunakan Objek RowSet ". Variasi penggunaannya pun bermacam-macam. Misalnya, kasus paling sederhana mungkin terlihat seperti ini:
@Test
public void shouldUseRowSet() throws SQLException {
 	JdbcRowSet jdbcRs = new JdbcRowSetImpl(connection);
 	jdbcRs.setCommand("SELECT * FROM customers");
	jdbcRs.execute();
	jdbcRs.next();
	String name = jdbcRs.getString("name");
	assertEquals("Brian", name);
}
Seperti yang Anda lihat, RowSet mirip dengan simbiosis pernyataan (kami menentukan perintah melaluinya) dan menjalankan perintah. Melalui itu kita mengontrol kursor (dengan memanggil metode selanjutnya) dan mendapatkan data darinya. Tidak hanya pendekatan ini yang menarik, tetapi juga kemungkinan penerapannya. Misalnya, CachedRowSet. Itu "terputus" (yaitu, tidak menggunakan koneksi persisten ke database) dan memerlukan sinkronisasi eksplisit dengan database:
CachedRowSet jdbcRsCached = new CachedRowSetImpl();
jdbcRsCached.acceptChanges(connection);
Anda dapat membaca lebih lanjut di tutorial di situs Oracle: " Menggunakan CachedRowSetObjects ".
JDBC atau tempat semuanya dimulai - 8

Metadata

Selain kueri, koneksi ke database (yaitu turunan dari kelas Connection) menyediakan akses ke metadata - data tentang bagaimana database kami dikonfigurasi dan diatur. Namun pertama-tama, mari kita sebutkan beberapa poin penting: URL untuk menghubungkan ke database kita: “jdbc:h2:mem:test”. tes adalah nama database kami. Untuk JDBC API, ini adalah direktori. Dan namanya akan menggunakan huruf besar, yaitu TEST. Skema default untuk H2 adalah PUBLIC. Sekarang, mari kita menulis tes yang menampilkan semua tabel pengguna. Mengapa adat? Karena database tidak hanya berisi tabel pengguna (yang kita buat sendiri menggunakan ekspresi buat tabel), tetapi juga tabel sistem. Mereka diperlukan untuk menyimpan informasi sistem tentang struktur database. Setiap database dapat menyimpan tabel sistem tersebut secara berbeda. Misalnya, di H2 mereka disimpan dalam skema " INFORMATION_SCHEMA ". Menariknya, SKEMA INFORMASI adalah pendekatan yang umum, tetapi Oracle mengambil jalan yang berbeda. Anda dapat membaca lebih lanjut di sini: " INFORMATION_SCHEMA dan Oracle ". Mari kita menulis tes yang menerima metadata pada tabel pengguna:
@Test
public void shoudGetMetadata() throws SQLException {
	// У нас URL = "jdbc:h2:mem:test", где test - название БД
	// Название БД = catalog
	DatabaseMetaData metaData = connection.getMetaData();
	ResultSet result = metaData.getTables("TEST", "PUBLIC", "%", null);
	List<String> tables = new ArrayList<>();
	while(result.next()) {
		tables.add(result.getString(2) + "." + result.getString(3));
	}
	assertTrue(tables.contains("PUBLIC.CUSTOMERS"));
}
JDBC atau tempat semuanya dimulai - 9

Kumpulan koneksi

Kumpulan koneksi dalam spesifikasi JDBC memiliki bagian yang disebut "Bab 11 Pengumpulan Koneksi". Ini juga memberikan pembenaran utama atas perlunya kumpulan koneksi. Setiap Coonection adalah koneksi fisik ke database. Pembuatan dan penutupannya merupakan pekerjaan yang cukup "mahal". JDBC hanya menyediakan API pengumpulan koneksi. Oleh karena itu, pilihan penerapannya tetap berada di tangan kita. Misalnya, implementasi tersebut mencakup HikariCP . Oleh karena itu, kita perlu menambahkan kumpulan ke ketergantungan proyek kita:
dependencies {
    implementation 'com.h2database:h2:1.4.197'
    implementation 'com.zaxxer:HikariCP:3.3.1'
    testImplementation 'junit:junit:4.12'
}
Sekarang kita perlu menggunakan kumpulan ini. Untuk melakukannya, Anda perlu menginisialisasi sumber data, juga dikenal sebagai Sumber Data:
private DataSource getDatasource() {
	HikariConfig config = new HikariConfig();
	config.setUsername("sa");
	config.setPassword("sa");
	config.setJdbcUrl("jdbc:h2:mem:test");
	DataSource ds = new HikariDataSource(config);
	return ds;
}
Dan mari kita menulis tes untuk menerima koneksi dari pool:
@Test
public void shouldGetConnectionFromDataSource() throws SQLException {
	DataSource datasource = getDatasource();
	try (Connection con = datasource.getConnection()) {
		assertTrue(con.isValid(1));
	}
}
JDBC atau tempat semuanya dimulai - 10

Transaksi

Salah satu hal yang paling menarik dari JDBC adalah transaksi. Dalam spesifikasi JDBC, mereka diberi bab "BAB 10 Transaksi". Pertama-tama, ada baiknya memahami apa itu transaksi. Transaksi adalah sekelompok operasi sekuensial yang digabungkan secara logis pada data, diproses atau dibatalkan secara keseluruhan. Kapan transaksi dimulai saat menggunakan JDBC? Sesuai spesifikasinya, ini ditangani langsung oleh Driver JDBC. Namun biasanya, transaksi baru dimulai ketika pernyataan SQL saat ini memerlukan transaksi dan transaksi tersebut belum dibuat. Kapan transaksi berakhir? Ini dikendalikan oleh atribut auto-commit. Jika komit otomatis diaktifkan, transaksi akan selesai setelah pernyataan SQL "selesai". Arti "selesai" bergantung pada jenis ekspresi SQL:
  • Bahasa Manipulasi Data, juga dikenal sebagai DML (Sisipkan, Perbarui, Hapus)
    Transaksi selesai segera setelah tindakan selesai
  • Pilih Pernyataan
    Transaksi selesai ketika ResultSet ditutup ( ResultSet#close )
  • CallableStatement dan ekspresi yang mengembalikan beberapa hasil
    Ketika semua ResultSets terkait telah ditutup dan semua output telah diterima (termasuk jumlah pembaruan)
Ini adalah bagaimana JDBC API berperilaku. Seperti biasa, mari kita tulis tes untuk ini:
@Test
public void shouldCommitTransaction() throws SQLException {
	connection.setAutoCommit(false);
	String query = "INSERT INTO customers VALUES (1, 'Max', 20)";
	connection.createStatement().executeUpdate(query);
	connection.commit();
	Statement statement = connection.createStatement();
 	statement.execute("SELECT * FROM customers");
	ResultSet resultSet = statement.getResultSet();
	int count = 0;
	while(resultSet.next()) {
		count++;
	}
	assertEquals(2, count);
}
Itu mudah. Namun hal ini berlaku selama kita hanya melakukan satu kali transaksi. Apa yang harus dilakukan jika jumlahnya beberapa? Mereka perlu diisolasi satu sama lain. Oleh karena itu, mari kita bahas tentang tingkat isolasi transaksi dan cara JDBC menanganinya.
JDBC atau tempat semuanya dimulai - 11

Tingkat isolasi

Mari kita buka subbagian "10.2 Tingkat Isolasi Transaksi" dari spesifikasi JDBC. Di sini, sebelum melangkah lebih jauh, saya ingin mengingat tentang hal seperti ACID. ACID menjelaskan persyaratan untuk sistem transaksional.
  • Atomicity:
    Tidak ada transaksi yang akan dikomit sebagian ke sistem. Semua sub-operasinya akan dijalankan, atau tidak ada satu pun yang dijalankan.
  • Konsistensi:
    Setiap transaksi yang berhasil, menurut definisi, hanya mencatat hasil yang valid.
  • Isolasi:
    Saat transaksi sedang berjalan, transaksi bersamaan tidak akan mempengaruhi hasilnya.
  • Daya Tahan:
    Jika transaksi berhasil diselesaikan, perubahan yang dilakukan tidak akan dibatalkan karena kegagalan apa pun.
Ketika berbicara tentang tingkat isolasi transaksi, kita berbicara tentang persyaratan “Isolasi”. Isolasi adalah persyaratan yang mahal, jadi dalam database nyata terdapat mode yang tidak sepenuhnya mengisolasi transaksi (tingkat isolasi Baca Berulang dan lebih rendah). Wikipedia memiliki penjelasan yang sangat bagus tentang masalah yang mungkin timbul saat menangani transaksi. Ada baiknya membaca lebih lanjut di sini: “ Masalah akses paralel menggunakan transaksi .” Sebelum kita menulis pengujian, mari kita ubah sedikit Gradle Build Script kita: tambahkan blok dengan properti, yaitu dengan pengaturan proyek kita:
ext {
    h2Version = '1.3.176' // 1.4.177
    hikariVersion = '3.3.1'
    junitVersion = '4.12'
}
Selanjutnya, kami menggunakan ini dalam versi:
dependencies {
    implementation "com.h2database:h2:${h2Version}"
    implementation "com.zaxxer:HikariCP:${hikariVersion}"
    testImplementation "junit:junit:${junitVersion}"
}
Anda mungkin memperhatikan bahwa versi h2 menjadi lebih rendah. Kita akan lihat alasannya nanti. Jadi bagaimana Anda menerapkan tingkat isolasi? Mari kita lihat contoh praktis kecilnya segera:
@Test
public void shouldGetReadUncommited() throws SQLException {
	Connection first = getNewConnection();
	assertTrue(first.getMetaData().supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED));
	first.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
	first.setAutoCommit(false);
	// Транзакиця на подключение. Поэтому первая транзакция с ReadUncommited вносит изменения
	String insertQuery = "INSERT INTO customers VALUES (5, 'Max', 15)";
	first.createStatement().executeUpdate(insertQuery);
	// Вторая транзакция пытается их увидеть
	int rowCount = 0;
	JdbcRowSet jdbcRs = new JdbcRowSetImpl(getNewConnection());
	jdbcRs.setCommand("SELECT * FROM customers");
	jdbcRs.execute();
	while (jdbcRs.next()) {
		rowCount++;
	}
	assertEquals(2, rowCount);
}
Menariknya, pengujian ini mungkin gagal pada vendor yang tidak mendukung TRANSACTION_READ_UNCOMMITTED (misalnya sqlite atau HSQL). Dan tingkat transaksi mungkin tidak berfungsi. Ingat kami menunjukkan versi driver Database H2? Jika kita menaikkannya ke h2Version = '1.4.177' dan lebih tinggi, maka READ UNCOMMITTED akan berhenti berfungsi, meskipun kita tidak mengubah kodenya. Hal ini sekali lagi membuktikan bahwa pemilihan versi vendor dan driver bukan sekedar huruf, namun akan menentukan bagaimana permintaan Anda akan dieksekusi. Anda dapat membaca tentang cara memperbaiki perilaku ini di versi 1.4.177 dan cara kerjanya tidak di versi yang lebih tinggi di sini: " Support READ UNCOMMITTED tingkat isolasi dalam mode MVStore ".
JDBC atau tempat semuanya dimulai - 12

Intinya

Seperti yang bisa kita lihat, JDBC adalah alat Java yang ampuh untuk bekerja dengan database. Saya harap ulasan singkat ini dapat membantu memberi Anda titik awal atau membantu menyegarkan ingatan Anda. Nah, untuk camilannya, beberapa bahan tambahannya: #Viacheslav
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION