Inyaniso kuqala, okanye kutheni inkqubo kufuneka iyilwe ngokusekelwe kuyilo lwedathabheyisi

Hayi Habr!

Siyaqhubeka nokuphanda isihloko Java ΠΈ intlakohlaza, kubandakanywa kwinqanaba ledathabheyisi. Namhlanje siyakumema ukuba ufunde malunga nokuba kutheni, xa uyila izicelo ezinkulu, isiseko sesiseko sedatha, kwaye kungekhona ikhowudi yeJava, ekufuneka ibaluleke kakhulu, ukuba kwenziwa njani oku, kwaye zeziphi izinto ezingaphandle kulo mgaqo.

Kweli nqaku lamva nje, ndiza kuchaza ukuba kutheni ndikholelwa ukuba phantse kuzo zonke iimeko, imodeli yedatha kwisicelo kufuneka iyilwe "isuka kwisiseko sedatha" kunokuba "isuse kwizakhono zeJava" (okanye naluphi na ulwimi lomxhasi onawo. ukusebenza kunye). Ngokuthatha indlela yesibini, uzibekela indlela ende yeentlungu kunye nokubandezeleka xa iprojekthi yakho iqala ukukhula.

Inqaku labhalwa ngokusekelwe umbuzo omnye, inikwe kwiStack Overflow.

Iingxoxo ezinomdla kwi-reddit kumacandelo /r/java ΠΈ /r/nkqubo.

Ukuveliswa kwekhowudi

Ndothuke kanjani into yokuba kukho icandelo elincinci labasebenzisi abathi, bathe baqhelana ne-jOOQ, bacatshukiswa yinto yokuba i-jOOQ ithembele ngokunzulu ekuveliseni ikhowudi yomthombo ukuze isebenze. Akukho mntu ukunqandayo ekusebenziseni i-jOOQ njengoko ubona kufanelekile, okanye akunyanzele ukuba usebenzise ukuvelisa ikhowudi. Kodwa okungagqibekanga (njengoko kuchaziwe kwincwadana) indlela yokusebenza nge jOOQ kukuba uqala nge (ilifa) schema sedatabase, uyibuyisele umva injineli usebenzisa ikhowudi yejenereyitha yejOOQ ukuze ufumane uluhlu lweeklasi ezimele iitafile zakho, kwaye emva koko ubhale uhlobo. -imibuzo ekhuselekileyo kwezi theyibhile:

	for (Record2<String, String> record : DSL.using(configuration)
//   ^^^^^^^^^^^^^^^^^^^^^^^ Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ ΠΎ Ρ‚ΠΈΠΏΠ°Ρ… Π²Ρ‹Π²Π΅Π΄Π΅Π½Π° Π½Π° 
//   основании сгСнСрированного ΠΊΠΎΠ΄Π°, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ссылаСтся ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠ΅
// Π½ΠΈΠΆΠ΅ условиС SELECT 
 
       .select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
//           vvvvv ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^ сгСнСрированныС ΠΈΠΌΠ΅Π½Π°
       .from(ACTOR)
       .orderBy(1, 2)) {
    // ...
}

Ikhowudi yenziwa mhlawumbi ngesandla ngaphandle kwendibano, okanye ngesandla kwindibano nganye. Ngokomzekelo, ukuvuselelwa okunjalo kunokulandela ngokukhawuleza emva koko Ukufuduka kwedatha ye-Flyway, enokwenziwa ngesandla okanye ngokuzenzekelayo.

Ukuveliswa kwekhowudi yomthombo

Kukho iifilosofi ezahlukeneyo, iingenelo kunye nokungonakali ezinxulumene nezi ndlela zokuvelisa ikhowudi - manual kunye ngokuzenzekelayo - ukuba andiyi kuxoxa ngokweenkcukacha kweli nqaku. Kodwa, ngokubanzi, yonke ingongoma yekhowudi eveliswayo kukuba ivumela ukuba sivelise kwakhona kwiJava ukuba "inyaniso" esiyithathayo, mhlawumbi ngaphakathi kwenkqubo yethu okanye ngaphandle kwayo. Ngandlel 'ithile, le yinto eyenziwa ngabaqulunqi xa bevelisa i-bytecode, ikhowudi yomatshini, okanye enye indlela yekhowudi yomthombo - sifumana ukumelwa "kwenyani" yethu ngolunye ulwimi, kungakhathaliseki ukuba ziziphi izizathu.

