java.util.Timer
i java.util.TimerTask
.
TimerService
, który będzie je powiadamiał przy pomocy metod zwrotnych. Obecnie nie dotyczy to Statefull SB. Jak budzik był dla EB, to usunięcie ziarna pozbędzie się też budzika. Ważne klasy:
TimerService
- Ziarna mogą pobrać ten obiekt od kontenera EJBContext.getTimerService()
. Pozwala utworzyć nowe budziki oraz pobrać te istniejące.Timer
- Obiekt reprezentujący budzik. Pozwala się odwołać, dowiedzić kiedy zadzwoni, (jeżeli przy tworzeniu podaliśmy obiekt z opisem) dowiedzieć czemu służy. Do budzików tak jak do ziaren można dostać serializowalne uchwyty.TimerObject
- Interfejs z metodą zwrotną, którą musi implementować ziarno.
public class StudentBean {
...
private String kluczOsoby; //klucz obcy łączący z Osobą
private Osoba osoba;
...
public Osoba getOsoba() { return osoba; }
public void setOsoba(Osoba o) { this.osoba = o; }
...
public void ejbLoad() {
1. odczytaj dane Studenta (zawierają klucz obcy Osoby)
2. pobierz z JNDI OsobaHome
3. osoba = osobaHome.findByPrimaryKey(this.kluczOsoby)
}
public void ejbStore() {
1. this.kluczOsoby = osoba.getKluczGł()
2. zapisz dane Studenta (razem z kluczem obcym Osoby)
}
}
<relationships>
<ejb-relation>
<ejb-relation-name>Osoba-Student</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>Osoba-jest-Studentem</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>Osoba</ejb-name>
</relationship-role-source>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>Student-jest-Osoba</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<cascade-delete/>
<relationship-role-source>
<ejb-name>Student</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>osoba</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
</ejb-relation>
...
</relationships>
java.util.Collection (może zawierać duplikaty) lub java.util.Set (nie może).
<cmr-field>
<crm-field-name>pracownicy</crm-field-name>
<crm-field-type>java.util.Collection</cmr-field-type>
</cmr-field>
- Dobre kontenery wczytują wszystkie dane dotyczące związku przy pomocy jednego zapytania. W BMP się tak nie da, bo drugi bean/beany(jeżeli kolekcja) musi się sam wczytać.
- Jeżeli kierunek związku na to pozwala możemy przechodzić po grafie obiektów przy pomocy w zapytaniach EJB-QL (kończymy w ziarnie lub w polu zarządzanym przez kontener).
SELECT s.osoba.nazwisko FROM Student s
Kierunek związku
Związki mogą być jedno lub dwukierunkowe. Nie ma to nic wspólnego z tym jak dane są przechowywane w bazie, ale gdzie są pola pozwalające na nawiagację.
Ćwiczenie 4
Podać kod OsobaBean, jeżeli związek Osoba-Student jest:
- jendokierunkowy
- dwukierunkowy
Ćwiczenie 5
Jakie zagrożenia niesie używanie interfejsów zdalnych dla EB będących w związkach.
Leniwe wgrywanie
Pokazany kod zakłada agresywne wgrywanie (ejbLoad()
punkt 3). Dla małych grafów to dobre, bo wszystko wgrywamy w jednej transakcji z bazą. Dla dużych grafów, np. przy związkach wiele do wiele, jest zagrożeniem dla efektywności. Agresywne wgrywanie może powodować zapętlenie (np. trzy ziarnowy cykl i zapętlamy się na wyszukiwaniu). Leniwie możemy wgrywać osobę na podstawie klucza w getOsoba()
. W CMP wystarczą odpowiednie definicje w deskryptorach kontenera.
Więzy spójności
Można zrobić w bazie danych przy pomocy odpowiednich więzów i trigerów. Można zrobić w bazie danych przy pomocy procedur składowanych. Można zrobić w EJB, przykładowo agregacja całkowita (w przeciwieństwie do agregacji) powinna powodować kaskadowe kasowanie (np. ejbRemove()
Osoby wywołuje remove()
na Studencie). W CMP zajmuje się tym kontener.
Ćwiczenie 6
Zaimplementować związki z Oraclowego schematu Emp-Dept-Salgrade. Dodać konieczne więzy spójności. Do wyboru przy pomocy BMP lub CMP.