JavaRush /Java блогу /Random-KY /JDBC же баары кайда башталат
Viacheslav
Деңгээл

JDBC же баары кайда башталат

Группада жарыяланган
Заманбап дүйнөдө маалымат сактагычсыз жол жок. Ал эми маалымат базалары менен иштөө тарыхы JDBC пайда болушу менен абдан көп убакыт мурун башталган. Мен JDBC үстүнө курулган эч кандай заманбап рамкасыз жасай албаган нерсени эстеп калууну сунуштайм. Андан тышкары, алар менен иштешкенде да, кээде «тамырыңа кайтууга» мүмкүнчүлүк керек болушу мүмкүн. Бул карап чыгуу киришүү катары жардам берет же эс тутумуңузду жаңыртууга жардам берет деп үмүттөнөм.
JDBC же баары башталат - 1

Киришүү

Программалоо тorнин негизги максаттарынын бири - маалыматты сактоо жана иштетүү. Маалыматтарды сактоо кандайча иштээрин жакшыраак түшүнүү үчүн, колдонмолордун теориясына жана архитектурасына бир аз убакыт бөлүү керек. Мисалы, сиз адабияттарды, тактап айтканда, " Программалык камсыздоонун архитекторунун колдонмосу: эффективдүү арканы ишке ашыруу аркылуу ийгorктүү программалык камсыздоо архитектору болуңуз... " китебин окуй аласыз Джозеф Инжено. Айтылгандай, белгилүү бир маалымат деңгээли же "Маалымат катмары" бар. Ал маалыматтарды сактоо үчүн жерди (мисалы, SQL маалымат базасы) жана маалымат дүкөнү менен иштөө куралдарын камтыйт (мисалы, JDBC, алар талкууланат). Майкрософт веб-сайтында дагы макала бар: “ Инфраструктуранын туруктуу катмарын долбоорлоо ”, анда кошумча катмарды Берorштер деңгээлинен - ​​Персистенция катмарынан бөлүүнүн архитектуралык чечими сүрөттөлөт. Бул учурда, Берorштер деңгээли - бул маалыматтардын өзүн сактоо деңгээли, ал эми туруктуулук катмары - бул маалымат деңгээлинен сактагычтагы маалыматтар менен иштөө үчүн абстракциянын кандайдыр бир деңгээли. Persistence Layer "DAO" үлгүсүн же ар кандай ORMдерди камтышы мүмкүн. Бирок ORM башка талкуу үчүн тема болуп саналат. Сиз буга чейин түшүнгөн болушуңуз керек, маалымат деңгээли биринчи пайда болгон. JDK 1.1 учурунан бери Java дүйнөсүндө JDBC (Java DataBase Connectivity - Java тorндеги маалымат базаларына кошулуу) пайда болгон. Бул Java тиркемелеринин Java SEге кирген java.sql жана javax.sql пакеттери түрүндө ишке ашырылган ар кандай DBMS менен өз ара аракеттенүү стандарты:
JDBC же баары башталат - 2
Бул стандарт " JSR 221 JDBC 4.1 API " спецификациясы менен сүрөттөлгөн . Бул спецификация JDBC API Java тorнде жазылган программалардан реляциялык маалымат базаларына программалык кирүүнү камсыздай турганын айтат. Ал ошондой эле JDBC API Java платформасынын бир бөлүгү болуп саналат жана ошондуктан Java SE жана Java EE кирет деп айтылат. JDBC API эки пакетте берилген: java.sql жана javax.sql. Келгиле анда алар менен таанышалы.
JDBC же баары башталат - 3

Иштин башталышы

JDBC API жалпысынан эмне экенин түшүнүү үчүн бизге Java тиркемеси керек. Долбоорду чогултуу системаларынын бирин колдонуу эң ыңгайлуу. Мисалы, Gradle колдонолу . Сиз Gradle жөнүндө кененирээк бул кыскача баяндамадан окуй аласыз: " Градлга кыскача киришүү ". Биринчиден, жаңы Gradle долбоорун инициализация кылалы. Gradle функционалдуулугу плагиндер аркылуу ишке ашырылгандыктан, инициализациялоо үчүн “ Gradle Build Init Plugin ” колдонушубуз керек :
gradle init --type java-application
Андан кийин, куруу сценарийин ачалы - build.gradle файлы , ал биздин долбоорду жана аны менен кантип иштөөнү сүрөттөйт. Бизди " көз карандылыктар " блогу кызыктырат , анда көз карандылыктар сүрөттөлөт, башкача айтканда, биз аларсыз иштей албай турган жана биз көз каранды болгон китепканалар/алHowтар/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 бар. Бул маалымат базаларынын ар бири маалымат базасын сатуучулар деп аталган өзүнчө компания тарабынан берилет. Ар бир маалымат базасы өзүнүн программалоо тorнде жазылган (сөзсүз 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 же баары башталат - 5

Байланыш

Ошентип, бизде JDBC драйвери бар, бизде JDBC API бар. Эсибизде болгондой, JDBC Java DataBase Connectivity дегенди билдирет. Ошондуктан, баары Connectivity менен башталат - байланыш түзүү мүмкүнчүлүгү. Ал эми байланыш - бул Байланыш. Келгиле, кайра 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());
	}
}
Бул сыноо, аткарылганда, натыйжада байланыш жарактуу (туура түзүлгөн) жана ал жабылбаганын текшерет. Ресурстарды колдонуу менен биз ресурстарга муктаж болбой калгандан кийин бошотобуз. Бул бизди туташуулардан жана эс тутумдун агып кетүүсүнөн коргойт. Берorштер базасы менен болгон бардык аракеттер байланышты талап кылгандыктан, тесттин башында @Test менен Байланыш деп белгиленген калган сыноо ыкмаларын берели, биз тесттен кийин чыгарабыз. Бул үчүн бизге эки 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 же баары башталат - 6