Zininzi iijenereyitha zekhowudi ezinjalo. Umzekelo, I-XJC inokuvelisa ikhowudi yeJava ngokusekelwe kwiifayile ze-XSD okanye zeWSDL. Umgaqo uhlala ufana:

  • Kukho inyaniso (yangaphakathi okanye yangaphandle) - umzekelo, inkcazo, imodeli yedatha, njl.
  • Sidinga umelo lwasekuhlaleni lwale nyaniso ngolwimi lwethu lwenkqubo.

Ngaphezu koko, phantse kusoloko kucetyiswa ukuba kuveliswe ukumelwa okunjalo ukuze kuthintelwe ukungafuneki.

Ababoneleli boHlobo kunye noLungiselelo lweSihlomelo

Qaphela: enye indlela yale mihla kunye nengqalileyo yokuvelisa ikhowudi yejOOQ isebenzisa ababoneleli bohlobo, njengoko ziphunyezwa kwi F#. Kule meko, ikhowudi yenziwe ngumqambi, ngokwenene kwinqanaba lokudibanisa. Ngokomgaqo, ikhowudi enjalo ayikho kwifom yomthombo. I-Java iyafana, nangona ingekho njengobuhle, izixhobo-iiprosesa zenkcazo, umzekelo, Lombok.

Ngandlela ithile, izinto ezifanayo zenzeka apha njengakwimeko yokuqala, ngaphandle koku:

  • Awuyiboni ikhowudi eyenziwe (mhlawumbi le meko ibonakala ingathandeki kumntu?)
  • Kufuneka uqinisekise ukuba iintlobo zinokubonelelwa, oko kukuthi, "inyaniso" kufuneka ihlale ikhona. Oku kulula kwimeko yeLombok, echaza "inyaniso". Kunzima ngakumbi kwiimodeli zesiseko sedatha ezixhomekeke kuqhagamshelwano oluhlala lukhona.

Yintoni ingxaki ngokwenza ikhowudi?

Ukongeza kumbuzo okhohlisayo wendlela engcono yokuqhuba ukuveliswa kwekhowudi - ngesandla okanye ngokuzenzekelayo, kufuneka sikhankanye ukuba kukho abantu abakholelwa ukuba ukuveliswa kwekhowudi akufuneki kwaphela. Ukuthetheleleka kolu luvo, endiye ndadibana nalo rhoqo, kukuba kunzima ukuseta umbhobho wokwakha. Ewe, kunzima ngokwenene. Iindleko ezongezelelweyo zeziseko zophuhliso ziyavela. Ukuba usandula ukuqalisa ngemveliso ethile (nokuba yi-jOOQ, okanye i-JAXB, okanye i-Hibernate, njl.), ukuseta indawo yemveliso kuthatha ixesha ongathanda ukulichitha ufunda i-API ngokwayo ukuze ukwazi ukukhupha ixabiso kuyo. .

Ukuba iindleko ezihambelana nokuqonda isakhiwo se-generator ziphezulu kakhulu, ngoko ke, ngokwenene, i-API yenza umsebenzi ombi ekusebenziseni i-generator yekhowudi (kwaye kamva kuvela ukuba ukulungiswa komsebenzisi kuyo kunzima). Ukusebenziseka kufuneka kube yeyona nto iphambili kuyo nayiphi na i-API enjalo. Kodwa le yingxoxo nje enye ngokuchasene nokuveliswa kwekhowudi. Kungenjalo, kuyincwadi ngokupheleleyo ukubhala umelo lwangaphakathi lwenyaniso yangaphakathi okanye yangaphandle.

Abaninzi baya kuthi abanalo ixesha lokwenza konke oku. Baphelelwa lixesha leMveliso yabo eyiSuper. Ngenye imini siyakuqoqosha iiconveyors ze assembly, sizakuba nexesha. Ndiya kubaphendula:

Inyaniso kuqala, okanye kutheni inkqubo kufuneka iyilwe ngokusekelwe kuyilo lwedathabheyisi
Okwangempela, UAlan O'Rourke, Isitaki sabaphulaphuli

