JavaRush /Java блогы /Random-KK /JDBC немесе барлығы қайдан басталады
Viacheslav
Деңгей

JDBC немесе барлығы қайдан басталады

Топта жарияланған
Қазіргі әлемде деректерді сақтаусыз жол жоқ. Ал деректер қорымен жұмыс жасау тарихы өте ертеден, JDBC пайда болғаннан басталды. Мен JDBC үстіне салынған заманауи құрылым онсыз жасай алмайтын нәрсені есте сақтауды ұсынамын. Сонымен қатар, олармен жұмыс істегенде де, кейде сізге «тамырыңызға оралу» мүмкіндігі қажет болуы мүмкін. Бұл шолу кіріспе ретінде көмектеседі немесе жадыңызды жаңартуға көмектеседі деп үміттенемін.
JDBC немесе барлығы қай жерде басталады - 1

Кіріспе

Бағдарламалау тілінің негізгі мақсаттарының бірі ақпаратты сақтау және өңдеу болып табылады. Деректерді сақтау қалай жұмыс істейтінін жақсы түсіну үшін қолданбалардың теориясы мен архитектурасына аз уақыт жұмсаған жөн. Мысалы, сіз әдебиеттерді, атап айтқанда Джозеф Инженоның « Бағдарламалық жасақтама сәулетшісінің анықтамалығы: тиімді арканы енгізу арқылы табысты бағдарламалық жасақтама сәулетшісі болыңыз... » кітабын оқи аласыз. Айтылғандай, белгілі бір деректер деңгейі немесе «деректер қабаты» бар. Ол деректерді сақтауға арналған орынды (мысалы, SQL дерекқоры) және деректер қоймасымен жұмыс істеу құралдарын (мысалы, талқыланатын JDBC) қамтиды. Сондай-ақ Microsoft веб-сайтында мақала бар: « Инфрақұрылымның тұрақтылық қабатын жобалау », ол қосымша қабатты деректер деңгейінен - ​​тұрақтылық деңгейінен бөлудің архитектуралық шешімін сипаттайды. Бұл жағдайда Деректер деңгейі деректердің өзін сақтау деңгейі болып табылады, ал тұрақтылық деңгейі деректер деңгейі деңгейінен қоймадағы деректермен жұмыс істеуге арналған абстракцияның кейбір деңгейі болып табылады. Тұрақтылық деңгейі «DAO» үлгісін немесе әртүрлі ORM-ді қамтуы мүмкін. Бірақ ORM - бұл басқа талқылау тақырыбы. Сіз бұрыннан түсінгеніңіздей, деректер деңгейі бірінші болып пайда болды. JDK 1.1 кезінен бастап Java әлемінде JDBC (Java DataBase Connectivity – Java тіліндегі дерекқорларға қосылу) пайда болды. Бұл Java SE құрамына кіретін java.sql және javax.sql пакеттері түрінде жүзеге асырылатын Java қосымшаларының әртүрлі ДҚБЖ-мен өзара әрекеттесу стандарты:
JDBC немесе бәрі басталатын жер - 2
Бұл стандарт " JSR 221 JDBC 4.1 API " спецификациясымен сипатталған . Бұл спецификация JDBC API Java тілінде жазылған бағдарламалардан реляциялық дерекқорларға бағдарламалық қатынасты қамтамасыз ететінін айтады. Ол сондай-ақ JDBC API Java платформасының бөлігі екенін және сондықтан Java SE және Java EE құрамына кіретінін айтады. JDBC API екі бумада берілген: java.sql және javax.sql. Олай болса олармен танысайық.
JDBC немесе барлығы қай жерде басталады - 3

Жұмыстың басталуы

