Заманбап дүйнөдө маалымат сактагычсыз жол жок. Ал эми маалымат базалары менен иштөө тарыхы JDBC пайда болушу менен абдан көп убакыт мурун башталган. Мен JDBC үстүнө курулган эч кандай заманбап рамкасыз жасай албаган нерсени эстеп калууну сунуштайм. Андан тышкары, алар менен иштешкенде да, кээде «тамырыңа кайтууга» мүмкүнчүлүк керек болушу мүмкүн. Бул карап чыгуу киришүү катары жардам берет же эс тутумуңузду жаңыртууга жардам берет деп үмүттөнөм.
Бул стандарт " JSR 221 JDBC 4.1 API " спецификациясы менен сүрөттөлгөн . Бул спецификация JDBC API Java тorнде жазылган программалардан реляциялык маалымат базаларына программалык кирүүнү камсыздай турганын айтат. Ал ошондой эле JDBC API Java платформасынын бир бөлүгү болуп саналат жана ошондуктан Java SE жана Java EE кирет деп айтылат. JDBC API эки пакетте берилген: java.sql жана javax.sql. Келгиле анда алар менен таанышалы.
Көрүнүп тургандай, бул логикалуу, маалымат базасы Java SEге таандык эмес тышкы компонент. Бул жөнөкөй эле түшүндүрүлөт - көп сандагы маалымат базалары бар жана сиз каалаган менен иштей аласыз. Мисалы, PostgreSQL, Oracle, MySQL, H2 бар. Бул маалымат базаларынын ар бири маалымат базасын сатуучулар деп аталган өзүнчө компания тарабынан берилет. Ар бир маалымат базасы өзүнүн программалоо тorнде жазылган (сөзсүз Java эмес). Java тиркемесинин маалымат базасы менен иштөө үчүн, маалымат базасынын провайдери өзүнүн сүрөт адаптери болгон атайын драйверди жазат. Мындай JDBC шайкеш болгондор (башкача айтканда, JDBC драйвери барлар) "JDBC-Шайкеш маалымат базасы" деп да аталат. Бул жерде биз компьютердик түзүлүштөр менен салыштырууга болот. Мисалы, блокнотто "Басып чыгаруу" баскычы бар. Аны баскан сайын программа операциялык системага блокнот тиркемеси басып чыгаргысы келгенин айтат. Жана сизде принтер бар. Операция системаңызды Canon же HP принтери менен бирдей байланышууга үйрөтүү үчүн сизге ар кандай драйверлер керек болот. Бирок сиз үчүн, колдонуучу катары, эч нерсе өзгөрбөйт. Сиз дагы эле ошол эле баскычты басасыз. JDBC менен бирдей. Сиз бир эле codeду иштетип жатасыз, жөн гана капоттун астында ар кандай маалымат базалары иштеп жаткан болушу мүмкүн. Бул абдан ачык-айкын мамиле деп ойлойм. Ар бир мындай JDBC драйвери кандайдыр бир артефакт, китепкана, jar файлы. Бул биздин долбоордун көз карандылыгы. Мисалы, биз маалымат базасын тандай алабыз " H2 Database " жана андан кийин төмөнкүдөй көз карандылыкты кошуу керек:
Киришүү
Программалоо т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 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 бар экен. Абдан жакшы. Бизге дагы эмне керек? Мындай сонун диаграмма бар:
dependencies {
implementation 'com.h2database:h2:1.4.197'
Көз карандылыкты кантип табуу жана аны кантип сыпаттоо маалымат базасынын провайдеринин расмий сайттарында же " Maven Central " сайтында көрсөтүлгөн. JDBC драйвери сиз түшүнгөндөй маалымат базасы эмес. Бирок ал ага жол көрсөтүүчү гана. Бирок " Эстим базаларында " деген нерсе бар . Булар сиздин тиркемеңиздин өмүр бою эстутумда сакталган маалымат базалары. Эреже катары, бул көбүнчө тестирлөө же окутуу максатында колдонулат. Бул машинага өзүнчө маалымат базасы serverин орнотуудан качууга мүмкүндүк берет. Бул JDBC менен таанышуу үчүн абдан ылайыктуу. Ошентип, биздин кумкоргон даяр жана биз баштайбыз.
Байланыш
Ошентип, бизде JDBC драйвери бар, бизде JDBC API бар. Эсибизде болгондой, JDBC Java DataBase Connectivity дегенди билдирет. Ошондуктан, баары Connectivity менен башталат - байланыш түзүү мүмкүнчүлүгү. Ал эми байланыш - бул Байланыш. Келгиле, кайра JDBC спецификациясынын текстине кайрылып , мазмунун карап көрөлү. « 4-БӨЛҮМ КЕРЕК » бөлүмүндө (обзор) биз « 4.1 Байланыш түзүү » бөлүмүнө кайрылабыз (байланыш түзүү) маалымат базасына кошулуунун эки жолу бар экени айтылат:- DriverManager аркылуу
- DataSource аркылуу
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 туташуусуна ээ болууга кепилдик берилет жана аны ар дайым өзү түзүүнүн кереги жок.
Билдирүүлөр
Андан кийин бизди билдирүүлөр же туюнтмалар кызыктырат. Алар " 13-ГЛАВА билдирүүлөр " бөлүмүндөгү documentацияда баяндалган . Биринчиден, ал билдирүүлөрдүн бир нече түрлөрү же түрлөрү бар деп айтылат:- Билдирме: эч кандай параметрлерди камтыган SQL туюнтмасы
- PreparedStatement : Киргизүү параметрлерин камтыган даярдалган SQL билдирүүсү
- CallableStatement: SQL сакталган proceduresалардан кайтаруу маанисин алуу мүмкүнчүлүгү бар SQL туюнтмасы.
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 катары көрсөтүлөт.
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 колдонуу ".
Метадайындар
Суроолордон тышкары, маалымат базасына туташуу (б.а., 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 спецификациясындагы туташуу пулунда "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 жөнүндө эң кызыктуу нерселердин бири - транзакциялар. JDBC спецификациясында аларга "10-БӨЛҮМ Бүтүмдөр" бөлүмү ыйгарылган. Биринчиден, бул бүтүм деген эмне экенин түшүнүү керек. Транзакция – бул бүтүндөй иштетилген же жокко чыгарылган маалыматтар боюнча логикалык айкалыштырылган ырааттуу операциялардын тобу. JDBC колдонгондо транзакция качан башталат? Спецификацияда айтылгандай, бул түздөн-түз JDBC драйвери тарабынан чечилет. Бирок, адатта, жаңы транзакция учурдагы SQL билдирүүсү транзакцияны талап кылганда жана транзакция али түзүлө элек кезде башталат. Транзакция качан бүтөт? Бул авто-милдеттүү атрибуту тарабынан көзөмөлдөнөт. Эгер автокоммит иштетилсе, транзакция SQL билдирүүсү "аякталгандан" кийин аяктайт. "Аткарылган" деген эмнени билдирет SQL туюнтмасынын түрүнө жараша болот:- Маалыматтарды манипуляциялоо тor, ошондой эле DML катары белгилүү (Insert, Update, Delete)
Транзакция аракет аяктагандан кийин бүтөт. Транзакцияларды тандоо
- CallableStatement жана бир нече натыйжаларды берген туюнтмалар
Бардык байланышкан ResultSets жабылганда жана бардык чыгарылыштар алынганда (жаңыртуулардын санын кошо алганда)
ResultSet жабылганда бүтөт ( ResultSet#close )
@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 спецификациясынын "10.2 Транзакцияларды изоляциялоо деңгээли" бөлүмчөсүн ачалы. Бул жерде, андан ары өтүүдөн мурун, мен ACID сыяктуу нерсени эстегим келет. ACID транзакциялык системага талаптарды сүрөттөйт.- Atomicity:
Эч кандай транзакция жарым-жартылай системага жүктөлбөйт. Же анын бардык суб-операциялары аткарылат, же бири дагы аткарылbyte. - Ырааттуулук:
Ар бир ийгorктүү транзакция, аныктама боюнча, жарактуу натыйжаларды гана жазат. - Изоляция:
транзакция иштеп жатканда, параллелдүү транзакциялар анын жыйынтыгына таасирин тийгизбеши керек. - Узактыгы:
Эгерде транзакция ийгorктүү аяктаса, ага киргизилген өзгөртүүлөр кандайдыр бир ийгorксиздиктен улам артка кайтарылbyte.
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 маалымат базалары менен иштөө үчүн Java колундагы күчтүү курал. Бул кыска карап чыгуу сизге баштапкы чекит берүүгө же эс тутумуңузду жаңыртууга жардам берет деп үмүттөнөм. Ошондой эле, закуска үчүн, кээ бир кошумча материалдар:- Өрт отчету: " Транзакциялар: мифтер, сюрприздер жана мүмкүнчүлүктөр " Мартин Клеппмандан
- Юрий Ткач: " JPA. Транзакциялар "
- Юрик Ткач: " JDBC - Java тестерлер үчүн "
- Udemy боюнча акысыз курс: " JDBC жана MySQL "
- " CallableStatement an objectтерин иштетүү "
- IBM Developer: " Java Database Connectivity "
- IBM Бorм борбору: " JDBC менен баштоо "
GO TO FULL VERSION