Kodwa kwiHibernate/JPA kulula kakhulu ukubhala ikhowudi yeJava.

Ngokwenene. Ku-Hibernate kunye nabasebenzisi bayo, oku kuyintsikelelo kunye nesiqalekiso. Kwi-Hibernate ungabhala ngokulula izinto ezimbalwa, ngolu hlobo:

	@Entity
class Book {
  @Id
  int id;
  String title;
}

Kwaye phantse yonke into ilungile. Ngoku kuxhomekeke ku-Hibernate ukuvelisa "iinkcukacha" ezintsonkothileyo zokuba le nto izakuchazwa njani kwi-DDL ye "dialect" yakho yeSQL:

	CREATE TABLE book (
  id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
  title VARCHAR(50),
 
  CONSTRAINT pk_book PRIMARY KEY (id)
);
 
CREATE INDEX i_book_title ON book (title);

... kwaye uqalise ukusebenzisa isicelo. Ithuba elihle kakhulu lokuqalisa ngokukhawuleza kwaye uzame izinto ezahlukeneyo.

Nangona kunjalo, ndicela undivumele. Bendixoka.

  • Ngaba u-Hibernate uya kuyinyanzelisa inkcazo yesi sitshixo siphambili?
  • Ngaba i-Hibernate iyakwenza isalathisi kwi-TITLE? – Ndiyazi ngokuqinisekileyo ukuba siya kuyidinga.
  • Ngaba i-Hibernate iya kwenza kanye esi sitshixo sichonge kwiSicaciso sesazisi?

Mhlawumbi akunjalo. Ukuba uphuhlisa iprojekthi yakho ukusuka ekuqaleni, kuhlala kulula ukulahla isiseko sedatha esidala kwaye uvelise entsha ngokukhawuleza ukuba wongeze amanqakwana ayimfuneko. Ke, iqumrhu leNcwadi liya kuthi ekugqibeleni lithathe ifom:

	@Entity
@Table(name = "book", indexes = {
  @Index(name = "i_book_title", columnList = "title")
})
class Book {
  @Id
  @GeneratedValue(strategy = IDENTITY)
  int id;
  String title;
}

Kuhle. Hlaziya. Kwakhona, kule meko kuya kuba lula kakhulu ekuqaleni.

Kodwa kuya kufuneka uyihlawule kamva

Kungekudala okanye kamva kuya kufuneka uye kwimveliso. Kulapho le modeli iya kuyeka ukusebenza. Ngenxa yokuba:

Kwimveliso, akusayi kuphinda kwenzeke, ukuba kuyimfuneko, ukulahla i-database endala kwaye uqale ukusuka ekuqaleni. Uvimba wakho wedatha uya kuba lilifa.

Ukususela ngoku kude kube ngunaphakade kuya kufuneka ubhale Izikripthi zokufuduka kwe-DDL, umzekelo, usebenzisa i-Flyway. Kuya kwenzeka ntoni kumaziko akho kule meko? Unokuzilungelelanisa ngesandla (kwaye ngaloo ndlela uphinda kabini umthwalo wakho womsebenzi), okanye ungaxelela i-Hibernate ukuba iphinde ikuvelisele yona (ingakanani inokwenzeka ukuba ezo zenziwe ngale ndlela ukuhlangabezana nolindelo lwakho?) Nokuba yeyiphi indlela, ulahlekelwe.

Ke wakuba ungenile kwimveliso uya kufuna amabala ashushu. Kwaye kufuneka zifakwe kwimveliso ngokukhawuleza okukhulu. Kuba ungakhange ulungiselele kwaye ungakhange uququzelele umbhobho ogudileyo wokufuduka kwakho kwimveliso, ulungisa yonke into. Kwaye ke awusenalo ixesha lokwenza yonke into ngokuchanekileyo. Kwaye uyamgxeka uHibernate, kuba ihlala ilityala lomnye umntu, hayi wena...

Kunoko, izinto ngezazizenziwe ngokwahluke ngokupheleleyo kwasekuqaleni. Umzekelo, faka amavili angqukuva kwibhayisekile.

Isiseko sedatha kuqala