JDBC API жалпы не екенін түсіну үшін бізге Java қолданбасы қажет. Жобаны құрастыру жүйелерінің бірін пайдалану ең қолайлы. Мысалы, Gradle қолданайық . Сіз Gradle туралы толығырақ қысқа шолудан оқи аласыз: " Gradle туралы қысқаша кіріспе ". Алдымен жаңа Gradle жобасын инициализациялайық. Gradle функционалдығы плагиндер арқылы жүзеге асырылатындықтан, инициализациялау үшін « Gradle Build Init Plugin » пайдалануымыз керек :
gradle init --type java-application
Осыдан кейін жобамызды және онымен қалай жұмыс істеу керектігін сипаттайтын build.gradle файлын құру сценарийін ашайық . Бізді « тәуелділіктер » блогы қызықтырады , онда тәуелділіктер сипатталады, яғни біз онсыз жұмыс істей алмайтын және біз тәуелді болатын кітапханалар/жақтаулар/api. Әдепкі бойынша біз келесідей нәрсені көреміз:
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'
}
Неліктен біз мұны мұнда көріп отырмыз? Бұл жобаны жасаған кезде Gradle арқылы автоматты түрде жасалған жобамыздың тәуелділіктері. Сондай-ақ, guava Java SE құрамына кірмейтін жеке кітапхана болғандықтан. JUnit де Java SE жүйесіне кірмейді. Бірақ бізде JDBC қораптан тыс, яғни Java SE бөлігі. Бізде JDBC бар екен. Тамаша. Бізге тағы не керек? Мұндай керемет диаграмма бар:
JDBC немесе барлығы қай жерде басталады - 4
Көріп отырғанымыздай және бұл логикалық, деректер базасы Java SE-ге тән емес сыртқы компонент болып табылады. Бұл жай ғана түсіндіріледі - деректер базаларының үлкен саны бар және сіз кез келгенімен жұмыс істей аласыз. Мысалы, PostgreSQL, Oracle, MySQL, H2 бар. Бұл дерекқорлардың әрқайсысын дерекқор жеткізушілері деп аталатын жеке компания қамтамасыз етеді. Әрбір дерекқор өзінің бағдарламалау тілінде жазылған (міндетті түрде Java емес). Java қосымшасынан деректер қорымен жұмыс істеу мүмкіндігін алу үшін деректер қоры провайдері өзінің кескін адаптері болып табылатын арнайы драйверді жазады. Мұндай JDBC үйлесімділері (яғни, JDBC драйвері барлар) «JDBC-үйлесімді дерекқор» деп те аталады. Мұнда біз компьютерлік құрылғыларға ұқсастық жасай аламыз. Мысалы, блокнотта «Басып шығару» түймесі бар. Оны басқан сайын бағдарлама операциялық жүйеге блокнот қолданбасы басып шығарғысы келетінін хабарлайды. Ал сізде принтер бар. Амалдық жүйеңізді Canon немесе HP принтерімен біркелкі байланысуға үйрету үшін сізге әртүрлі драйверлер қажет болады. Бірақ сіз үшін, пайдаланушы ретінде, ештеңе өзгермейді. Сіз бұрынғыдай түймені басасыз. JDBC-мен бірдей. Сіз бірдей codeты іске қосып жатырсыз, бұл әртүрлі дерекқорлар қақпақ астында жұмыс істеуі мүмкін. Менің ойымша, бұл өте айқын көзқарас. Әрбір JDBC драйвері артефакт, кітапхана, jar файлының бір түрі болып табылады. Бұл біздің жобаға тәуелділік. Мысалы, біз « H2 Database » дерекқорын таңдай аламыз, содан кейін келесідей тәуелділікті қосуымыз керек:
dependencies {
    implementation 'com.h2database:h2:1.4.197'
Тәуелділікті қалай табуға болады және оны қалай сипаттауға болады, дерекқор провайдерінің ресми сайттарында немесе « Maven Central » сайтында көрсетілген. JDBC драйвері сіз түсінгендей дерекқор емес. Бірақ ол оған тек жол көрсетуші ғана. Бірақ « Жад дерекқорларында » деген нәрсе бар . Бұл қолданбаңыздың қызмет ету мерзімі бойы жадта болатын дерекқорлар. Әдетте бұл тестілеу немесе оқыту мақсатында жиі пайдаланылады. Бұл құрылғыға бөлек дерекқор serverін орнатудан аулақ болуға мүмкіндік береді. Бұл бізге JDBC-пен танысу үшін өте қолайлы. Сонымен, құм жәшігіміз дайын және біз бастаймыз.
JDBC or с чего всё начинается - 5

Байланыс

Сонымен, бізде JDBC драйвері бар, бізде JDBC API бар. Естеріңізде болса, JDBC Java Database Connectivity дегенді білдіреді. Сондықтан бәрі Connectivity - байланыс орнату мүмкіндігінен басталады. Ал қосылым — Connection. JDBC спецификациясының мәтініне қайта оралып , мазмұн кестесін қарастырайық. « 4-ТАРАУ шолу » тарауында (шолу) « 4.1 Байланысты орнату » (байланыс орнату) бөліміне жүгінеміз , мәліметтер базасына қосылудың екі жолы бар екендігі айтылады:
  • DriverManager арқылы
  • DataSource арқылы
DriverManager бағдарламасымен айналысайық. Айтылғандай, DriverManager көрсетілген URL мекенжайы бойынша дерекқорға қосылуға мүмкіндік береді, сонымен қатар CLASSPATH ішінен табылған JDBC драйверлерін жүктейді (және бұрын JDBC 4.0 нұсқасына дейін драйвер класын өзіңіз жүктеп алуыңыз керек еді). Дерекқорға қосылу туралы «9-ТАРАУ Қосылымдар» жеке тарауы бар. Бізді DriverManager арқылы қалай қосуға болатыны қызықтырады, сондықтан бізді «9.3 DriverManager сыныбы» бөлімі қызықтырады. Ол дерекқорға қалай қол жеткізе алатынымызды көрсетеді:
Connection con = DriverManager.getConnection(url, user, passwd);
Параметрлерді біз таңдаған дерекқордың веб-сайтынан алуға болады. Біздің жағдайда бұл H2 - " H2 Cheat Sheet ". Gradle дайындаған AppTest сыныбына көшейік. Онда JUnit сынақтары бар. JUnit сынағы - annotationмен белгіленген әдіс @Test. Бірлік сынақтары бұл шолудың тақырыбы емес, сондықтан біз бұл белгілі бір жолмен сипатталған әдістер екенін түсінумен ғана шектелеміз, олардың мақсаты бір нәрсені сынау. JDBC спецификациясына және H2 веб-сайтына сәйкес біз дерекқорға қосылым алғанымызды тексереміз. Қосылымды алу әдісін жазайық:
private Connection getNewConnection() throws SQLException {
	String url = "jdbc:h2:mem:test";
	String user = "sa";
	String passwd = "sa";
	return DriverManager.getConnection(url, user, passwd);
}
Енді қосылымның нақты орнатылғанын тексеретін осы әдіске тест жазайық:
@Test
public void shouldGetJdbcConnection() throws SQLException {
	try(Connection connection = getNewConnection()) {
		assertTrue(connection.isValid(1));
		assertFalse(connection.isClosed());
	}
}
Бұл сынақ орындалған кезде нәтиже қосылымының жарамды (дұрыс жасалған) және жабылмағанын тексереді. Ресурстарды қолданып көру арқылы біз ресурстарды қажет етпеген кезде шығарамыз. Бұл бізді қосылымдардың әлсіреуінен және жадтың ағып кетуінен қорғайды. Дерекқормен кез келген әрекеттер қосылымды қажет ететіндіктен, сынақтың басында @Test Connection деп белгіленген қалған сынақ әдістерін берейік, біз оны сынақтан кейін шығарамыз. Мұны істеу үшін бізге екі annotation қажет: @Before және @After AppTest сыныбына сынақтар үшін JDBC қосылымын сақтайтын жаңа өрісті қосамыз:
private static Connection connection;
Жаңа әдістерді қосайық:
@Before
public void init() throws SQLException {
	connection = getNewConnection();
}
@After
public void close() throws SQLException {
	connection.close();
}
Енді кез келген сынақ әдісі JDBC қосылымына кепілдік береді және оны әр уақытта өзі жасаудың қажеті жоқ.
JDBC or с чего всё начинается - 6

Мәлімдеме

Әрі қарай бізді мәлімдемелер немесе өрнектер қызықтырады. Олар құжаттаманың « 13-ТАРАУ мәлімдемелері » тарауында сипатталған . Біріншіден, ол мәлімдемелердің бірнеше түрі немесе түрлері бар екенін айтады:
  • Мәлімдеме: параметрлері жоқ SQL өрнегі
  • PreparedStatement : Енгізу параметрлерін қамтитын дайындалған SQL мәлімдемесі
  • CallableStatement: SQL сақталған proceduresаларынан қайтару мәнін алу мүмкіндігі бар SQL өрнегі.
Сонымен, байланысқа ие бола отырып, біз осы қосылым шеңберінде кейбір сұрауларды орындай аламыз. Сондықтан бастапқыда Connection ішінен SQL өрнегі данасын алуымыз қисынды. Кестені құрудан бастау керек. Кестені құру сұранысын String айнымалысы ретінде сипаттайық. Бұны қалай істейді? " sqltutorial.org ", " sqlbolt.com ", " postgresqltutorial.com ", " codecademy.com " сияқты оқулықтарды қолданайық . Мысалы, khanacademy.org сайтындағы SQL курсының мысалын қолданайық . Мәліметтер қорында өрнекті орындау әдісін қосамыз:
private int executeUpdate(String query) throws SQLException {
	Statement statement = connection.createStatement();
	// Для Insert, Update, Delete
	int result = statement.executeUpdate(query);
	return result;
}
Алдыңғы әдісті пайдаланып сынақ кестесін құру әдісін қосамыз:
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);
}
Енді мынаны сынап көрейік:
@Test
public void shouldCreateCustomerTable() throws SQLException {
	createCustomerTable();
	connection.createStatement().execute("SELECT * FROM customers");
}
Енді сұрауды орындайық, тіпті параметрмен:
@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 PreparedStatement үшін аталған параметрлерді қолдамайды, сондықтан параметрлердің өзі сұрақтар арқылы көрсетіледі және мәнді көрсету арқылы біз сұрақ индексін көрсетеміз (нөлден емес, 1-ден бастап). Соңғы сынақта біз нәтиженің бар-жоғын анықтау үшін шындықты алдық. Бірақ сұрау нәтижесі JDBC API интерфейсінде қалай көрсетіледі? Және ол ResultSet ретінде ұсынылады.
JDBC or с чего всё начинается - 7

