<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4795010795101372767</id><updated>2011-11-28T01:43:33.368+01:00</updated><category term='JUNG'/><category term='Hibernate'/><category term='hibernate cascade'/><category term='Hibernate reprezentacja dziedziczenia polimorfizm'/><category term='hibernate pierwsza aplikacja'/><category term='HibernateDaoSupport'/><category term='generowanie grafu'/><category term='Spring'/><category term='c3p0'/><category term='System.setProperty'/><category term='Spring Security'/><category term='Eclipse'/><title type='text'>Java, Hibernate, Spring</title><subtitle type='html'>Blog programisty.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://marekel.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://marekel.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Marek Lewandowski</name><uri>http://www.blogger.com/profile/12462254017661407439</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://4.bp.blogspot.com/_tDsMaYJzwyc/SYmBdOzwV2I/AAAAAAAAGzE/jFalxrPjviM/S220/avatar.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>7</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4795010795101372767.post-7732417952074164931</id><published>2010-02-23T16:00:00.003+01:00</published><updated>2010-02-23T16:21:41.675+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Spring Security'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Debug w Eclipse jak migacz - raz działa raz nie działa :)</title><content type='html'>Cały dzień męczyłem ciekawy problem. Debugging w Eclipse przestał działać (działał do połowy metody) po podłączeniu do aplikcji Spring Security...&lt;br /&gt;Rozwiązanie?&lt;br&gt;&lt;br /&gt;&lt;a href="http://java.sun.com/javase/6/webnotes/6u15.html"&gt;http://java.sun.com/javase/6/webnotes/6u15.html&lt;/a&gt;&lt;br&gt;&lt;br /&gt;&lt;a href="http://stackoverflow.com/questions/1370868/eclipse-debugger-doesnt-stop-at-breakpoint"&gt;http://stackoverflow.com/questions/1370868/eclipse-debugger-doesnt-stop-at-breakpoint&lt;/a&gt;&lt;br&gt;&lt;br /&gt;Bug w JDK... Aż się nie chce wierzyć ;) Przejście z wersji 14 na wersję 17 rozwiązała problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4795010795101372767-7732417952074164931?l=marekel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marekel.blogspot.com/feeds/7732417952074164931/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://marekel.blogspot.com/2010/02/debug-w-eclipse-jak-migacz-raz-dziaa.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/7732417952074164931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/7732417952074164931'/><link rel='alternate' type='text/html' href='http://marekel.blogspot.com/2010/02/debug-w-eclipse-jak-migacz-raz-dziaa.html' title='Debug w Eclipse jak migacz - raz działa raz nie działa :)'/><author><name>Marek Lewandowski</name><uri>http://www.blogger.com/profile/12462254017661407439</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://4.bp.blogspot.com/_tDsMaYJzwyc/SYmBdOzwV2I/AAAAAAAAGzE/jFalxrPjviM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4795010795101372767.post-4370048510441197481</id><published>2009-09-18T15:54:00.002+02:00</published><updated>2009-09-18T15:55:49.448+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate cascade'/><title type='text'>Kaskadowość w hibernate</title><content type='html'>Postaram się przeanalizować dosyć nieintuicyjną (według mnie) kwestię kaskadowego zapisywania relacji w Hibernate. Posłużę się wykorzystywanym już wcześniej przykładem dwóch tabel: Produkt i Kategoria.&lt;br /&gt;&lt;br /&gt;Na początek: brak kaskadowości, mapowanie jednostronne.&lt;br /&gt;Mapowania i klasy POJO:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;  &lt;br /&gt;   &lt;br /&gt;&amp;lt;!DOCTYPE hibernate-mapping PUBLIC  &lt;br /&gt;    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   &lt;br /&gt;    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;class name="Produkt" table="produkt"&amp;gt;&lt;br /&gt;  &amp;lt;id name="id" unsaved-value="null" column="produkt_id"&amp;gt;&lt;br /&gt;   &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;    &amp;lt;param name="sequence"&amp;gt;prod_seq&amp;lt;/param&amp;gt;&lt;br /&gt;   &amp;lt;/generator&amp;gt;&lt;br /&gt;  &amp;lt;/id&amp;gt;&lt;br /&gt;  &amp;lt;property name="name" /&amp;gt;&lt;br /&gt;  &amp;lt;property name="value" /&amp;gt;&lt;br /&gt; &amp;lt;/class&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;  &lt;br /&gt;   &lt;br /&gt;&amp;lt;!DOCTYPE hibernate-mapping PUBLIC  &lt;br /&gt;    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   &lt;br /&gt;    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;class name="Kategoria" table="kategoria"&amp;gt;&lt;br /&gt;  &amp;lt;id name="id" unsaved-value="null" column="kategory_id"&amp;gt;&lt;br /&gt;   &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;    &amp;lt;param name="sequence"&amp;gt;kat_seq&amp;lt;/param&amp;gt;&lt;br /&gt;   &amp;lt;/generator&amp;gt;&lt;br /&gt;  &amp;lt;/id&amp;gt;&lt;br /&gt;  &amp;lt;property name="name" /&amp;gt;&lt;br /&gt;  &amp;lt;property name="type" /&amp;gt;&lt;br /&gt;  &amp;lt;property name="description" /&amp;gt;&lt;br /&gt;  &amp;lt;set name="products" lazy="true" inverse="false" cascade="none"&amp;gt;&lt;br /&gt;   &amp;lt;key column="kategory_id" /&amp;gt;&lt;br /&gt;   &amp;lt;one-to-many class="Produkt" /&amp;gt;&lt;br /&gt;  &amp;lt;/set&amp;gt;&lt;br /&gt; &amp;lt;/class&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package main;&lt;br /&gt;&lt;br /&gt;public class Produkt {&lt;br /&gt; Integer id;&lt;br /&gt; String name;&lt;br /&gt; Integer value;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt; public Integer getId() {&lt;br /&gt;  return id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setId(Integer id) {&lt;br /&gt;  this.id = id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getName() {&lt;br /&gt;  return name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setName(String name) {&lt;br /&gt;  this.name = name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Integer getValue() {&lt;br /&gt;  return value;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setValue(Integer value) {&lt;br /&gt;  this.value = value;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package main;&lt;br /&gt;&lt;br /&gt;import java.util.HashSet;&lt;br /&gt;import java.util.Set;&lt;br /&gt;&lt;br /&gt;public class Kategoria {&lt;br /&gt; Integer id;&lt;br /&gt; String name;&lt;br /&gt; String type;&lt;br /&gt; String description;&lt;br /&gt; Set&amp;lt;Produkt&amp;gt; products = new HashSet&amp;lt;Produkt&amp;gt;();&lt;br /&gt;&lt;br /&gt; public Integer getId() {&lt;br /&gt;  return id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setId(Integer id) {&lt;br /&gt;  this.id = id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getName() {&lt;br /&gt;  return name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setName(String name) {&lt;br /&gt;  this.name = name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getType() {&lt;br /&gt;  return type;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setType(String type) {&lt;br /&gt;  this.type = type;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getDescription() {&lt;br /&gt;  return description;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setDescription(String description) {&lt;br /&gt;  this.description = description;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Set&amp;lt;Produkt&amp;gt; getProducts() {&lt;br /&gt;  return products;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setProducts(Set&amp;lt;Produkt&amp;gt; products) {&lt;br /&gt;  this.products = products;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Zapisanie do bazy danych kategorii i produktu wygląda następująco:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package main;&lt;br /&gt;&lt;br /&gt;import org.hibernate.Session;&lt;br /&gt;import org.hibernate.SessionFactory;&lt;br /&gt;import org.hibernate.cfg.Configuration;&lt;br /&gt;&lt;br /&gt;public class Main {&lt;br /&gt; public static void main(String[] args) {&lt;br /&gt;  Session session = null;&lt;br /&gt;  SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();&lt;br /&gt;  session = sessionFactory.openSession();&lt;br /&gt;  &lt;br /&gt;  Kategoria kat = new Kategoria();&lt;br /&gt;  Produkt prod1 = new Produkt();&lt;br /&gt;  Produkt prod2 = new Produkt();&lt;br /&gt;  kat.setName("kat");&lt;br /&gt;  prod1.setName("prod1");&lt;br /&gt;  prod2.setName("prod2");&lt;br /&gt;  kat.getProducts().add(prod1);&lt;br /&gt;  kat.getProducts().add(prod2);&lt;br /&gt;  session.beginTransaction();&lt;br /&gt;  session.save(prod1);&lt;br /&gt;  session.save(prod2);&lt;br /&gt;  session.save(kat);&lt;br /&gt;  session.flush();&lt;br /&gt;  session.getTransaction().commit();&lt;br /&gt;  session.close();&lt;br /&gt;  System.out.println("zapisane!");&lt;br /&gt;  session = sessionFactory.openSession();&lt;br /&gt;  session.beginTransaction();&lt;br /&gt;  System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());&lt;br /&gt;  System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());&lt;br /&gt;  session.clear();&lt;br /&gt;  session.delete(prod1);&lt;br /&gt;  session.flush();&lt;br /&gt;  session.getTransaction().commit();&lt;br /&gt;  session.close();&lt;br /&gt;  System.out.println("produkt usuniety");&lt;br /&gt;  session = sessionFactory.openSession();&lt;br /&gt;  session.beginTransaction();&lt;br /&gt;  System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());&lt;br /&gt;  System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());&lt;br /&gt;  session.clear();&lt;br /&gt;  session.delete(kat);&lt;br /&gt;  session.flush();&lt;br /&gt;  session.getTransaction().commit();&lt;br /&gt;  session.close();&lt;br /&gt;  System.out.println("kategoria usunieta");&lt;br /&gt;  session = sessionFactory.openSession();&lt;br /&gt;  session.beginTransaction();&lt;br /&gt;  System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());&lt;br /&gt;  System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());&lt;br /&gt;  System.out.println("end");&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Bardzo ważne jest, aby zapisać zarówno produkt jak i kategorię. Jeśli tego nie zrobimy, pojawi się błąd: exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: main.Produkt. Kolejność zapisywania nie jest istotna. &lt;br /&gt;W kodzie musiałem wyczyścić sesję (session.clear()), żeby uniknąć błędu: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session. &lt;br /&gt;Wynikiem działania programiku jest:&lt;br /&gt;zapisane!&lt;br /&gt;Kategorie: 1&lt;br /&gt;Produkty: 2&lt;br /&gt;produkt usuniety&lt;br /&gt;Kategorie: 1&lt;br /&gt;Produkty: 1&lt;br /&gt;kategoria usunieta&lt;br /&gt;Kategorie: 0&lt;br /&gt;Produkty: 1&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Niby ok, ale dlaczego istnieje produkt bez kategorii? Jeśli spojrzymy do bazy danych, to faktycznie zobaczymy, że w tabeli Produkty istnieje wpis "prod2" z pustą wartością klucza obcego kategory_id. Trochę to nieintuicyjne. Może można zrobić tak, że obiekty zależne (produkty) zapisywane i usuwane są razem z obiektem nadrzędnym (kategorią)? Oczywiście, że można. Trzeba się tylko trochę namęczyć:&lt;br /&gt;&lt;br /&gt;Mapowania:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;  &lt;br /&gt;   &lt;br /&gt;&amp;lt;!DOCTYPE hibernate-mapping PUBLIC  &lt;br /&gt;    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   &lt;br /&gt;    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;class name="Kategoria" table="kategoria"&amp;gt;&lt;br /&gt;  &amp;lt;id name="id" unsaved-value="null" column="kategory_id"&amp;gt;&lt;br /&gt;   &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;    &amp;lt;param name="sequence"&amp;gt;kat_seq&amp;lt;/param&amp;gt;&lt;br /&gt;   &amp;lt;/generator&amp;gt;&lt;br /&gt;  &amp;lt;/id&amp;gt;&lt;br /&gt;  &amp;lt;property name="name" /&amp;gt;&lt;br /&gt;  &amp;lt;property name="type" /&amp;gt;&lt;br /&gt;  &amp;lt;property name="description" /&amp;gt;&lt;br /&gt;  &amp;lt;set name="products" lazy="true" inverse="true" cascade="all"&amp;gt;&lt;br /&gt;   &amp;lt;key column="kategory_id" /&amp;gt;&lt;br /&gt;   &amp;lt;one-to-many class="Produkt"/&amp;gt;&lt;br /&gt;  &amp;lt;/set&amp;gt;&lt;br /&gt; &amp;lt;/class&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;  &lt;br /&gt;   &lt;br /&gt;&amp;lt;!DOCTYPE hibernate-mapping PUBLIC  &lt;br /&gt;    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   &lt;br /&gt;    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;class name="Produkt" table="produkt"&amp;gt;&lt;br /&gt;  &amp;lt;id name="id" unsaved-value="null" column="produkt_id"&amp;gt;&lt;br /&gt;   &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;    &amp;lt;param name="sequence"&amp;gt;prod_seq&amp;lt;/param&amp;gt;&lt;br /&gt;   &amp;lt;/generator&amp;gt;&lt;br /&gt;  &amp;lt;/id&amp;gt;&lt;br /&gt;  &amp;lt;property name="name" /&amp;gt;&lt;br /&gt;  &amp;lt;property name="value" /&amp;gt;&lt;br /&gt;  &amp;lt;many-to-one name="kategoria" class="Kategoria" not-null="true" column="kategory_id"/&amp;gt;&lt;br /&gt; &amp;lt;/class&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Klasy POJO:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package main;&lt;br /&gt;&lt;br /&gt;import java.util.HashSet;&lt;br /&gt;import java.util.Set;&lt;br /&gt;&lt;br /&gt;public class Kategoria {&lt;br /&gt; Integer id;&lt;br /&gt; String name;&lt;br /&gt; String type;&lt;br /&gt; String description;&lt;br /&gt; Set&amp;lt;Produkt&amp;gt; products = new HashSet&amp;lt;Produkt&amp;gt;();&lt;br /&gt;&lt;br /&gt; public Integer getId() {&lt;br /&gt;  return id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setId(Integer id) {&lt;br /&gt;  this.id = id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getName() {&lt;br /&gt;  return name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setName(String name) {&lt;br /&gt;  this.name = name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getType() {&lt;br /&gt;  return type;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setType(String type) {&lt;br /&gt;  this.type = type;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getDescription() {&lt;br /&gt;  return description;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setDescription(String description) {&lt;br /&gt;  this.description = description;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Set&amp;lt;Produkt&amp;gt; getProducts() {&lt;br /&gt;  return products;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setProducts(Set&amp;lt;Produkt&amp;gt; products) {&lt;br /&gt;  this.products = products;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public void addProduct(Produkt product) {&lt;br /&gt;  if (product.getKategoria()==null)&lt;br /&gt;   product.setKategoria(this);&lt;br /&gt;  products.add(product);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;package main;&lt;br /&gt;&lt;br /&gt;public class Produkt {&lt;br /&gt; Integer id;&lt;br /&gt; String name;&lt;br /&gt; Integer value;&lt;br /&gt; Kategoria kategoria;&lt;br /&gt; &lt;br /&gt; public Kategoria getKategoria() {&lt;br /&gt;  return kategoria;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public void setKategoria(Kategoria kategoria) {&lt;br /&gt;  this.kategoria=kategoria;&lt;br /&gt;  this.kategoria.getProducts().add(this);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public Integer getId() {&lt;br /&gt;  return id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setId(Integer id) {&lt;br /&gt;  this.id = id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getName() {&lt;br /&gt;  return name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setName(String name) {&lt;br /&gt;  this.name = name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Integer getValue() {&lt;br /&gt;  return value;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setValue(Integer value) {&lt;br /&gt;  this.value = value;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;W mapowaniach i POJO kluczowe są opcje "cascade", "inverse" oraz settery (setKatgoria, setProdukt, addProdukt) - bez nich nie proste operacje na javovych obiektach nie miałyby bezpośredniego przełożenia na sytuację w bazie danych.&lt;br /&gt;&lt;br /&gt;No i main:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;package main;&lt;br /&gt;&lt;br /&gt;import org.hibernate.Session;&lt;br /&gt;import org.hibernate.SessionFactory;&lt;br /&gt;import org.hibernate.cfg.Configuration;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class Main {&lt;br /&gt;&lt;br /&gt; public static void main(String[] args) {&lt;br /&gt;&lt;br /&gt;  Session session = null;&lt;br /&gt;  SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();&lt;br /&gt;  session = sessionFactory.openSession();&lt;br /&gt;  &lt;br /&gt;  session.beginTransaction();&lt;br /&gt;  &lt;br /&gt;  Kategoria kat = new Kategoria();&lt;br /&gt;  Produkt prod1 = new Produkt();&lt;br /&gt;  Produkt prod2 = new Produkt();&lt;br /&gt;  prod1.setName("prod1");&lt;br /&gt;  prod2.setName("prod2");&lt;br /&gt;  kat.addProduct(prod1);&lt;br /&gt;  prod2.setKategoria(kat);&lt;br /&gt;  &lt;br /&gt;  session.save(kat);&lt;br /&gt;  session.flush();&lt;br /&gt;  session.getTransaction().commit();&lt;br /&gt;  session.close();&lt;br /&gt;  System.out.println("zapisane!");&lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  session = sessionFactory.openSession();&lt;br /&gt;  session.beginTransaction();&lt;br /&gt;  System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());&lt;br /&gt;  System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());&lt;br /&gt;  session.clear();&lt;br /&gt;  session.delete(prod1);&lt;br /&gt;  kat.getProducts().remove(prod1);&lt;br /&gt;  session.flush();&lt;br /&gt;  session.getTransaction().commit();&lt;br /&gt;  session.close();&lt;br /&gt;  System.out.println("produkt usuniety");&lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  session = sessionFactory.openSession();&lt;br /&gt;  session.beginTransaction();&lt;br /&gt;  System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());&lt;br /&gt;  System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());&lt;br /&gt;  session.clear();&lt;br /&gt;  System.out.println("produkty: "+kat.getProducts().size());&lt;br /&gt;  session.delete(kat);&lt;br /&gt;  session.flush();&lt;br /&gt;  session.getTransaction().commit();&lt;br /&gt;  session.close();&lt;br /&gt;  System.out.println("kategoria usunieta");&lt;br /&gt;  session = sessionFactory.openSession();&lt;br /&gt;  session.beginTransaction();&lt;br /&gt;  System.out.println("Kategorie: "+session.createQuery("from Kategoria").list().size());&lt;br /&gt;  System.out.println("Produkty: "+session.createQuery("from Produkt").list().size());&lt;br /&gt;  System.out.println("end");&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Wynik działania programu:&lt;br /&gt;&lt;br /&gt;zapisane!&lt;br /&gt;Kategorie: 1&lt;br /&gt;Produkty: 2&lt;br /&gt;produkt usuniety&lt;br /&gt;Kategorie: 1&lt;br /&gt;Produkty: 1&lt;br /&gt;produkty: 1&lt;br /&gt;kategoria usunieta&lt;br /&gt;Kategorie: 0&lt;br /&gt;Produkty: 0&lt;br /&gt;end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4795010795101372767-4370048510441197481?l=marekel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marekel.blogspot.com/feeds/4370048510441197481/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://marekel.blogspot.com/2009/09/kaskadowosc-zapisu-w-hibernate.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/4370048510441197481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/4370048510441197481'/><link rel='alternate' type='text/html' href='http://marekel.blogspot.com/2009/09/kaskadowosc-zapisu-w-hibernate.html' title='Kaskadowość w hibernate'/><author><name>Marek Lewandowski</name><uri>http://www.blogger.com/profile/12462254017661407439</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://4.bp.blogspot.com/_tDsMaYJzwyc/SYmBdOzwV2I/AAAAAAAAGzE/jFalxrPjviM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4795010795101372767.post-1768010808992945377</id><published>2009-08-04T15:49:00.007+02:00</published><updated>2009-09-18T15:39:05.811+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c3p0'/><category scheme='http://www.blogger.com/atom/ns#' term='System.setProperty'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>System.setProperty() z wykorzystaniem Springa</title><content type='html'>Problem w jaki sposób wywołać System.setProperty ze Springa pojawił się, gdy po zdeployowaniu dwóch aplikacji na jednym serwerze, w logach jednej z nich pojawił się następujący wpis:&lt;br /&gt;&lt;br /&gt;"A C3P0Registry mbean is already registered. This probably means that an application using c3p0 was undeployed, but not all PooledDataSources were closed prior to undeployment. This may lead to resource leaks over time. Please take care to close all PooledDataSources."&lt;br /&gt;&lt;br /&gt;Na forum hibernate znalazłem informację, że trzeba w systemie ustawić zmienną:&lt;br /&gt;com.mchange.v2.c3p0.management.ManagementCoordinator=com.mchange.v2.c3p0.management.NullManagementCoordinator&lt;br /&gt;&lt;br /&gt;Niestety powyższe rozwiązanie nie wchodziło w rachubę (każdy z klientów musiałby zmodyfikować swój skrypt uruchamiający Tomcata). Jedyne sensowne rozwiązanie jakie przychodziło mi do głowy, to zmuszenie Springa do zadziałania.&lt;br /&gt;Trochę się naszukałem, aż w końcu znalazłem jedno (niepoprawne) rozwiązanie mojego problemu. Po zmianach i uproszczeniach uzyskałem działającego bean'a :)&lt;br /&gt;&lt;br /&gt;Oto on:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;bean id="sysprops" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"&amp;gt;&lt;br /&gt;    &amp;lt;property name="targetClass"&amp;gt; &lt;br /&gt;        &amp;lt;value&amp;gt;java.lang.System&amp;lt;/value&amp;gt;&lt;br /&gt;    &amp;lt;/property&amp;gt;&lt;br /&gt;    &amp;lt;property name="targetMethod"&amp;gt;&lt;br /&gt;        &amp;lt;value&amp;gt;setProperty&amp;lt;/value&amp;gt;&lt;br /&gt;    &amp;lt;/property&amp;gt;&lt;br /&gt;    &amp;lt;property name="arguments"&amp;gt;&lt;br /&gt;        &amp;lt;list&amp;gt;&lt;br /&gt;            &amp;lt;value&amp;gt;com.mchange.v2.c3p0.management.ManagementCoordinator&amp;lt;/value&amp;gt;&lt;br /&gt;            &amp;lt;value&amp;gt;com.mchange.v2.c3p0.management.NullManagementCoordinator&amp;lt;/value&amp;gt;&lt;br /&gt;        &amp;lt;/list&amp;gt;&lt;br /&gt;    &amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Gdyby kogoś interesowało, dlaczego taka a nie inna zmienna musiała być ustawiona, to zapraszam &lt;a href="https://forum.hibernate.org/viewtopic.php?f=1&amp;t=988562&amp;start=0" target=_blank&gt;na forum hibernate&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4795010795101372767-1768010808992945377?l=marekel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marekel.blogspot.com/feeds/1768010808992945377/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://marekel.blogspot.com/2009/08/systemsetproperty-z-wykorzystaniem.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/1768010808992945377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/1768010808992945377'/><link rel='alternate' type='text/html' href='http://marekel.blogspot.com/2009/08/systemsetproperty-z-wykorzystaniem.html' title='System.setProperty() z wykorzystaniem Springa'/><author><name>Marek Lewandowski</name><uri>http://www.blogger.com/profile/12462254017661407439</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://4.bp.blogspot.com/_tDsMaYJzwyc/SYmBdOzwV2I/AAAAAAAAGzE/jFalxrPjviM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4795010795101372767.post-8372198929211294247</id><published>2009-03-26T15:22:00.007+01:00</published><updated>2009-08-04T16:23:09.491+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate reprezentacja dziedziczenia polimorfizm'/><title type='text'>Hibernate - reprezentacja dziedziczenia</title><content type='html'>Pierwszy problem niedopasowania świata obiektowego i relacyjnego pojawia się podczas modelowania (mapowania) hierarchii klas. Dziedziczenie jest jednym z paradygmatów programowania obiektowego i zrezygnowanie z niego, z powodu relacyjności warstwy danych, byłoby uwstecznieniem. Używając Hibernate można odwzorowywać dziedziczenie na trzy sposoby:&lt;br /&gt;1. tabela na każdą klasę (table per concrete class)&lt;br /&gt;2. tabela na każdą hierarchię klas (table per class hierarchy)&lt;br /&gt;3. tabela na każdą podklasę (table per subclass)&lt;br /&gt;&lt;br /&gt;We wszystkich przypadkach będę wykonywał metodę:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public class Main {&lt;br /&gt;   public static void main(String[] args) {&lt;br /&gt;      Session session = null;&lt;br /&gt;      SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();&lt;br /&gt;      session = sessionFactory.openSession();&lt;br /&gt;      Subcategory1 cat = new Subcategory1();&lt;br /&gt;      cat.setName("sub1");&lt;br /&gt;      cat.setSize(1);  &lt;br /&gt;      Subcategory2 cat2 = new Subcategory2();&lt;br /&gt;      cat2.setName("sub2");&lt;br /&gt;      cat2.setVolume(2);&lt;br /&gt;      session.beginTransaction();&lt;br /&gt;      session.save(cat);&lt;br /&gt;      session.save(cat2);&lt;br /&gt;      session.flush();&lt;br /&gt;      session.getTransaction().commit();&lt;br /&gt;      session.close();&lt;br /&gt;      session = sessionFactory.openSession();&lt;br /&gt;      session.beginTransaction();&lt;br /&gt;      List&amp;lt;Category&amp;gt; cats = session.createQuery("from Subcategory1").list();&lt;br /&gt;      System.out.println(cats.size());&lt;br /&gt;      cats = session.createQuery("from Subcategory2").list();&lt;br /&gt;      System.out.println(cats.size());&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class Category {&lt;br /&gt;   Integer id;&lt;br /&gt;   String name;&lt;br /&gt;   public Integer getId() {&lt;br /&gt;      return id;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void setId(Integer id) {&lt;br /&gt;      this.id = id;&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   public String getName() {&lt;br /&gt;      return name;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void setName(String name) {&lt;br /&gt;      this.name = name;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Subcategory1 extends Category {&lt;br /&gt;   Integer id;&lt;br /&gt;   Integer size;&lt;br /&gt;   public Integer getId() {&lt;br /&gt;      return id;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void setId(Integer id) {&lt;br /&gt;      this.id = id;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public Integer getSize() {&lt;br /&gt;      return size;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void setSize(Integer size) {&lt;br /&gt;      this.size = size;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Subcategory2 extends Category {&lt;br /&gt;   Integer id;&lt;br /&gt;   Integer volume;&lt;br /&gt;&lt;br /&gt;   public Integer getId() {&lt;br /&gt;      return id;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void setId(Integer id) {&lt;br /&gt;      this.id = id;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public Integer getVolume() {&lt;br /&gt;      return volume;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void setVolume(Integer volume) {&lt;br /&gt;      this.volume = volume;&lt;br /&gt;   }&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ad 1.&lt;br /&gt;Podejście najprostsze - baza danych w ogóle nie zdaje sobie sprawy z dziedziczenia.&lt;br /&gt;&lt;br /&gt;Tworzę DWA pliki mapowań: Subcategory1.hbm.xml, Subcategory2.hbm.xml:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!DOCTYPE hibernate-mapping PUBLIC&lt;br /&gt;    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" &lt;br /&gt;    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;class name="Subcategory1"&amp;gt;&lt;br /&gt;  &amp;lt;id name="id" unsaved-value="null" column="category_id"&amp;gt;&lt;br /&gt;   &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;    &amp;lt;param name="sequence"&amp;gt;sub1_category_seq&amp;lt;/param&amp;gt;&lt;br /&gt;   &amp;lt;/generator&amp;gt;&lt;br /&gt;  &amp;lt;/id&amp;gt;&lt;br /&gt;  &amp;lt;property name="name"/&amp;gt;&lt;br /&gt;  &amp;lt;property name="size"/&amp;gt;&lt;br /&gt; &amp;lt;/class&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!DOCTYPE hibernate-mapping PUBLIC&lt;br /&gt;    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" &lt;br /&gt;    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;class name="Subcategory2"&amp;gt;&lt;br /&gt;  &amp;lt;id name="id" unsaved-value="null" column="category_id"&amp;gt;&lt;br /&gt;   &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;    &amp;lt;param name="sequence"&amp;gt;sub2_category_seq&amp;lt;/param&amp;gt;&lt;br /&gt;   &amp;lt;/generator&amp;gt;&lt;br /&gt;  &amp;lt;/id&amp;gt;&lt;br /&gt;  &amp;lt;property name="name"/&amp;gt;&lt;br /&gt;  &amp;lt;property name="volume"/&amp;gt;&lt;br /&gt; &amp;lt;/class&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Stworzone zostaly dwie tabele:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="sql"&gt;&lt;br /&gt;CREATE TABLE subcategory1&lt;br /&gt;(&lt;br /&gt;  category_id integer NOT NULL,&lt;br /&gt;  name character varying(255),&lt;br /&gt;  size integer,&lt;br /&gt;  CONSTRAINT subcategory1_pkey PRIMARY KEY (category_id)&lt;br /&gt;) &lt;br /&gt;&lt;br /&gt;CREATE TABLE subcategory2&lt;br /&gt;(&lt;br /&gt;  category_id integer NOT NULL,&lt;br /&gt;  name character varying(255),&lt;br /&gt;  volume integer,&lt;br /&gt;  CONSTRAINT subcategory2_pkey PRIMARY KEY (category_id)&lt;br /&gt;) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ad2.&lt;br /&gt;Podejście drugie - odwzorowanie całej hierarchii klas w jednej tabeli.&lt;br /&gt;Tworzę JEDEN plik mapowań: Category.hbm.xml&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!DOCTYPE hibernate-mapping PUBLIC&lt;br /&gt;    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" &lt;br /&gt;    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;class name="Category"&amp;gt;&lt;br /&gt;  &amp;lt;id name="id" unsaved-value="null" column="category_id"&amp;gt;&lt;br /&gt;   &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;    &amp;lt;param name="sequence"&amp;gt;category_seq&amp;lt;/param&amp;gt;&lt;br /&gt;   &amp;lt;/generator&amp;gt;&lt;br /&gt;  &amp;lt;/id&amp;gt;&lt;br /&gt;  &amp;lt;discriminator column="type" type="string" /&amp;gt;&lt;br /&gt;  &amp;lt;property name="name" /&amp;gt;&lt;br /&gt;  &amp;lt;subclass name="Subcategory1" discriminator-value="1"&amp;gt;&lt;br /&gt;   &amp;lt;property name="size" /&amp;gt;&lt;br /&gt;  &amp;lt;/subclass&amp;gt;&lt;br /&gt;  &amp;lt;subclass name="Subcategory2" discriminator-value="2"&amp;gt;&lt;br /&gt;   &amp;lt;property name="volume" /&amp;gt;&lt;br /&gt;  &amp;lt;/subclass&amp;gt;&lt;br /&gt; &amp;lt;/class&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Stworzona została jedna tabela:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="sql"&gt;&lt;br /&gt;CREATE TABLE category&lt;br /&gt;(&lt;br /&gt;  category_id integer NOT NULL,&lt;br /&gt;  "type" character varying(255) NOT NULL,&lt;br /&gt;  name character varying(255),&lt;br /&gt;  size integer,&lt;br /&gt;  volume integer,&lt;br /&gt;  CONSTRAINT category_pkey PRIMARY KEY (category_id)&lt;br /&gt;) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ważne! Podczas tworzenia pliku z mapowaniem należy pamiętać, żeby element &amp;lt;discriminator&amp;gt; znajdował się przed wszystkimi elementami &amp;lt;property&amp;gt;.&lt;br /&gt;&lt;br /&gt;Ad 3.&lt;br /&gt;Podejście trzecie polega na reprezentacji związków dziedziczenia jako powiązań relacyjnych kluczy obcych. Każda podklasa korzysta z własnej tabeli.&lt;br /&gt;Tworzę trzy pliki mapowań: Category.hbm.xml, Subcategory1.hbm.xml, Subcategory2.hbm.xml&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!DOCTYPE hibernate-mapping PUBLIC&lt;br /&gt;    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" &lt;br /&gt;    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;class name="Category"&amp;gt;&lt;br /&gt;  &amp;lt;id name="id" unsaved-value="null" column="category_id"&amp;gt;&lt;br /&gt;   &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;    &amp;lt;param name="sequence"&amp;gt;category_seq&amp;lt;/param&amp;gt;&lt;br /&gt;   &amp;lt;/generator&amp;gt;&lt;br /&gt;  &amp;lt;/id&amp;gt;&lt;br /&gt;  &amp;lt;property name="name" /&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;/class&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!DOCTYPE hibernate-mapping PUBLIC&lt;br /&gt;    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" &lt;br /&gt;    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;joined-subclass name="Subcategory1" extends="Category"&amp;gt;&lt;br /&gt;  &amp;lt;key column="category_id"/&amp;gt;&lt;br /&gt;  &amp;lt;property name="size"/&amp;gt;&lt;br /&gt; &amp;lt;/joined-subclass&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!DOCTYPE hibernate-mapping PUBLIC&lt;br /&gt;    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" &lt;br /&gt;    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;joined-subclass name="Subcategory2" extends="Category"&amp;gt;&lt;br /&gt;  &amp;lt;key column="category_id"/&amp;gt;&lt;br /&gt;  &amp;lt;property name="volume"/&amp;gt;&lt;br /&gt; &amp;lt;/joined-subclass&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-mapping&amp;gt;  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;W bazie danych utworzone zostały trzy tabele:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="sql"&gt;&lt;br /&gt;CREATE TABLE category&lt;br /&gt;(&lt;br /&gt;  category_id integer NOT NULL,&lt;br /&gt;  name character varying(255),&lt;br /&gt;  CONSTRAINT category_pkey PRIMARY KEY (category_id)&lt;br /&gt;) &lt;br /&gt;&lt;br /&gt;CREATE TABLE subcategory1&lt;br /&gt;(&lt;br /&gt;  category_id integer NOT NULL,&lt;br /&gt;  size integer,&lt;br /&gt;  CONSTRAINT subcategory1_pkey PRIMARY KEY (category_id),&lt;br /&gt;  CONSTRAINT fk6c9080d3884719af FOREIGN KEY (category_id)&lt;br /&gt;      REFERENCES category (category_id) MATCH SIMPLE&lt;br /&gt;      ON UPDATE NO ACTION ON DELETE NO ACTION&lt;br /&gt;) &lt;br /&gt;&lt;br /&gt;CREATE TABLE subcategory2&lt;br /&gt;(&lt;br /&gt;  category_id integer NOT NULL,&lt;br /&gt;  volume integer,&lt;br /&gt;  CONSTRAINT subcategory2_pkey PRIMARY KEY (category_id),&lt;br /&gt;  CONSTRAINT fk6c9080d4884719af FOREIGN KEY (category_id)&lt;br /&gt;      REFERENCES category (category_id) MATCH SIMPLE&lt;br /&gt;      ON UPDATE NO ACTION ON DELETE NO ACTION&lt;br /&gt;) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ten typ odwzorowania umożliwia wydawanie intuicyjnych zapytań polimorficznych:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;cats = session.createQuery("from Category").list();&lt;br /&gt;System.out.println(cats.size()); // "2"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Każdy wpis w tabeli subcategory1 i subcategory2 odpowiadać będzie wpisowi w tabeli category.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4795010795101372767-8372198929211294247?l=marekel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marekel.blogspot.com/feeds/8372198929211294247/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://marekel.blogspot.com/2009/03/hibernate-reprezentacja-dziedziczenia.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/8372198929211294247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/8372198929211294247'/><link rel='alternate' type='text/html' href='http://marekel.blogspot.com/2009/03/hibernate-reprezentacja-dziedziczenia.html' title='Hibernate - reprezentacja dziedziczenia'/><author><name>Marek Lewandowski</name><uri>http://www.blogger.com/profile/12462254017661407439</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://4.bp.blogspot.com/_tDsMaYJzwyc/SYmBdOzwV2I/AAAAAAAAGzE/jFalxrPjviM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4795010795101372767.post-429871295836536604</id><published>2009-03-09T11:59:00.018+01:00</published><updated>2009-09-18T15:52:30.344+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hibernate pierwsza aplikacja'/><title type='text'>Hibernate - pierwsza aplikacja</title><content type='html'>Wiem, że to powinien być pierwszy post, ale jakoś nie miałem nigdy czasu ani chęci sklecać wszystkiego (całej konfiguracji) od początku. No ale w końcu się zmobilizowałem i zrobiłem pierwszą, prostą aplikację, która do bazy danych zapisuje jedną krotkę.&lt;br /&gt;&lt;br /&gt;Moje POJO jest bardzo proste:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt; public class Category {&lt;br /&gt; Integer id;&lt;br /&gt; String name;&lt;br /&gt;&lt;br /&gt; public Integer getId() {&lt;br /&gt;    return id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setId(Integer id) {&lt;br /&gt;    this.id = id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getName() {&lt;br /&gt;    return name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setName(String name) {&lt;br /&gt;    this.name = name;&lt;br /&gt; }&lt;br /&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Do tego równie proste mapowanie:&lt;br /&gt;&lt;br /&gt; &lt;pre name="code" class="xml"&gt;&amp;lt;hibernate-mapping package="main"&amp;gt;&lt;br /&gt; &amp;lt;class name="Category"&amp;gt;&lt;br /&gt;    &amp;lt;id name="id" value="null" column="category_id"&amp;gt;&lt;br /&gt;    &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;    &amp;lt;/generator&amp;gt;&amp;lt;/id&amp;gt;&amp;lt;/class&amp;gt;&amp;lt;/hibernate-mapping&amp;gt;&amp;lt;paramname="sequence"&amp;gt;category_seq&lt;br /&gt;&lt;br /&gt;&amp;lt;property name="name"&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Plik konfiguracyjny wygląda następująco:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE  hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"&lt;br /&gt; "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd"&amp;gt; &lt;br /&gt; &amp;lt;hibernate-configuration&amp;gt;&lt;br /&gt;    &amp;lt;session-factory&amp;gt;&lt;br /&gt;        &amp;lt;property name="hibernate.connection.url"&amp;gt;jdbc:postgresql://localhost:5432/testy&lt;br /&gt;        &amp;lt;/property&amp;gt;&lt;br /&gt;        &amp;lt;property name="hibernate.connection.driver_class"&amp;gt;org.postgresql.Driver&lt;br /&gt;        &amp;lt;/property&amp;gt;&lt;br /&gt;        &amp;lt;property name="hibernate.connection.username"&amp;gt;test&amp;lt;/property&amp;gt;&lt;br /&gt;        &amp;lt;property name="hibernate.connection.password"&amp;gt;test&amp;lt;/property&amp;gt;&lt;br /&gt;        &amp;lt;property name="hibernate.dialect"&amp;gt;org.hibernate.dialect.PostgreSQLDialect&lt;br /&gt;        &amp;lt;/property&amp;gt;&lt;br /&gt;        &amp;lt;property name="hibernate.show_sql"&amp;gt;false&amp;lt;/property&amp;gt;&lt;br /&gt;        &amp;lt;property name="hbm2ddl.auto"&amp;gt;create&amp;lt;/property&amp;gt;&lt;br /&gt;        &amp;lt;mapping resource="main\Category.hbm.xml" /&amp;gt;&lt;br /&gt;    &amp;lt;/session-factory&amp;gt;&lt;br /&gt;&amp;lt;/hibernate-configuration&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;W konfiguracji zawarty jest wpis o automatycznym tworzeniu schematu bazy danych ze zdefiniowanych plików mapowań:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;property name="hbm2ddl.auto"&amp;gt;create&amp;lt;/property&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Główna klasa projektu wygląda następująco:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;public class Main {&lt;br /&gt;public static void main(String[] args) {&lt;br /&gt; Session session = null;&lt;br /&gt; SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();&lt;br /&gt; session = sessionFactory.openSession();&lt;br /&gt; Category cat = new Category();&lt;br /&gt; cat.setName("name");&lt;br /&gt; session.beginTransaction();&lt;br /&gt; session.save(cat);&lt;br /&gt; session.flush();&lt;br /&gt; session.getTransaction().commit();&lt;br /&gt; session.close();&lt;br /&gt; System.out.println("end");&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Największą trudność może sprawić poprawne dobranie zależności. Działająca konfiguracja wygląda następująco:&lt;br /&gt;&lt;br /&gt;- antlr-2.7.6.jar&lt;br /&gt;- backport-util-concurrent-3.1.jar&lt;br /&gt;- postgresql-8.1-407.jdbc3.jar&lt;br /&gt;- ehcache-1.5.0.jar&lt;br /&gt;- log4j-1.2.14.jar&lt;br /&gt;- commons-collections-3.2.jar&lt;br /&gt;- dom4j-1.6.1.jar&lt;br /&gt;- commons-logging-1.1.1.jar&lt;br /&gt;- hibernate-3.2.5.ga.jar&lt;br /&gt;- jta-1.0.1B.jar&lt;br /&gt;- xml-apis-1.3.03.jar&lt;br /&gt;- cglib-nodep-2.1_3.jar&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4795010795101372767-429871295836536604?l=marekel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marekel.blogspot.com/feeds/429871295836536604/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://marekel.blogspot.com/2009/03/hibernate-pierwsza-aplikacja.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/429871295836536604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/429871295836536604'/><link rel='alternate' type='text/html' href='http://marekel.blogspot.com/2009/03/hibernate-pierwsza-aplikacja.html' title='Hibernate - pierwsza aplikacja'/><author><name>Marek Lewandowski</name><uri>http://www.blogger.com/profile/12462254017661407439</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://4.bp.blogspot.com/_tDsMaYJzwyc/SYmBdOzwV2I/AAAAAAAAGzE/jFalxrPjviM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4795010795101372767.post-3519314144369199277</id><published>2009-03-04T16:10:00.002+01:00</published><updated>2009-03-26T16:12:41.475+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JUNG'/><category scheme='http://www.blogger.com/atom/ns#' term='generowanie grafu'/><title type='text'>JUNG. Problem z generowaniem różnych grafów wynikowych dla takich samych danych wejściowych.</title><content type='html'>&lt;span style="font-weight: bold;"&gt;JUNG &lt;/span&gt;to skrót od Java Universal Network / Graph Framework. Biblioteka (albo framework, jak wolą autorzy) służy w ogólności do budowania grafów i obliczania współrzędnych ich wierzchołków. JUNG udostępnia szereg predefiniowanych typów grafów: skierowane, nieskierowane, acykliczne, z równoległymi krawędziami, drzewa, itp.&lt;br /&gt;Sam framework jest bardzo dobrze udokumentowny i używa się go w sposób bardzo intuicyjny, zatem ograniczę się do krótkiego przykładu:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;private void buildGraph() {&lt;br /&gt; //tworzę graf&lt;br /&gt; SparseGraph s = new SparseGraph();&lt;br /&gt;&lt;br /&gt; //tworzę wierzchołki grafu&lt;br /&gt; UndirectedSparseVertex node1 = new UndirectedSparseVertex();&lt;br /&gt; UndirectedSparseVertex node2 = new UndirectedSparseVertex();&lt;br /&gt;&lt;br /&gt; //dodaję wierzchołki do grafu&lt;br /&gt; g.addVertex(node1);&lt;br /&gt; g.addVertex(node1);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; //tworzę krawędź między dwoma wierzchołkami&lt;br /&gt; UndirectedSparseEdge link = new UndirectedSparseEdge(node1, node2);&lt;br /&gt; //dodaję krawędź do grafu&lt;br /&gt; g.addEdge(link);&lt;br /&gt;&lt;br /&gt; //rozmieszczam elementy grafu na okręgu, płaszczyźnie o wymiarach 100 x 100.&lt;br /&gt; CircleLayout layout = new MyCircleLayout(g);&lt;br /&gt; layout.initialize(new Dimension(100, 100));&lt;br /&gt;&lt;br /&gt; //informacyjnie wyświetlam obliczone przez JUNGa współrzędne&lt;br /&gt; System.out.println("--------------");&lt;br /&gt; System.out.println("node1.getX(): "+ layout.getLocation(node1).getX());&lt;br /&gt; System.out.println("node1.getY(): "+ layout.getLocation(node1).getY());&lt;br /&gt; System.out.println("node2.getX(): "+ layout.getLocation(node2).getX());&lt;br /&gt; System.out.println("node2.getY(): "+ layout.getLocation(node2).getY());&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Działa!&lt;br /&gt;&lt;br /&gt;Ale nie do końca tak jak bym tego chciał... dosyć szybko okazało się, że JUNG nie zawsze oblicza te same współrzędne dla tego samego grafu. Gdyby powyższa metoda wywołana została dwa razy, wynik mógłby wyglądać następująco:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;--------------&lt;br /&gt;node1().getX(): 10.00&lt;br /&gt;node1().getY(): 20.00&lt;br /&gt;node2().getX(): 30.00&lt;br /&gt;node2().getY(): 40.00&lt;br /&gt;&lt;br /&gt;--------------&lt;br /&gt;node1().getX(): 30.00&lt;br /&gt;node1().getY(): 40.00&lt;br /&gt;node2().getX(): 10.00&lt;br /&gt;node2().getY(): 20.00&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Problemem okazała się reprezentacja wierzchołków i krawędzi w obiekcie SparseGraph. Elementy te trzymane były w zbiorach HashSet, zatem kolejność ich pobierania ze zbioru nie zawsze musiała (i jak się okazało nie była) określona! Szybkim, prostym i skutecznym rozwiązaniem problemu okazało się napisanie klasy rozszerzającej SparseGraph i przeciążenie metody initialize(). Ostatecznie, poprawnie działający przykład, wygląda następująco:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;private static class MyGraph extends SparseGraph {&lt;br /&gt; protected void initialize()&lt;br /&gt;    {&lt;br /&gt;       super.initialize();&lt;br /&gt;       //LinkedHashSet gwarantuje, że elementy są umieszczane w zbiorze i pobierane z niego w tej samej kolejności&lt;br /&gt;       mVertices = new LinkedHashSet();&lt;br /&gt;       mEdges = new LinkedHashSet();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void buildGraph() {&lt;br /&gt; //tworzę graf&lt;br /&gt; MyGraph s = new MyGraph();&lt;br /&gt;&lt;br /&gt; //...&lt;br /&gt; //dalej analogicznie jak w poprzednim przykładzie&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4795010795101372767-3519314144369199277?l=marekel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marekel.blogspot.com/feeds/3519314144369199277/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://marekel.blogspot.com/2009/03/jung-problem-z-generowaniem-roznych.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/3519314144369199277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/3519314144369199277'/><link rel='alternate' type='text/html' href='http://marekel.blogspot.com/2009/03/jung-problem-z-generowaniem-roznych.html' title='JUNG. Problem z generowaniem różnych grafów wynikowych dla takich samych danych wejściowych.'/><author><name>Marek Lewandowski</name><uri>http://www.blogger.com/profile/12462254017661407439</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://4.bp.blogspot.com/_tDsMaYJzwyc/SYmBdOzwV2I/AAAAAAAAGzE/jFalxrPjviM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4795010795101372767.post-8705495398999738279</id><published>2009-02-04T17:05:00.001+01:00</published><updated>2009-03-26T16:19:02.279+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='HibernateDaoSupport'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Zarządzanie sesją i transakcjami w HibernateDaoSupport</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Pierwszy wpis na blogu i od razu wytaczam ciężkie działa - zarządzanie transakcjami bazodanowymi w środowisku Spring + Hibernate. Teoretycznie sprawa jest bardzo prosta - Spring, za pomocą HibernateDaoSupport, udostępnia cały zestaw metod służących bezbolesnej obsłudze danych (dodawanie, usuwanie) bez potrzeby zawracania sobie głowy sesjami, transakcjami, flushowaniem, commitowaniem, itd. Takie usprawnienie może wydawać się bardzo atrakcyjne, jednak w pewnych sytuacjach (czytaj: zazwyczaj) rodzi bardzo wiele problemów.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Poniżej postaram się opisać, w jaki sposób ujarzmić sesje i kontrolować transakcje podczas pracy ze springowym HibernateDaoSupport.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Pozwoję sobie pominąć szczegóły implementacyjne, skupiając się tylko na meritum.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Klasyczny przykład: mamy klasę Produkt i klasę Kategoria. Jeden produkt może znajdować się tylko w jednej kategorii, kategoria posiada zbiór produktów, a zatem relacja "jeden do wiele".&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Klasy POJO i mapowania:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;class name="Kategoria" table="kategoria"&amp;gt;&lt;br /&gt;    &amp;lt;id name="id" unsaved-value="null" column="kategory_id"&amp;gt;&lt;br /&gt;            &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;                    &amp;lt;param name="sequence"&amp;gt;kat_seq&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;/generator&amp;gt;&lt;br /&gt;    &amp;lt;/id&amp;gt;&lt;br /&gt;    &amp;lt;property name="name"/&amp;gt;&lt;br /&gt;    &amp;lt;property name="type"/&amp;gt;&lt;br /&gt;    &amp;lt;property name="description"/&amp;gt;&lt;br /&gt;    &amp;lt;set name="products" lazy="true"&amp;gt;&lt;br /&gt;            &amp;lt;key column="kategory_id"/&amp;gt;&lt;br /&gt;            &amp;lt;one-to-many class="Produkt"/&amp;gt;&lt;br /&gt;    &amp;lt;/set&amp;gt;&lt;br /&gt;&amp;lt;/class&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;class name="Produkt" table="produkt"&amp;gt;&lt;br /&gt;    &amp;lt;id name="id" unsaved-value="null" column="produkt_id"&amp;gt;&lt;br /&gt;            &amp;lt;generator class="sequence"&amp;gt;&lt;br /&gt;                    &amp;lt;param name="sequence"&amp;gt;prod_seq&amp;lt;/param&amp;gt;&lt;br /&gt;            &amp;lt;/generator&amp;gt;&lt;br /&gt;    &amp;lt;/id&amp;gt;&lt;br /&gt;    &amp;lt;property name="name"/&amp;gt;&lt;br /&gt;    &amp;lt;property name="value"/&amp;gt;&lt;br /&gt;    &amp;lt;many-to-one name="kategoria" class="Kategoria"/&amp;gt;&lt;br /&gt;&amp;lt;/class&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Ogólne DAO dla wszystkich obiektów:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;public class GenericDao extends HibernateDaoSupport {&lt;br /&gt;&lt;br /&gt;      public void store(Object object) {&lt;br /&gt;              getHibernateTemplate().saveOrUpdate(object);&lt;br /&gt;      };&lt;br /&gt;   &lt;br /&gt;      public void delete(Object object) {&lt;br /&gt;              getHibernateTemplate().delete(object);&lt;br /&gt;      };&lt;br /&gt;   &lt;br /&gt;      public List&amp;lt;Object&amp;gt; find(String query) {&lt;br /&gt;              return getHibernateTemplate().find(query);&lt;br /&gt;      }&lt;br /&gt;   &lt;br /&gt;      public Object findUnique(String query) {&lt;br /&gt;              List &amp;lt;Object&amp;gt; list = getHibernateTemplate().find(query);&lt;br /&gt;              if (list.size() &gt; 0)&lt;br /&gt;                      return list.get(0);&lt;br /&gt;              else&lt;br /&gt;                      return null;&lt;br /&gt;      }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Zakładam, że wszystkie DAO bądą dziedziczyć z powyższej klasy:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;public class KategoriaDao extends GenericDao {&lt;br /&gt;public Kategoria findKategoriaByName(String name) {&lt;br /&gt;return (Kategoria)findUnique("... where name = "+name);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class ProduktDao extends GenericDao {&lt;br /&gt;public Produkt findProduktByName(String name) {&lt;br /&gt;return (Produkt)findUnique("... where name = "+name);&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Teraz praktyczne działanie:&lt;br /&gt;&lt;pre name="code" class="java"&gt;public void testInsert() {&lt;br /&gt;Kategoria kat = new Kategoria();&lt;br /&gt;kat.setName("kat");&lt;br /&gt;kat.setDescription("desc");&lt;br /&gt;kategoriaDao.store(kat);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Po wywolaniu metody store() obiekt kat zostal zapisany w bazie danych. Bez tworzenia sesji, zatwierdzania transakcji, uspójniania bazy danych z objektami...&lt;br /&gt;Po prostu - wywołanie jednej metody i kategoria jest w bazie danych. Proste, prawda?&lt;br /&gt;&lt;br /&gt;Załóżmy, że w bazie danych istnieje kategoria o nazwie "kat". W bazie istnieją również cztery produkty należące do tej kategorii.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;public void testSelect() {&lt;br /&gt;Kategoria kat = kategoriaDao.findKategoriaByName("kat");&lt;br /&gt;System.out.println(kat.getName()); //kat&lt;br /&gt;System.out.println(kat.getDescription()); //desc&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Hmm... jeszcze prostsza sprawa. Zapisuję do bazy jedną metodą (store), odczytuję też jedną (find...), nigdzie w kodzie nie pojawia się magiczne słowo&lt;br /&gt;"session", HibernateDaoSupport jest rewelacyjne!&lt;br /&gt;&lt;br /&gt;Ok, ale zanim stwierdzimy, że Spring do spółki z Hibernatem wszystko za nas zrobią, spójrzmy na kojeny przykład:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;public void testSelectCollections() {&lt;br /&gt;Kategoria kat = kategoriaDao.findKategoriaByName("kat");&lt;br /&gt;for (Produkt p : kat.getProducts()) {&lt;br /&gt;System.out.println(p.getName());&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;W trakcie działania metody rzucony zostanie wyjątek LazyInitializationException: no session or session was closed.&lt;br /&gt;Hmm... pierwszy raz pojawia się więc słówko "session". Co się stało?&lt;br /&gt;Kategoria ma zbiór Produktów, który jest inicjalizowany w sposób "leniwy" (&lt;set name="products" lazy="true"&gt;), co oznacza, że podczas pobierania&lt;br /&gt;kategorii z bazy danych, NIE zostaną pobrane produkty należące do danej kategorii. Produkty zostaną ściągnięte z bazy danych dopiero wtedy, gdy&lt;br /&gt;będą potrzebne (nastąpi odwołanie do nich). Takie odwołanie następuje w pętli w metodzie testSelectCollections(). Dlaczego więc produkty nie będą&lt;br /&gt;pobrane w tym momencie? Ponieważ sesja z bazą danych wygasła i połączenie jest nieaktywne. Tylko skąd wiadomo gdzie zaczyna i gdzie kończy się&lt;br /&gt;sesja i jak nad tym zapanować? Otóż Spring samodzielnie zarządza sesjami otwierając je tylko i wyłącznie na czas wywołania metody z HibernateDaoSupport. Gwoli ścisłości:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;public void testSelectCollections() {&lt;br /&gt;//nie ma sesji&lt;br /&gt;Kategoria kat = kategoriaDao.findKategoriaByName("kat"); //jest sesja&lt;br /&gt;//nie ma sesji&lt;br /&gt;for (Produkt p : kat.getProducts()) {&lt;br /&gt;System.out.println(p.getName());&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Na szczęście Spring pozwala zapanować nad sesją. Z pomocą przychodzi Aspect Oriented Programming (AOP), które (za pomocą np. adnotacji) wskazuje Springowi&lt;br /&gt;gdzie zaczyna i gdzie kończy się transakcja, a co za tym idzie i sesja. Za pomocą adnotacji @Transactional oznaczamy metodę, która ma się wykonać w jednej transakcji:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;@Transactional&lt;br /&gt;public void testSelectCollections() {&lt;br /&gt;Kategoria kat = kategoriaDao.findKategoriaByName("kat");&lt;br /&gt;for (Produkt p : kat.getProducts()) {&lt;br /&gt;System.out.println(p.getName());&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;span style="font-family:verdana;"&gt;&lt;br /&gt;Sesja trwa przez cały czas wykonywania metody. Jest tylko jeden warunek - adnotacje @Transactional działają tylko w klasach, które są beanami springowymi!!!&lt;br /&gt;Problem rozwiązany!&lt;br /&gt;&lt;br /&gt;Żeby wszystko zadziałało trzeba poinformować Springa o chęci skorzystania z adnotacji i z AOP. Poniżej przykładowy plik konfiguracyjny:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;xmlns:context="http://www.springframework.org/schema/context"&lt;br /&gt;xmlns:tx="http://www.springframework.org/schema/tx"&lt;br /&gt;xmlns:aop="http://www.springframework.org/schema/aop"&lt;br /&gt;xsi:schemaLocation="&lt;br /&gt;  http://www.springframework.org/schema/beans&lt;br /&gt;  classpath:org/springframework/beans/factory/xml/spring-beans-2.0.xsd&lt;br /&gt;  http://www.springframework.org/schema/tx&lt;br /&gt;  classpath:org/springframework/transaction/config/spring-tx-2.0.xsd&lt;br /&gt;  http://www.springframework.org/schema/aop&lt;br /&gt;  classpath:org/springframework/aop/config/spring-aop-2.0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"&amp;gt;&lt;br /&gt;             ...&lt;br /&gt;     &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;bean id="localSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&amp;gt;&lt;br /&gt;             &amp;lt;property name="dataSource" ref="dataSource" /&amp;gt;&lt;br /&gt;             &amp;lt;property name="mappingResources"&amp;gt;&lt;br /&gt;                     &amp;lt;list&amp;gt;&lt;br /&gt;                             ...&lt;br /&gt;                     &amp;lt;/list&amp;gt;&lt;br /&gt;             &amp;lt;/property&amp;gt;&lt;br /&gt;             &amp;lt;property name="hibernateProperties"&amp;gt;&lt;br /&gt;                     &amp;lt;ref bean="hibernateProperties" /&amp;gt;&lt;br /&gt;             &amp;lt;/property&amp;gt;&lt;br /&gt;     &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;      &amp;lt;bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"&amp;gt;&lt;br /&gt;             &amp;lt;property name="sessionFactory" ref="localSessionFactory" /&amp;gt;&lt;br /&gt;  &amp;lt;/bean&amp;gt;&lt;br /&gt;     &amp;lt;tx:annotation-driven/&amp;gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Z całego pliku najważniejsze są:&lt;br /&gt;- &amp;lt;tx:annotation-driven&amp;gt; - dosłownie: "transakcje sterowane adnotacjami"&lt;br /&gt;- poprawne schemaLocation&lt;br /&gt;&lt;br /&gt;Trzeba też zwrócić uwagę na to, aby dołączane do projektu jary chciały ze sobą współpracować. Pewnego razu nie mogłem dojść do ładu z AOP,&lt;br /&gt;ponieważ każdy potrzebny jar był "z innej parafii". Gruntowne porządki w pom'ie były niezbędne.&lt;br /&gt;&lt;br /&gt;Poniżej fragment zależności z pom'a, które definiują poprawną konfigurację jar'ów (&amp;lt;springframework.version&amp;gt;2.0.6&amp;lt;/springframework.version&amp;gt;):&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&amp;lt;dependencies&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-aspects&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-aop&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-beans&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-dao&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-hibernate3&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-jms&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-jmx&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-remoting&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;spring-webmvc&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;${springframework.version}&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;             &amp;lt;dependency&amp;gt;&lt;br /&gt;                     &amp;lt;groupId&amp;gt;net.sf.ehcache&amp;lt;/groupId&amp;gt;&lt;br /&gt;                     &amp;lt;artifactId&amp;gt;ehcache&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                     &amp;lt;version&amp;gt;1.5.0&amp;lt;/version&amp;gt;&lt;br /&gt;             &amp;lt;/dependency&amp;gt;&lt;br /&gt;     &amp;lt;/dependencies&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4795010795101372767-8705495398999738279?l=marekel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://marekel.blogspot.com/feeds/8705495398999738279/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://marekel.blogspot.com/2009/02/zarzadzanie-sesja-i-transakcjami-w.html#comment-form' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/8705495398999738279'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4795010795101372767/posts/default/8705495398999738279'/><link rel='alternate' type='text/html' href='http://marekel.blogspot.com/2009/02/zarzadzanie-sesja-i-transakcjami-w.html' title='Zarządzanie sesją i transakcjami w HibernateDaoSupport'/><author><name>Marek Lewandowski</name><uri>http://www.blogger.com/profile/12462254017661407439</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://4.bp.blogspot.com/_tDsMaYJzwyc/SYmBdOzwV2I/AAAAAAAAGzE/jFalxrPjviM/S220/avatar.jpg'/></author><thr:total>3</thr:total></entry></feed>