"Inyaniso" yokwenyani kwi-schema sedatabase yakho kunye "nolongamo" phezu kwayo ingaphakathi kwendawo egciniweyo. I-schema ichazwa kuphela kwi-database ngokwayo kwaye akukho ndawo, kwaye umxhasi ngamnye unekopi yesi schema, ngoko kunengqiqo ukunyanzelisa ukuthotyelwa kwe-schema kunye nokunyaniseka kwayo, ukuyenza ngokufanelekileyo kwi-database - apho ulwazi lukhona. igcinwe.
Bubulumko obu budala, nobuqhetseba. Izitshixo eziphambili kunye ezizodwa zilungile. Izitshixo zangaphandle zilungile. Ukujonga izithintelo kulungile. Ukuqinisekisa - Kulungile.

Ngaphezu koko, akuphelelanga apho. Umzekelo, usebenzisa i-Oracle, ungafuna ukukhankanya:

  • Yeyiphi indawo yetafile ekwitafile yakho?
  • Lithini ixabiso layo lePCTFREE?
  • Ithini isayizi yecache kulandelelwano lwakho (emva kwe-id)

Oku kusenokungabalulekanga kwiinkqubo ezincinci, kodwa akunyanzelekanga ukuba ulinde de ungene kwindawo enkulu yedatha-ungaqalisa ukuxhamla kugcino olubonelelwa ngabathengisi njengalezo zikhankanywe ngasentla kwakamsinya. Akukho nanye kwii-ORM endizibonileyo (kuquka i-jOOQ) ebonelela ngokufikelela kwiseti epheleleyo yeenketho ze-DDL onokufuna ukuzisebenzisa kuvimba wakho wedatha. Ii-ORM zibonelela ngezixhobo ezithile ezikuncedayo ukuba ubhale i-DDL.

Kodwa ekupheleni kosuku, isiphaluka esiyilwe kakuhle sibhalwa ngesandla kwi-DDL. Nayiphi na i-DDL eveliswayo kukuqikelelwa kwayo kuphela.

Kuthekani ngemodeli yabathengi?

Njengoko kukhankanyiwe ngasentla, kumxhasi uya kufuna ikopi ye-schema yedatha yakho, imbono yomxhasi. Akufuneki kukhankanywa, le mbono yomxhasi kufuneka ihambelane nemodeli eyiyo. Yeyiphi eyona ndlela ilungileyo yokuphumeza oku? Ukusebenzisa ikhowudi generator.

Zonke iidathabheyisi zibonelela ngolwazi lwazo lwemeta ngeSQL. Nantsi indlela yokufumana zonke iitafile kwisiseko sedatha yakho kwiilwimi ezahlukeneyo zeSQL:

	-- H2, HSQLDB, MySQL, PostgreSQL, SQL Server
SELECT table_schema, table_name
FROM information_schema.tables
 
-- DB2
SELECT tabschema, tabname
FROM syscat.tables
 
-- Oracle
SELECT owner, table_name
FROM all_tables
 
-- SQLite
SELECT name
FROM sqlite_master
 
-- Teradata
SELECT databasename, tablename
FROM dbc.tables

Le mibuzo (okanye efanayo, kuxhomekeke ekubeni kufuneka uqwalasele iimbono, iimboniselo eziphathekayo, imisebenzi exatyiswe kwitheyibhile) nazo ziyenziwa ngokufowuna. DatabaseMetaData.getTables() ukusuka kwi-JDBC, okanye usebenzisa i-jOOQ meta-modyuli.

Kwiziphumo zemibuzo enjalo, kulula kakhulu ukuvelisa naluphi na umboniso wecala lomxhasi wemodeli yakho yesiseko sedatha, nokuba usebenzisa yeyiphi iteknoloji kumxhasi.

  • Ukuba usebenzisa i-JDBC okanye iNtwasahlobo, ungenza iseti yeentambo zemitya
  • Ukuba usebenzisa iJPA, unokuvelisa amaqumrhu ngokwawo
  • Ukuba usebenzisa i-jOOQ, unokuvelisa imodeli yemeta yejOOQ

Kuxhomekeke kubungakanani bomsebenzi obonelelwa ngumxhasi wakho we-API (umzekelo, i-jOOQ okanye i-JPA), imodeli yemeta eyenziweyo inokuba nobutyebi kwaye iphelele. Thatha, umzekelo, ukubakho kokudibanisa okucacileyo, yaziswa kwi-jOOQ 3.11, exhomekeke kulwazi lwemeta olwenziweyo malunga nobudlelwane obuphambili bangaphandle obukhoyo phakathi kweetafile zakho.