Нәтиже жинағы

ResultSet тұжырымдамасы JDBC API спецификациясында «15-БӨЛІМ Нәтиже жиындары» тарауында сипатталған. Ең алдымен, ол ResultSet орындалған сұраулардың нәтижелерін алу және өңдеу әдістерін қамтамасыз ететінін айтады. Яғни, егер орындау әдісі бізге шындықты қайтарса, онда біз ResultSet аламыз. Қоңырауды createCustomerTable() әдісіне @Before ретінде белгіленген init әдісіне жылжытайық. Енді shouldSelectData тестімізді аяқтаймыз:
@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);
}
Бұл жерде келесі «курсорды» жылжытатын әдіс екенін атап өткен жөн. ResultSet ішіндегі курсор кейбір жолды көрсетеді. Осылайша, жолды оқу үшін оған дәл осы курсорды қою керек. Меңзерді жылжытқанда курсорды жылжыту әдісі, егер курсор жарамды (дұрыс, дұрыс) болса, ақиқат мәнін қайтарады, яғни ол деректерге нұсқайды. Егер ол false мәнін қайтарса, онда деректер жоқ, яғни курсор деректерді көрсетпейді. Жарамсыз курсормен деректерді алуға әрекеттенсек, біз қатені аламыз: Деректер жоқ. Сондай-ақ, ResultSet арқылы жолдарды жаңартуға немесе тіпті енгізуге болатыны қызық:
@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();
}