Билдирүүлөр

Андан кийин бизди билдирүүлөр же туюнтмалар кызыктырат. Алар " 13-ГЛАВА билдирүүлөр " бөлүмүндөгү documentацияда баяндалган . Биринчиден, ал билдирүүлөрдүн бир нече түрлөрү же түрлөрү бар деп айтылат:
  • Билдирме: эч кандай параметрлерди камтыган SQL туюнтмасы
  • PreparedStatement : Киргизүү параметрлерин камтыган даярдалган SQL билдирүүсү
  • CallableStatement: SQL сакталган proceduresалардан кайтаруу маанисин алуу мүмкүнчүлүгү бар SQL туюнтмасы.
Ошентип, байланыш бар, биз бул байланыштын алкагында кандайдыр бир өтүнүчтү аткара алабыз. Ошондуктан, биз алгач Connection'тан SQL туюнтмасынын мисалын алганыбыз логикалык. Сиз table түзүү менен баштоо керек. Таблица түзүү өтүнүчүн String өзгөрмө катары сүрөттөп көрөлү. Муну кандай жасаш керек? Келгиле, " sqltutorial.org ", " sqlbolt.com ", " postgresqltutorial.com ", " codecademy.com " сыяктуу окуу куралдарын колдонолу. Мисалы, khanacademy.org сайтындагы SQL курсунун мисалын колдонолу . Берorштер базасына туюнтманы аткаруунун ыкмасын кошолу:
private int executeUpdate(String query) throws SQLException {
	Statement statement = connection.createStatement();
	// Для Insert, Update, Delete
	int result = statement.executeUpdate(query);
	return result;
}
Мурунку ыкманы колдонуу менен тесттик table түзүү ыкмасын кошолу:
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 же баары башталат - 7

ResultSet

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" деп кайтарса, анда эч кандай маалымат жок, башкача айтканда, курсор берorштерди көрсөткөн эмес. Эгерде биз жараксыз курсор менен маалыматтарды алууга аракет кылсак, анда биз ката алабыз: Маалымат жок. 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();
}

RowSet

ResultSet'тен тышкары, JDBC RowSet концепциясын киргизет. Сиз бул жерден көбүрөөк окуй аласыз: " JDBC Негиздери: RowSet an objectтерин колдонуу ". Колдонуунун ар кандай варианттары бар. Мисалы, эң жөнөкөй окуя мындай көрүнүшү мүмкүн:
@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 же баары башталат - 8

Метадайындар

Суроолордон тышкары, маалымат базасына туташуу (б.а., Connection классынын инстанциясы) метаберorштерге жетүү мүмкүнчүлүгүн берет - биздин маалымат базабыз кантип конфигурацияланган жана уюштурулгандыгы жөнүндө маалыматтар. Бирок, адегенде, бир нече негизги ойлорду айта кетели: Биздин маалымат базасына туташуу үчүн URL: "jdbc:h2:mem:test". тест биздин маалымат базабыздын аты. JDBC API үчүн бул каталог. Ал эми аты баш тамга менен болот, башкача айтканда, ТЕСТ. Н2 үчүн демейки схема PUBLIC. Эми, келгиле, бардык колдонуучу tableларын көрсөткөн тест жазалы. Эмне үчүн салт? Анткени маалымат базаларында колдонуучу tableлары гана эмес (table туюнтмаларын түзүү аркылуу өзүбүз түзгөндөр), ошондой эле системалык tableлар да бар. Алар маалымат базасынын түзүмү жөнүндө системалык маалыматты сактоо үчүн зарыл. Ар бир маалымат базасы мындай система tableларын ар кандай сактай алат. Мисалы, Н2де алар " INFORMATION_SCHEMA " схемасында сакталат . Кызыктуусу, МААЛЫМАТ СХЕМАСЫ – бул кеңири таралган ыкма, бирок Oracle башка жол менен кетти. Бул жерден көбүрөөк окуй аласыз: " INFORMATION_SCHEMA жана Oracle ". Келгиле, колдонуучу tableларында метаберorштерди кабыл алган тест жазалы:
@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 же баары башталат - 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 же баары башталат - 10

Транзакциялар

