Hibernate propose :
- Schéma dynamique mais unique pour toutes les entités
- Schéma figé mais différent selon entités
1) Rajouter un Interceptor Hibernate :
/**
* This class can rebuild requests.
*/
@Component
public class HibernateSchemaInterceptor extends EmptyInterceptor {
public final static Logger LOGGER = LoggerFactory.getLogger(HibernateSchemaInterceptor.class.getCanonicalName());
public HibernateSchemaInterceptor() {
LOGGER.info("initialize HibernateSchemaInterceptor bean.");
}
@Override
public String onPrepareStatement(String sql) {
String correctedSQL = sql;
correctedSQL = correctedSQL.replaceAll(GenericEntity.FIRST_SCHEMA_NAME, StaticServiceHolder.firstSchemaName);
correctedSQL = correctedSQL.replaceAll(GenericEntity.SECOND_SCHEMA_NAME, StaticServiceHolder.secondSchemaName);
return super.onPrepareStatement(correctedSQL);
}
}
Cette classe est appelée avant ou après l'exécution d'une requête.
2) Rajouter l'interceptor aux properties JPA
@Bean
public Properties jpaProperties() {
Properties props = new Properties();
super.putProperties("hibernate.dialect", props);
//super.putProperties("hibernate.hbm2ddl.auto", props);
props.setProperty("hibernate.enable_lazy_load_no_trans", "true");
props.setProperty("org.hibernate.flushMode", "AUTO");
props.setProperty("hibernate.ejb.interceptor", HibernateSchemaInterceptor.class.getCanonicalName());
LOGGER.info("Hibernate JPA Properties loaded");
return props;
}
L'instanciation serait faite via les EJB.
3) Définir un endroit ou l'interceptor pourra accéder aux beans variables (noms des schémas) :
/**
* This class inject itself the Spring context to make it available for classes not managed by Spring.
*/
@Component
public class StaticServiceHolder {
public static String firstSchemaName;
public static String secondSchemaName ;
@Autowired
public void setFirstSchemaName(String firstSchemaName) {
StaticServiceHolder.firstSchemaName = firstSchemaName;
}
@Autowired
public void setSecondSchemaName(String secondSchemaName) {
StaticServiceHolder. secondSchemaName = secondSchemaName;
}
}
4) Rajouter le nom des schémas "mocké" aux entités :
@Entity
@Table(name = "TABLE", schema = GenericEntity.FIRST_SCHEMA_NAME)
public class Entity implements GenericEntity {
//Dans les join table AUSSI :
@JoinTable(
name = "JT_ENTITY_ENTITY2",
schema = GenericEntity.FIRST_SCHEMA_NAME,
joinColumns = @JoinColumn(name = "ENTITY_ID"),
inverseJoinColumns = @JoinColumn(name = "ENTITY2_ID")
)
@ManyToMany
private Set<Entity2> linked;
Lorsque l'on doit gérer une application qui communique avec un base de données et plusieurs schémas.
Ce qu'il faut savoir : Hibernate permet de setter un schéma global dynamiquement ou un schéma par entité mais en dur...
Comment gérer le cas ou le nom des schémas change selon l'environnement ?
Je ne dis pas que le besoin est légitime (est-ce une bonne pratique ? probablement pas), en attentant, cette petite page va probablement sauver ma semaine.