Жолдар жинағы

ResultSet-ке қосымша, JDBC RowSet тұжырымдамасын ұсынады. Толығырақ мына жерден оқи аласыз: " JDBC негіздері: RowSet нысандарын пайдалану ". Қолданудың әртүрлі нұсқалары бар. Мысалы, ең қарапайым жағдай келесідей болуы мүмкін:
@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);
}
Көріп отырғаныңыздай, RowSet оператор (біз ол арқылы пәрменді көрсеттік) және орындалған команданың симбиозына ұқсас. Ол арқылы курсорды басқарамыз (келесі әдісті шақыру арқылы) және одан мәліметтер аламыз. Бұл тәсіл қызықты ғана емес, сонымен қатар мүмкін жүзеге асырулар. Мысалы, CachedRowSet. Ол «ажыратылған» (яғни, ол дерекқорға тұрақты қосылымды пайдаланбайды) және дерекқормен нақты синхрондауды қажет етеді:
CachedRowSet jdbcRsCached = new CachedRowSetImpl();
jdbcRsCached.acceptChanges(connection);
Қосымша ақпаратты Oracle веб-сайтындағы оқулықтан оқи аласыз: " CachedRowSetObjects пайдалану ".
JDBC or с чего всё начинается - 8

Метадеректер

Сұраулардан басқа, дерекқорға қосылу (яғни, Қосылым сыныбының данасы) метадеректерге қол жеткізуді қамтамасыз етеді - дерекқордың конфигурациялануы және ұйымдастырылуы туралы деректер. Бірақ алдымен бірнеше негізгі тармақтарды атап өтейік: Біздің дерекқорға қосылу URL мекенжайы: “jdbc:h2:mem:test”. test - бұл біздің дерекқорымыздың атауы. JDBC API үшін бұл каталог. Ал аты бас әріппен, яғни ТЕСТ болады. H2 үшін әдепкі схема - PUBLIC. Енді барлық пайдаланушы кестелерін көрсететін тест жазайық. Неліктен әдет-ғұрып? Өйткені дерекқорларда тек пайдаланушы кестелері ғана емес (кесте өрнектерін жасау арқылы өзіміз жасағандар), сонымен қатар жүйелік кестелер де бар. Олар мәліметтер қорының құрылымы туралы жүйелік ақпаратты сақтау үшін қажет. Әрбір дерекқор мұндай жүйелік кестелерді әртүрлі сақтай алады. Мысалы, Н2-де олар " АҚПАРАТ_СХЕМА " схемасында сақталады . Бір қызығы, АҚПАРАТТЫҚ СХЕМА кең таралған тәсіл, бірақ Oracle басқа жолмен жүрді. Толығырақ мына жерден оқи аласыз: " INFORMATION_SCHEMA және Oracle ". Пайдаланушы кестелерінде метадеректерді алатын сынақты жазайық:
@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 or с чего всё начинается - 9