JDBC жөнүндө эң кызыктуу нерселердин бири - транзакциялар. JDBC спецификациясында аларга "10-БӨЛҮМ Бүтүмдөр" бөлүмү ыйгарылган. Биринчиден, бул бүтүм деген эмне экенин түшүнүү керек. Транзакция – бул бүтүндөй иштетилген же жокко чыгарылган маалыматтар боюнча логикалык айкалыштырылган ырааттуу операциялардын тобу. JDBC колдонгондо транзакция качан башталат? Спецификацияда айтылгандай, бул түздөн-түз JDBC драйвери тарабынан чечилет. Бирок, адатта, жаңы транзакция учурдагы SQL билдирүүсү транзакцияны талап кылганда жана транзакция али түзүлө элек кезде башталат. Транзакция качан бүтөт? Бул авто-милдеттүү атрибуту тарабынан көзөмөлдөнөт. Эгер автокоммит иштетилсе, транзакция SQL билдирүүсү "аякталгандан" кийин аяктайт. "Аткарылган" деген эмнени билдирет SQL туюнтмасынын түрүнө жараша болот:
  • Маалыматтарды манипуляциялоо тor, ошондой эле DML катары белгилүү (Insert, Update, Delete)
    Транзакция аракет аяктагандан кийин бүтөт.
  • Транзакцияларды тандоо
    ResultSet жабылганда бүтөт ( ResultSet#close )
  • CallableStatement жана бир нече натыйжаларды берген туюнтмалар
    Бардык байланышкан ResultSets жабылганда жана бардык чыгарылыштар алынганда (жаңыртуулардын санын кошо алганда)
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 же баары башталат - 11

Изоляция деңгээли

JDBC спецификациясынын "10.2 Транзакцияларды изоляциялоо деңгээли" бөлүмчөсүн ачалы. Бул жерде, андан ары өтүүдөн мурун, мен ACID сыяктуу нерсени эстегим келет. ACID транзакциялык системага талаптарды сүрөттөйт.
  • Atomicity:
    Эч кандай транзакция жарым-жартылай системага жүктөлбөйт. Же анын бардык суб-операциялары аткарылат, же бири дагы аткарылbyte.
  • Ырааттуулук:
    Ар бир ийгorктүү транзакция, аныктама боюнча, жарактуу натыйжаларды гана жазат.
  • Изоляция:
    транзакция иштеп жатканда, параллелдүү транзакциялар анын жыйынтыгына таасирин тийгизбеши керек.
  • Узактыгы:
    Эгерде транзакция ийгorктүү аяктаса, ага киргизилген өзгөртүүлөр кандайдыр бир ийгorксиздиктен улам артка кайтарылbyte.
Транзакциянын изоляциясынын деңгээли жөнүндө сөз болгондо, биз "Изоляция" талабы жөнүндө сөз болуп жатабыз. Изоляция кымбат талап болуп саналат, ошондуктан реалдуу маалымат базаларында транзакцияны толугу менен обочолонбогон режимдер бар (кайталануучу окуу изоляция деңгээли жана андан төмөн). Wikipedia транзакциялар менен иштөөдө пайда болушу мүмкүн болгон көйгөйлөрдүн сонун түшүндүрмөсү бар. Бул жерден көбүрөөк окуу керек: " Транзакцияларды колдонуу менен параллелдүү жетүү көйгөйлөрү ." Тестти жазуудан мурун, келгиле, Gradle Build Scriptти бир аз өзгөртөлү: касиеттери бар блокту, башкача айтканда, биздин долбоордун орнотуулары менен кошобуз:
ext {
    h2Version = '1.3.176' // 1.4.177
    hikariVersion = '3.3.1'
    junitVersion = '4.12'
}
Андан кийин, биз муну versionларда колдонобуз:
dependencies {
    implementation "com.h2database:h2:${h2Version}"
    implementation "com.zaxxer:HikariCP:${hikariVersion}"
    testImplementation "junit:junit:${junitVersion}"
}
Сиз h2 versionсы төмөн болуп калганын байкаган чыгарсыз. Мунун себебин кийинчерээк көрөбүз. Ошентип, сиз изоляция деңгээлин кантип колдоносуз? Келгиле, дароо кичинекей практикалык мисалды карап көрөлү:
@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 колдоого албаган сатуучуда ийгorксиз болушу мүмкүн (мисалы, sqlite же HSQL). Жана транзакция деңгээли жөн эле иштебеши мүмкүн. H2 Database драйверинин versionсын көрсөткөнүбүз эсиңиздеби? Эгерде биз аны h2Version = '1.4.177' жана андан жогору көтөрсөк, анда биз codeду өзгөртпөгөнүбүз менен READ UNCOMMITTED иштебей калат. Бул дагы бир жолу сатуучу жана драйвер versionсын тандоо тамгалар эмес экенин далилдейт, ал чындыгында сиздин суроо-талаптарыңыз кандай аткарыларын аныктайт. Бул жүрүм-турумду кантип оңдоону 1.4.177 versionсында жана ал кантип жогорку versionларда иштебей турганын бул жерден окуй аласыз: " MVStore режиминде READ UNCOMMITTED изоляция деңгээлин колдоо ".
JDBC же баары башталат - 12

Төмөнкү сызык

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