JPA XML mapping állományok
Adott egy web alkalmazás, mely perzisztenciához Hibernate JPA provider-t és Oracle 10g adatbázist használ. A JPA nagy ígérete a platformfüggetlenség, azaz az alkalmazás minimális erőfeszítéssel futtatható másik adatbázison.
Ki is próbáltam, és a Hibernate specifikus databasePlatform beállítást org.hibernate.dialect.Oracle10gDialect értékről átírtam MySQL5Dialect-re (normál esetben ez a persistence.xml-ben van, de én Spring-ből használtam, így az applicationContext.xml-ben).
Ekkora következő hibaüzeneteket kaptam:
Caused by: org.hibernate.MappingException: could not instantiate id generator
Caused by: org.hibernate.MappingException: Dialect does not support sequences
Ez azért van, mert a forráskódban az entitás id attribútumán a következő annotáció szerepelt:
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "EmployeeSeq")
@SequenceGenerator(name="EmployeeSeq", sequenceName = "seq_employee")
private Long id;
...
}
Ez azt jelenti, hogy az id értéke automatikusan generált, az EmployeeSeq generátor által, mely egy Oracle szekvencia, seq_employee néven. Azonban a MySQL nem ismeri a szekvencia fogalmát, helyette a mezőnek egy tulajdonsága az auto increment.
Az automatikus azonosító generálásra a JPA a következő lehetőségeket biztosítja:
- Table: ekkor egy tábla tartalmazza a kiosztható azonosítókat - ez minden adatbázison működő megoldás
- Sequence: azonosító generálása szekvencia alapján - pl. az Oracle ismeri
- Identity: elsődleges kulcs identity, vagy más néven autonumber vagy auto increment - a MySQL ezt ismeri
- Auto: a provider választ
Így tehát a kóddal, a forráskódban szereplő annotációkkal az adatbázishoz kötöttük magunkat, bukva a platformfüggetlenséget. Vagy mégsem?
A JPA-ban (ugyanúgy mint az EJB3-ban) ugyanis lehetőség van a konfiguráció megadására annotációként, és ezt felül lehet definiálni a kódon kívül XML konfigurációs állományokban (EJB esetén deployment descriptor-nak hívják). Ezek a konfigurációs állományok JPA esetén a JPA XML mapping állományok. Minden egyes annotációval megadható konfigurációt meg lehet adni XML konfigurációval is. Amennyiben nincs sem annotációval, sem XML-ben konfiguráció megadva, ún. intelligens default értékek kerülnek alkalmazásra. Ilyen intelligens alapértelmezett érték pl. az, hogy a tábla neve megegyezik az entitás nevével, annyi oszlop van benne, amennyi nem tranziens attribútum.
Tehát a cél, hogy az alkalmazás kódjának módosítása nélkül képes legyen MySQL adatbázison is működni. Ehhez először a persistence.xml állományban kell megadni az XML konfigurációs állomány helyét. Legyen ez is a persistence.xml állomány mellett, mapping-mysql.xml néven (a WAR állományban a WEB-INF/classes/META-INF könyvtárban kell elhelyezni).
Ehhez módosítsuk a persistence.xml állományt a következő módon:
<persistence-unit name="jtechlogPU" transaction-type="RESOURCE_LOCAL">
<mapping-file>META-INF/mapping-mysql.xml</mapping-file>
</persistence-unit>
Az állomány helyét a CLASSPATH-hoz képest kell megadni.
A mapping-mysql.xml állományban definiáljuk, hogy az Employee osztály id attribútumának generátora identity típusú legyen:
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
version="1.0">
<entity class="jtechlog.Employee">
<attributes>
<id name="id">
<generated-value strategy="IDENTITY" />
</id>
</attributes>
</entity>
</entity-mappings>
Ezzel a beállítással az alkalmazás azonnal képes volt MySQL adatbázison is működni. Már csak a build folyamatot kell úgy módosítani, hogy a persistence.xml állományban egy környezeti beállítás alapján helyezze el a mapping állomány hivatkozást.