Қосылу пулы

JDBC спецификациясындағы қосылым пулында "11-тарау қосылымды біріктіру" деп аталатын бөлім бар. Ол сондай-ақ қосылым пулының қажеттілігінің негізгі негіздемесін береді. Әрбір Coonection дерекқорға физикалық қосылым болып табылады. Оны құру және жабу - айтарлықтай «қымбат» жұмыс. JDBC тек қосылымды біріктіру API ұсынады. Сондықтан іске асыруды таңдау біздікі болып қалады. Мысалы, мұндай іске асыруға HikariCP кіреді . Тиісінше, біз жобаға тәуелділікке пул қосуымыз керек:
dependencies {
    implementation 'com.h2database:h2:1.4.197'
    implementation 'com.zaxxer:HikariCP:3.3.1'
    testImplementation 'junit:junit:4.12'
}
Енді бізге бұл бассейнді қалай да пайдалану керек. Мұны істеу үшін деректер көзі ретінде белгілі деректер көзін инициализациялау қажет:
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;
}
Пулдан қосылым алу үшін сынақ жазайық:
@Test
public void shouldGetConnectionFromDataSource() throws SQLException {
	DataSource datasource = getDatasource();
	try (Connection con = datasource.getConnection()) {
		assertTrue(con.isValid(1));
	}
}
JDBC or с чего всё начинается - 10

Мәмілелер

JDBC туралы ең қызықты нәрселердің бірі транзакциялар болып табылады. JDBC спецификациясында оларға «10-ТАРАУ транзакциялар» тарауы тағайындалған. Ең алдымен, транзакцияның не екенін түсіну керек. Транзакция – бұл тұтастай өңделген немесе жойылған деректер бойынша логикалық біріктірілген дәйекті операциялар тобы. JDBC пайдалану кезінде транзакция қашан басталады? Техникалық сипаттамада айтылғандай, бұл тікелей JDBC драйверімен өңделеді. Бірақ әдетте жаңа транзакция ағымдағы SQL мәлімдемесі транзакцияны талап еткенде және транзакция әлі жасалмаған кезде басталады. Транзакция қашан аяқталады? Бұл автоматты орындау атрибуты арқылы басқарылады. Автоматты орындау қосылса, транзакция SQL мәлімдемесі «аяқталғаннан» кейін аяқталады. «Орындалды» деген сөз SQL өрнегі түріне байланысты:
  • Деректерді өңдеу тілі, сонымен қатар DML (Insert, Update, Delete) ретінде белгілі.
    Транзакция әрекет аяқталғаннан кейін аяқталады.
  • Мәлімдемелерді таңдау
    ResultSet жабылған кезде транзакция аяқталады ( ResultSet#close )
  • CallableStatement және бірнеше нәтижелерді қайтаратын өрнектер
    Барлық байланысты нәтижелер жиындары жабылғанда және барлық нәтиже алынғанда (жаңартулар санын қоса)
JDBC API дәл осылай әрекет етеді. Әдеттегідей бұл үшін тест жазайық:
@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);
}
Бәрі оңай. Бірақ бұл бізде тек бір транзакция болғанша дұрыс. Олардың бірнешеуі болған кезде не істеу керек? Оларды бір-бірінен оқшаулау керек. Сондықтан транзакцияны оқшаулау деңгейлері және JDBC олармен қалай жұмыс істейтіні туралы сөйлесейік.
JDBC or с чего всё начинается - 11

