JPA - EclipseLink - Как изменить схему по умолчанию
Я программирую веб-приложение, используя weblogic и oracle. источник данных настраивается через JNDI с ограниченным пользователем базы данных, который может использовать DML в таблицах, но не может использовать DDL. Как вы можете догадаться, этот пользователь не является владельцем этих таблиц, но ему предоставлен доступ.
Допустим, он GUEST_USER
Приложение использует JPA + EclipseLink, и уже определено множество сущностей. Я не хочу писать в каждом классе каждой сущности атрибут для изменения схемы. Я попробовал SessionCustomizer, с этим кодом.
public class MyCustomizer implements SessionCustomizer{
@Override
public void customize(Session session) throws Exception {
session.executeNonSelectingSQL("ALTER SESSION SET CURRENT_SCHEMA = OWNERS_SCHEMA");
}
}
Кажется, что-то неинициализировано, я получаю исключение нулевого указателя, я даже не уверен, что это способ изменить схему для соединений перед их использованием. Есть образцы или идеи?
Заранее спасибо за помощь!
3 ответа
Если все объекты используют одну и ту же схему, вы можете использовать файл сопоставления xml для определения схемы по умолчанию.
Нечто подобное должно работать (пример для JPA 2.0, измените schemaLocation на 1.0)
orm.xml:
<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 orm_2_0.xsd"
version="2.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<schema>OWNERS_SCHEMA</schema>
</persistence-unit-defaults>
</persistence-unit-metadata>
. . .
</entity-mappings>
persistence.xml:
<persistence
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" >
<persistence-unit name="foo">
. . .
<mapping-file>orm.xml</mapping-file>
. . .
</persistence-unit>
</persistence>
Вы можете сделать это программно. Вы можете настроить значение схемы по умолчанию для каждого сеанса.
public class MySessionCustomizer implements SessionCustomizer {
private static String schemaName;
public static void setSchemaName(String schemaName) {
MySessionCustomizer.schemaName = schemaName;
}
@Override
public void customize(Session session) throws Exception {
if (StringUtils.hasText(this.schemaName)) {
session.getLogin().setTableQualifier(this.schemaName);
}
}
}
Затем установите настройщик сеанса на свойства фабрики диспетчера сущностей:
PersistenceUnitProperties.SESSION_CUSTOMIZER
например
propertiesMap.put(PersistenceUnitProperties.SESSION_CUSTOMIZER, MySessionCustomizer.class.getName());
Я использую EJB прямо перед запросом базы данных, поэтому, используя Interceptors, я могу установить схему в контексте EJB, просматривая текущего аутентифицированного пользователя.
Затем, когда я строю менеджер сущностей, я могу установить правильную схему. Таким образом, не указывая схему перед именем таблицы, PostgreSQL будет смотреть на search_path
для определения, какую схему запрашивать.
<!-- language: lang-java -->
public class Interceptor {
Logger logger = Logger.getLogger(Interceptor.class);
/**
*
* @param ctx is always null before being passed to EJB implementation. We always query database
* for populating context data, making user's session accessible to all EJB implementations
* @return
* @throws Exception
*/
@SuppressWarnings({ "unchecked", "unused" })
@AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String ejbName = ctx.getMethod().getDeclaringClass().getSimpleName();
String methodName = ctx.getMethod().getName();
Boolean override_schema = false;
String overridden_schema = "";
logger.info("Intercepting " + ejbName + "." + methodName);
if(auth != null) {
UserDetails userDetails = (UserDetails)auth.getPrincipal();
String username = userDetails.getUsername();
Collection<SimpleGrantedAuthority> permList = (Collection<SimpleGrantedAuthority>) auth.getAuthorities();
List<String> permissions = new ArrayList<String>();
for (SimpleGrantedAuthority authority : permList) {
permissions.add(authority.getAuthority());
}
Query query = getMasterEntityManager()
.createNativeQuery(
"SQL for retrieving the schema by the current logged in user");
query.setParameter("username", username);
List<Object[]> result = null; //query.getResultList();
if(result != null) {
logger.info("Interceptor: context set for " + username);
Object[] userObj = result.get(0);
getContext().getContextData().put("username", username);
getContext().getContextData().put("schema_name",(String)userObj[1]);
}
}
return ctx.proceed();
}
}
Затем, когда вы строите менеджер сущностей, вы можете установить схему, которую вы хотите.