JAVA JDBC
Přehled rozhraní pro přístup k relační databázi jednotné nezávislé na databázi výrobce databáze musí dodat JDBC driver umožňuje vykonávání SQL dotazů přístup k výsledkům dotazů podobné reflection API balíky java.sql, javax.sql verze JDK 1.4 JDBC 3.0 JDK 6 JDBC 4.0 JDK 7 JDBC 4.1 JDK 8 JDBC 4.2 JDK 9, 10 JDBC 4.3
JDBC Driver JDBC API v podstatě jen rozhraní implementace dodána přes driver driver explicitně natáhnout a zaregistrovat Class.forName("com.driver.Name"); po natažení driveru, vytvořit připojení na DB Connection con = DriverManager.getConnection(url, "mylogin", "mypassword"); url jdbc:mysql://localhost/test jdbc:odbc:source
JDBC Driver typy driveru Native-protocol pure Java driver Native-API partly-java driver JDBC-Net pure Java driver JDBC-ODBC bridge plus ODBC driver
Základní třídy a rozhraní DriverManager třída všechny metody jsou statické getconnection() několik variant getdrivers() všechny natažené drivery getlogwriter(), setlogwriter() println() zapis do logu getlogintimeout(), setlogintimeout()
Základní třídy a rozhraní Connection interface vytváření a vykonávání dotazů ResultSet interface výsledky dotazu
Základní příklad Class.forName("com.mysql.jdbc.Driver"); Connection con = DriverManager.getConnection( "jdbc:mysql://localhost/test", "",""); Statement stmt = con.createstatement(); ResultSet rs = stmt.executequery("select * FROM test"); while (rs.next()) { // zpracování výsledků po řádcích } stmt.close(); con.close();
Přístup k výsledkům podbné reflection API getstring(), getint(),... pracuje se nad aktuálním řádkem identifikace sloupce pomocí jména pořadí ResultSet rs = stmt.executequery("select ID, NAME FROM TEST"); while (rs.next()) { int id = rs.getint("id"); String s = rs.getstring("string"); System.out.println(id + " " + s); }
Přístup k výsledkům ResultSet.next() musí být zavoláno i na první řádek getstring() lze volat na všechny typy nelze na nové SQL3 typy automatická konverze na String
Dotazy Connection.createStatement() vytvoření dotazu ("prázdného") Statement.executeQuery("...") pro dotazy vracející vysledky (SELECT) výsledky přes ResultSet Statement.executeUpdate("...") pro dotazy nevracející výsledky UPDATE CREATE TABLE
PreparedStatement PreparedStatement interface dědí od Statement předpřipravený dotaz s parametry vyplní se před použitím metody settype(int index, type v) clearparameters() PreparedStatement pstmt = con.preparestatement("update EMPLOYEES SET SALARY =? WHERE ID =?"); pstmt.setbigdecimal(1, 153833.00) pstmt.setint(2, 110592)
Transakce implicitně auto-commit mód commit se provede po každé změně auto-commit lze zrušit con.setautocommit(false); // // posloupnost změn // con.commit(); // nebo con.rollback() con.setautocommit(true);
Callable Statements pro přístup k uloženým procedurám dědí od PreparedStatement nastavení parametrů settype(int index, type v) návratový typ nutno zaregistrovat registeroutparameter(int index, int sqltype) formát a) {?= call <procedure-name>[<arg1>,<arg2>, ]} b) {call <procedure-name>[<arg1>,<arg2>, ]} CallableStatement cs = con.preparecall("{call SHOW_SUPPLIERS}"); ResultSet rs = cs.executequery();
Ošetření chyb SQLException a její potomci String getsqlstate() definováno X/Open int geterrorcode() specifický pro konkrétní databázi varování (warnings) SQLWarning není to výjimka nutno explicitně testovat Statement.getWarnings() SQLWarning.getNextWarning()
Batch update zpracování více dotazů najednou Statement.addBatch(String sql) přidá dotaz do dávky int[] Statement.executeBatch(); provede dávku vrací počet ovlivněných řádků pro každý dotaz v dávce
Updatable ResultSet implicitní ResultSet nelze měnit, lze se pohybovat pouze vpřed lze změnit při vytváření Statementu Statement stmt = con.createstatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executequery("select..."); výsledný ResultSet lze měnit, lze se v něm volně pohybovat, nejsou v něm vidět změny od ostatních uživatelů
Java DB http://www.oracle.com/technetwork/java/javadb/ distribuovaná s Java 7 a 8 není v Java 9+ Oraclem podporovaná distribuce databáze Apache Derby http://db.apache.org/derby/ kompletně v Javě lze používat samostatně jako server uvnitř jiné aplikace snaha o malou spotřebu paměti (~ 2MB) existují i jiné databáze napsané v Javě
Objektové databáze ne-relační databáze ukládaní a vyhledávání objektů vlastní přístup bez JDBC NeoDatis db4o příklad pro NeoDatis Sport sport = new Sport("volley-ball"); ODB odb = ODBFactory.open("test.neodatis"); odb.store(sport); Objects<Player> players = odb.getobjects(player.class); odb.close(); moc se nepoužívají
ORM problém s OO databázemi jednoduché na použití nepříliš výkonné, nepříliš podporované,... řešení ORM (object-relational mapping) vrstva mapující relační databázi na objekty zjednodušeně třída ~ schéma tabulku objekt ~ řádek v tabulce JDBC se typicky používá uvnitř automaticky Hibernate http://hibernate.org/ nejpoužívanější ORM pro Javu implementace i pro další technologie
Dokumentové databáze ukládání dokumentů semi-structured date MongoDB https://www.mongodb.com/ dokumenty ~ JSON MongoClient mongoclient = new MongoClient(); MongoDatabase database = mongoclient.getdatabase("mydb"); MongoCollection<Document> collection = database.getcollection("test"); Document doc = new Document("name", "MongoDB").append("type", "database").append("count", 1).append("versions", Arrays.asList("v3.2", "v3.0", "v2.6")).append("info", new Document("x", 203).append("y", 102)); collection.insertone(doc);
JAVA Hibernate
Architektura image source: http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/hibernate_user_guide.html
Základní API Session propojení mezi DB a aplikací schovává v sobě spojení do DB JDBC connection spravuje objekty obsahuje cache objektů SessionFactory tvůrce session obsahuje mapovaní mezi objekty a DB může obsahovat cache objektů persistentní objekty obyčejné Java objekty POJO/JavaBeans měly by dodržovat pravidla pro JavaBeans ale není to nutné
Použití zjednodušeně vytvořit konfiguraci XML vytvořit třídy Java vytvořit mapovaní XML nebo Java anotace
Konfigurace XML soubor definuje připojení do DB typ (dialekt) DB kde je mapovaní <hibernate-configuration> <session-factory> <property name="connection.driver_class">org.h2.driver</property> <property name="connection.url">jdbc:h2:mem:db1;db_close_delay=-1;mvcc=true</property> <property name="connection.username">sa</property> <property name="connection.password"/> <property name="connection.pool_size">1</property> <property name="dialect">org.hibernate.dialect.h2dialect</property> <property name="cache.provider_class">org.hibernate.cache.nocacheprovider</property> <property name="show_sql">true</property> <property name="hbm2ddl.auto">create</property> <mapping resource="org/hibernate/tutorial/hbm/event.hbm.xml"/> </session-factory> </hibernate-configuration>
Třídy pro persistentní data POJO měly by dodržovat pravidla pro JavaBeans není nutné je potřeba konstruktor bez parametrů jeho viditelnost je libovolná public class Event { private Long id; private String title; private Date date; public Event() {} public Event(String title, Date date) { this.title = title; this.date = date; } public Long getid() { return id; } private void setid(long id) { this.id = id; } public Date getdate() { return date; } public void setdate(date date) { this.date = date; } public String gettitle() { return title; } public void settitle(string title) { this.title = title; } }
Mapování XML soubor mapování atributů třídy na sloupce definuje se jméno typ není nutný, pokud je zřejmý Hibernate typy nejsou to ani Java ani SQL typy jsou to převodníky mezi Java a SQL typy sloupec není nutný pokud je stejný jako jméno <hibernate-mapping package="org.hibernate.tutorial.hbm"> <class name="event" table="events"> <id name="id" column="event_id"> <generator class="increment"/> </id> <property name="date" type="timestamp" column="event_date"/> <property name="title"/> </class> </hibernate-mapping>
Mapování @Entity @Table( name = "EVENTS" ) public class Event { private Long id; private String title; private Date date; public Event() { } public Event(String title, Date date) { this.title = title; this.date = date; } mapování lze i pomocí anotací v konfiguraci je pak v mapování přímo odkaz na třídu @Id @GeneratedValue(generator="increment") @GenericGenerator(name="increment", strategy = "increment") public Long getid() { return id; } private void setid(long id) { this.id = id; } @Temporal(TemporalType.TIMESTAMP) @Column(name = "EVENT_DATE") public Date getdate() { return date; } public void setdate(date date) { this.date = date; } } public String gettitle() { return title; } public void settitle(string title) { this.title = title; }
Používání SessionFactory sessionfactory = new Configuration().configure().buildSessionFactory(); Session session = sessionfactory.opensession(); session.begintransaction(); session.save(new Event("Our very first event!", new Date())); session.save(new Event("A follow up event", new Date())); session.gettransaction().commit(); session.close(); List result = session.createquery( "from Event" ).list();
Stavy objektů Transient vytvořený objekt (new) ale ještě neasociovaný s Hibernate session Persistent objekt asociovaný se session vytvořený a pak uloženy nebo načtený Detached perzistentní objekt jehož session byla skončena lze asociovat s novou session
Používání objektů načítání sess.load( Event.class, new Long(id) ); při neexistenci vyhazuje výjimku nemusí nutně sahat ihned do DB sess.get( Event.class, new Long(id) ); při neexistenci vrací null dotazování sess.createquery(...).list() modifikování objektů Event e = sess.load( Event.class, new Long(69) ); e.set... sess.flush();
Používání objektů modifikace odpojených objektů Event e = sess.load( Event.class, new Long(69) ); e.set...... secondsess.update(e); mazání objektů sess.delete(e);
Dotazování HQL Hibernate query language obdoba SQL select foo from Foo foo, Bar bar where foo.startdate = bar.date lze používat i nativní SQL sess.createsqlquery("select * FROM CATS").list();
Hibernate... další součásti vytváření tříd podle tabulek podpora pro full-text vyhledávání verzování objektů validace objektů podpora JPA (Java Persistence API)...
JAVA Práce s XML
Přehled JAXP Java API for XML Processing čtení, zápis a transformaci XML SAX, DOM, XSLT podle W3C podporuje různé implementace referenční implementace součástí JDK lze použít jiné JDOM http://www.jdom.org/ zjednodušený DOM pro Javu JAXB Java Architecture for XML Binding mapování XML <=> Java objekty Elliotte Rusty Harold: Processing XML with Java http://www.cafeconleche.org/books/xmljava/ kniha volně ke stažení
JAXP přehled balíky javax.xml.parsers org.w3c.dom org.xml.sax javax.xml.transform SAX (Simple API for XML) průchod přes XML dokument element po elementu na každém elementu něco provést rychlé, nenáročné na paměť složitější na použití DOM postaví z dokumentu strom v paměti jednoduché na použití pomalé, náročné na paměť 37
SAX 38
DOM 39
DOM: použití DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newdocumentbuilder(); // vytvoří celý strom v paměti Document document = builder.parse("file.xml"); Element root = document.getdocumentelement(); NodeList nl = root.getchildnodes(); for (int i=0; i<nl.length(); i++) { Node n = nl.item(i);... } 40
SAX: použití class MyHandler extends DefaultHandler { void startdocument() {... } void enddocument() {... } void startelement(...) {... }... } SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxparser = factory.newsaxparser(); saxparser.parse("file.xml", new MyHandler() ); 41
Implementace existují různé implementace JAXP DocumentBuilderFactory.newInstance() i SAXParserFactory.newInstance() uvnitř používají ServiceLoader varianta newinstance(string factoryclassname, ClassLoader classloader) hledá danou třídu 42
JDOM Přehled http://www.jdom.org/ API pro XML přímo pro Javu používá std. API z Javy (kolekce,...) jednoduché na používání rychlé "light-weight" 43
Použití SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(filename); Element root = doc.getrootelement(); List children = current.getchildren(); Iterator iterator = children.iterator(); while (iterator.hasnext()) { Element child = (Element) iterator.next();... } 44
JAXB přehled automatické mapovaní mezi XML dokumenty a Java objekty princip Java třídy a odpovídající XML schema lze vygenerovat třídy ze schematu i obraceně použití vytvoření Java objektů z XML (unmarshaling) práce s Java objekty uložení Java objektů do XML (marshaling) deprecated od Java 9 45
JAXB příklad <?xml version="1.0" encoding="utf-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/xmlschema" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" jxb:version="2.0"> <xsd:element name="greetings" type="greetinglisttype"/> <xsd:complextype name="greetinglisttype"> <xsd:sequence> <xsd:element name="greeting" type="greetingtype" maxoccurs="unbounded"/> </xsd:sequence> </xsd:complextype> <xsd:complextype name="greetingtype"> <xsd:sequence> <xsd:element name="text" type="xsd:string"/> </xsd:sequence> <xsd:attribute name="language" type="xsd:language"/> </xsd:complextype> </xsd:schema> 46
JAXB příklad vygenerování tříd xjc -p hello hello.xsd 47
JAXB příklad public class Hello { private ObjectFactory of; private GreetingListType grlist; public Hello(){ of = new ObjectFactory(); grlist = of.creategreetinglisttype(); } public void make( String t, String l ){ GreetingType g = of.creategreetingtype(); g.settext( t ); g.setlanguage( l ); grlist.getgreeting().add( g ); } public void marshal() { try { JAXBElement gl = of.creategreetings( grlist ); JAXBContext jc = JAXBContext.newInstance( "hello" ); Marshaller m = jc.createmarshaller(); m.marshal( gl, System.out ); } catch( JAXBException jbe ){ } } Java, } letní semestr 2018 48
JAXB příklad Hello h = new Hello(); h.make( "Bonjour, madame", "fr" ); h.make( "Hey, you", "en" ); h.marshal(); <?xml version="1.0" encoding="utf-8" standalone="yes"?> <Greetings> <Greeting language="fr"> <Text>Bonjour, madame</text> </Greeting> <Greeting language="en"> <Text>Hey, you</text> </Greeting> </Greetings> 49
JAVA Scripting API
Přehled podpora skriptovacích jazyku přímo z Javy integrace skriptů do Java programu volání skriptů používání Java objektů ze skriptu a obraceně JSR 223 Scripting for the Java TM Platform od Java 6 přímo součástí JDK součástí JDK je JavaScript engine Java 6-7 Mozilla Rhino engine Java 8 Nashorn engine implementace JavaScript jazyka v Javě implementuje rozhraní JSR 223 existuje mnoho implementací pro další jazyky stačí dát JAR balík na CLASSPATH
Proč jednotné rozhraní pro všechny skriptovací jazyky dříve si každá implementace řešila rozhraní po svém snadné požívání skr. jazyků proměnné bez typů automatické konverze programy není nutno kompilovat existence shelů použití složitější konfigurační soubory rozhraní pro administrátora aplikace rozšiřování aplikace (pluginy) skriptování v aplikaci obdoba jako JS v prohlížeči, VBScript v office,...
Použití balíček javax.scripting ScriptEngineManager základní třída nalezení a získání instance skript. enginu základní použití instance ScriptEngineManageru nalezení požadovaného enginu spuštění skriptu pomocí metody eval()
Hello world public class Hello { public static void main(string[] args) { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getenginebyname("javascript"); //ScriptEngine engine = manager.getenginebyextension("js"); //ScriptEngine engine = manager.getenginebymimetype("application/javascript"); try { engine.eval("println( \"Hello World!\");" ); System.out.println( engine.eval( " 'Hello World again!' ")); } catch(scriptexception e) {... } } }
Přehled funkčnosti skript řetězec nebo znakový stream (reader) vyhodnocení přes ScriptEngine.eval() interface Compilable jeho implementace volitelná otestovat instanceof Compilable kompilace skriptu do byte-code interface Invocable jeho implementace volitelná otestovat instanceof Invocable volání metod a funkcí ze skriptů Bindings, ScriptContext prostředí pro vykonávání skriptů mapování proměnných sdílených mezi Javou a skriptem
Získání enginu (1) ScriptEngineManager.getEngineFactories() seznam všech ScriptEngineFactory for (ScriptEngineFactory factory : enginemanager.getenginefactories()) { System.out.println("Engine name: " + factory.getenginename()); System.out.println("Engine version: " + factory.getengineversion()); System.out.println("Language name: " + factory.getlanguagename()); System.out.println("Language version: " + factory.getlanguageversion()); System.out.println("Engine names:"); for (String name : factory.getnames()) { System.out.println(" " + name); } System.out.println("Engine MIME-types:"); for (String mime : factory.getmimetypes()) { System.out.println(" " + mime); } }
Získání enginu (2) ScriptEngineFactory.getEngine() nebo přímo ScriptEngineManager.getEngineByName() ScriptEngineManager.getEngineByExtension() ScriptEngineManager.getEngineByMimeType()
Skripty vykonání skriptu Object ScriptEngine.eval( String s,... Object ScriptEngine.eval( Reader r, předávání proměnných (základní varianta) void ScriptEngine.put(String name, Object value) Object ScriptEngine.get(String name) POZOR na konverze typů!
Předávání proměnných interface Bindings extends Map<String,Object> základní implementace SimpleBindings interface ScriptContext prostředí, ve kterém se skripty vykonávají základní implementace SimpleScriptContext obsahuje scopes scope = Binding speciální scopes ENGINE_SCOPE lokální pro ScriptEngine GLOBAL_SCOPE globální pro EngineManager getattribute(..) / setattribute(..) odpovídají getbindings(..).get / put lze nastavit standardní Reader a Writery (vstup a výstup) pro skript
Předávání proměnných zdroj obrázku: http://www.javaworld.com/javaworld/jw-04-2006/jw-0424-scripting.html
Volání funkcí/metod interface Invocable volitelná funkčnost, je třeba testovat (instanceof) poskytuje volání funkcí skriptu z Java kódu volání metod objektů skriptu z Java kódu, pokud je skriptovací jazyk objektový implementace Java interface funkcemi (metodami) skriptu ScriptEngine engine = manager.getenginebyname("javascript"); Invocable inv = (Invocable) engine; engine.eval("function run() { println( 'funkce run'); };"); Runnable r = inv.getinterface(runnable.class); (new Thread(r)).start(); engine.eval("var runobj = { run: function() { println('metoda run'); } };"); o = engine.get("runobj"); r = inv.getinterface(o, Runnable.class); (new Thread(r)).start();
JavaScript engine v JDK (1) některé funkce odstraněny (nebo nahrazeny) převážně z důvodů bezpečnosti vestavěné funkce pro import Java balíčků importpackage(), importclass() balíčky přístupné přes Packages.JmenoBalíčku, pro nejpoužívanější balíčky jsou definované zkratky (proměnné): java (ekvivalentní Packages.java), org, com,.. java.lang není importován automaticky (možné konflikty objektů Object, Math,..) v Java 8 nutno nejdříve použít load("nashorn:mozilla_compat.js"); objekt JavaImporter pro ukrytí importovaných prvků do proměnné (předchází konfliktům) var imp = new JavaImporter( java.lang, java.io);
JavaScript engine v JDK (2) Java objekty v js vytváří se stejně jako v Javě var obj = new Trida(...) Javovské pole v js vytvoříme přes Java Reflection var pole = java.lang.reflect.array.newinstance(..) dále pracujeme běžně: pole[i], pole.length, var a = java.lang.reflect.array.newinstance( java.lang.string, 5); a[0] = "Hello" anonymní třídy anonymní implementace Java rozhraní var r = new java.lang.runnable() { run: function() { println( "running..."); } }; var th = null; th = new java.lang.thread( r); Java, letní semestr th.start(); 2018
JavaScript engine v JDK (3) anonymní třídy (pokrač.) autokonverze funkce na rozhraní s jednou metodou function func() { print("i am func!"); }; th = new java.lang.thread( func); th.start();
JavaScript engine v JDK (4) přetížené Java metody připomenutí overoading se děje při překladu (javac) při předání JavaScriptových proměnných Java metodám vybere script engine správnou variantu výběr můžeme ale ovlivnit objekt[ název_metody(typy parametrů) ](parametry) pozor! řetězec bez mezer!
Další enginy existuje velké množství hotových enginů awk, Haskell, Python, Scheme, XPath, XSLT, PHP,... použití stáhnout JAR dát JAR na CLASSPATH vytvoření vlastního enginu implementace API nutno implementovat alespoň ScriptEngineFactory ScriptEngine zabalení do JAR přidat soubor META-INF/services/javax.script.ScriptEngineFactory ScriptEngineManager používá ServiceLoader
Java, letní semestr Verze prezentace 2018 AJ07.cz.2018.01 Tato prezentace podléhá licenci Creative Commons Uveďte autora-neužívejte komerčně 4.0 Mezinárodní License. 67