Ngoku nakuphi na ukonyuswa kwedatha kuya kuhlaziya ngokuzenzekelayo ikhowudi yomxhasi. Khawufane ucinge umzekelo:

ALTER TABLE book RENAME COLUMN title TO book_title;

Ngaba ngokwenene ungathanda ukwenza lo msebenzi kabini? Akukho meko. Yenza nje i-DDL, yiqhube ngombhobho wakho wokwakha, kwaye ufumane into ehlaziyiweyo:

@Entity
@Table(name = "book", indexes = {
 
  // Π’Ρ‹ ΠΎΠ± этом Π·Π°Π΄ΡƒΠΌΡ‹Π²Π°Π»ΠΈΡΡŒ?
  @Index(name = "i_book_title", columnList = "book_title")
})
class Book {
  @Id
  @GeneratedValue(strategy = IDENTITY)
  int id;
 
  @Column("book_title")
  String bookTitle;
}

Okanye iklasi ye-jOOQ ehlaziyiweyo. Uninzi lweenguqu ze-DDL zikwachaphazela i-semantics, kungekhona nje i-syntax. Ke ngoko, kunokuba luncedo ukujonga kwikhowudi ehlanganisiweyo ukubona ukuba yeyiphi ikhowudi eya (okanye inokuchaphazeleka) ngokunyuswa kwedatha yakho.

Inyaniso yodwa

Nokuba yeyiphi itekhnoloji oyisebenzisayo, kuhlala kukho imodeli enye ekuphela komthombo wenyaniso kwenye inkqubo engaphantsi-okanye, ubuncinci, kufuneka sizabalazele oku kwaye sikuphephe ukubhideka kweshishini, apho "inyani" ikhona yonke indawo kwaye akukho ndawo ngaxeshanye. . Yonke into inokuba lula ngakumbi. Ukuba utshintshiselana ngeefayile ze-XML ngenye indlela, sebenzisa nje i-XSD. Jonga kwi-INFORMATION_SCHEMA imeta-imodeli esuka ku-jOOQ kwifomu ye-XML:
https://www.jooq.org/xsd/jooq-meta-3.10.0.xsd

  • I-XSD iqondwa kakuhle
  • I-XSD ibeka uphawu lwe-XML kakuhle kakhulu kwaye ivumela ukuqinisekiswa kuzo zonke iilwimi zabaxumi
  • I-XSD iguqulelwe kakuhle kwaye ihambelane nomva
  • I-XSD inokuguqulelwa kwikhowudi yeJava kusetyenziswa i-XJC

Inqaku lokugqibela libalulekile. Xa unxibelelana nenkqubo yangaphandle usebenzisa imiyalezo yeXML, sifuna ukuqiniseka ukuba imiyalezo yethu iyasebenza. Oku kulula kakhulu ukufikelela usebenzisa i-JAXB, i-XJC kunye ne-XSD. Iya kuba yimpambano enkulu ukucinga ukuba, ngendlela yoyilo "ye-Java yokuqala" apho senza khona imiyalezo yethu njengezinto zeJava, ukuba ngandlel 'ithile inokufakwa kwimephu ehambelanayo kwi-XML kwaye ithunyelwe kwenye inkqubo ukuze isetyenziswe. I-XML eveliswe ngolu hlobo inokuba yeyomgangatho ophantsi kakhulu, ingabhalwanga phantsi, kwaye kunzima ukuyiphuhlisa. Ukuba bekukho isivumelwano senqanaba lenkonzo (i-SLA) kujongano olunjalo, besiya kuyijija ngoko nangoko.

Ngokunyaniseka, oku kwenzeka ngalo lonke ixesha nge-JSON APIs, kodwa lelinye ibali, ndiya kuxabana kwixesha elizayo ...

Databases: ziyafana

Xa usebenza ngogcino-lwazi, uyaqonda ukuba zonke ziyafana. Isiseko siphethe idatha yaso kwaye kufuneka silawule iskimu. Naluphi na uhlengahlengiso olwenziwe kwischema kufuneka luphunyezwe ngokuthe ngqo kwi-DDL ukuze kuhlaziywe umthombo omnye wenyaniso.

Xa uhlaziyo lomthombo lwenzekile, bonke abathengi kufuneka bahlaziye iikopi zabo zemodeli. Abanye abathengi banokubhalwa kwiJava usebenzisa i-jOOQ kunye neHibernate okanye i-JDBC (okanye zombini). Abanye abathengi banokubhalwa kwi-Perl (sibanqwenelela inhlanhla), ngelixa ezinye zingabhalwa kwi-C #. Ayinamsebenzi lonto. Imodeli ephambili ikwisiseko sedatha. Iimodeli ezenziwe kusetyenziswa ii-ORM zihlala zikumgangatho ophantsi, zibhalwe kakubi, kwaye kunzima ukuziphuhlisa.

Ngoko musa ukwenza iimpazamo. Musa ukwenza iimpazamo kwasekuqaleni. Sebenza kwisiseko sedatha. Yakha umbhobho wokusasaza onokuthi uzenzele. Nika amandla abavelisi bekhowudi ukwenza kube lula ukukopa imodeli yakho yedatha kwaye uyilahle kubathengi. Kwaye yeka ukuzikhathaza malunga neejeneretha zekhowudi. Balungile. Ngazo uya kuba nemveliso ngakumbi. Kufuneka nje uchithe ixesha elincinci uzimise kwasekuqaleni-kwaye ke iminyaka yokwanda kwemveliso ikulindile, eya kwenza imbali yeprojekthi yakho.

Ungandibuleli okwangoku, kamva.

Inkcazo

Ukucaca: Eli nqaku akukho ndlela ikhuthaza ukuba kufuneka ugobe inkqubo yonke (oko kukuthi, i-domain, i-logic yezoshishino, njl. njl.) Ukulungelelanisa imodeli yakho yedatha. Into endiyithethayo kweli nqaku kukuba ikhowudi yomxhasi esebenzisana nesiseko sedatha kufuneka isebenze ngesiseko somzekelo wesiseko sedatha, ukuze yona ngokwayo iphinde ivelise kwakhona imodeli yedatha kwi "class-class" status. Le ngqiqo idla ngokubekwa kumaleko wofikelelo lwedatha kumxhasi wakho.

Kwizakhiwo zemigangatho emibini, ezisagcinwe kwezinye iindawo, imodeli yenkqubo enjalo inokuba yodwa enokwenzeka. Nangona kunjalo, kwiinkqubo ezininzi umaleko wofikelelo lwedatha kum ubonakala ngathi "yinkqubo engaphantsi" equka imodeli yedatha.

Ngaphandle

Kukho izinto ezingafaniyo kuwo wonke umthetho, kwaye sele nditshilo ukuba indlela yokuvelisa i-database-yokuqala kunye nekhowudi yomthombo ngamanye amaxesha ayifaneleki. Nazi ezinye zezinto ezingaphandle (mhlawumbi kukho ezinye):

  • Xa i-schema ingaziwa kwaye ifuna ukufunyanwa. Umzekelo, ungumboneleli wesixhobo esinceda abasebenzisi ukuba bajonge kuyo nayiphi na idayagram. Yhuu. Akukho kuveliswa kwekhowudi apha. Kodwa kunjalo, i-database iza kuqala.
  • Xa isekethe kufuneka iveliswe ngempukane ukusombulula ingxaki ethile. Lo mzekelo ubonakala ngathi yinguqulelo encinci yepateni ixabiso lophawu loyelelwano, o.t., awunalo ngenene isicwangciso esichazwe ngokucacileyo. Kule meko, awusoloko ungaqinisekanga nokuba i-RDBMS iyakufanela.

Iimeko ezikhethekileyo ngokwendalo zikhethekile. Kwiimeko ezininzi ezibandakanya ukusetyenziswa kwe-RDBMS, i-schema iyaziwa kwangaphambili, ihlala ngaphakathi kwe-RDBMS kwaye iyona mthombo kuphela "wenyaniso", kwaye bonke abathengi kufuneka bafumane iikopi ezivela kuyo. Ngokufanelekileyo, kufuneka usebenzise ikhowudi generator.

umthombo: www.habr.com

Yongeza izimvo