Оқшаулау деңгейлері

JDBC спецификациясының «10.2 транзакцияны оқшаулау деңгейлері» ішкі бөлімін ашайық. Мұнда, әрі қарай қозғалмас бұрын, мен ACID сияқты нәрсе туралы еске түсіргім келеді. ACID транзакциялық жүйеге қойылатын талаптарды сипаттайды.
  • Атомдық:
    Ешбір транзакция жүйеге ішінара бекітілмейді. Оның барлық қосалқы операциялары орындалады немесе ешқайсысы орындалмайды.
  • Жүйелілік:
    Әрбір сәтті транзакция анықтамасы бойынша тек жарамды нәтижелерді жазады.
  • Оқшаулау:
    транзакция орындалып жатқанда, бір мезгілде жасалатын транзакциялар оның нәтижесіне әсер етпеуі керек.
  • Ұзақтығы:
    транзакция сәтті аяқталса, оған енгізілген өзгерістер кез келген сәтсіздікке байланысты кері қайтарылмайды.
Транзакцияны оқшаулау деңгейлері туралы айтқанда, біз «Оқшаулау» талабы туралы айтып отырмыз. Оқшаулау қымбат талап болып табылады, сондықтан нақты дерекқорларда транзакцияны толығымен оқшауламайтын режимдер бар (Қайталанатын оқу оқшаулау деңгейлері және одан төмен). Уикипедияда транзакциялармен жұмыс істеу кезінде туындауы мүмкін мәселелердің тамаша түсіндірмесі бар. Толығырақ мына жерден оқу керек: « Транзакцияларды пайдалана отырып параллельді қол жеткізу мәселелері ». Тестімізді жазбас бұрын, Gradle Build сценарийін сәл өзгертейік: қасиеттері бар блокты, яғни жобамыздың параметрлерін қосыңыз:
ext {
    h2Version = '1.3.176' // 1.4.177
    hikariVersion = '3.3.1'
    junitVersion = '4.12'
}
Содан кейін біз оны нұсқаларда қолданамыз:
dependencies {
    implementation "com.h2database:h2:${h2Version}"
    implementation "com.zaxxer:HikariCP:${hikariVersion}"
    testImplementation "junit:junit:${junitVersion}"
}
Сіз h2 нұсқасының төмендегенін байқаған боларсыз. Неге екенін кейін көреміз. Сонымен, оқшаулау деңгейлерін қалай қолданасыз? Бірден шағын практикалық мысалды қарастырайық:
@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);
}
Бір қызығы, бұл сынақ TRANSACTION_READ_UNCOMMITTED қолдамайтын жеткізушіде сәтсіз болуы мүмкін (мысалы, sqlite немесе HSQL). Және транзакция деңгейі жай жұмыс істемеуі мүмкін. H2 Database драйверінің нұсқасын көрсеткеніміз есіңізде ме? Егер оны h2Version = '1.4.177' және одан жоғары деңгейге көтерсек, codeты өзгертпесек те, READ UNCOMMITTED жұмысын тоқтатады. Бұл тағы бір рет жеткізуші мен драйвер нұсқасын таңдау тек әріптер емес, ол сіздің сұрауларыңыздың қалай орындалатынын нақты анықтайды. Бұл әрекетті 1.4.177 нұсқасында қалай түзетуге болатынын және оның жоғары нұсқаларда қалай жұмыс істемейтінін мына жерден оқи аласыз: " MVStore режимінде READ UNCOMMITTED оқшаулау деңгейін қолдау ".
JDBC or с чего всё начинается - 12

Төменгі сызық

Көріп отырғанымыздай, JDBC дерекқорлармен жұмыс істеуге арналған Java қолындағы қуатты құрал болып табылады. Бұл қысқа шолу сізге бастапқы нүкте беруге немесе жадыңызды жаңартуға көмектеседі деп үміттенемін. Ал, тағамдар үшін кейбір қосымша материалдар: #Вячеслав
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION