How to set request specific SQL session variable when loading data using Hibernate Native Query

Viewed 416

In one of my team's Spring Boot application we are using Spring JPA with Hibernate as JPA provider. We have this SQLExecutor class as a repository which is autowired in the request handler. The following is the skeleton structure of the class:

@Repository
public class SQLExecutor {
@PersistenceContext
private EntityManager em;

@Value("${query.fetch.size}")
private Integer queryFetchSize;

@SuppressWarnings("unchecked")
public Stream<Map<String, Object>> executeSqlStreamed(String dbQuerySql, List<Object> params) {
    Query query = constructQueryForStream(dbQuerySql, params);
    return query.getResultStream();
}

@SuppressWarnings("unchecked")
public List<Map<String, Object>> executeSql(String dbQuerySql, List<Object> params) {
    Query query = constructQueryForStream(dbQuerySql, params);
    return query.getResultList();
}

@SuppressWarnings("unchecked")
public Map<String, Object> executeSqlSingleResult(String dbQuerySql, List<Object> params) {
    Query query = constructQuery(dbQuerySql, params);
    return (Map<String, Object>) query.getSingleResult();
}

private Query constructQueryForStream(String dbQuerySql, List<Object> params) {
    Query query = constructQuery(dbQuerySql, params);
    query.setHint(QueryHints.HINT_FETCH_SIZE, queryFetchSize);
    return query;
}

@SuppressWarnings("deprecation")
private Query constructQuery(String dbQuerySql, List<Object> params) {
    Query query = em.createNativeQuery(dbQuerySql);
    query.unwrap(org.hibernate.query.Query.class).setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
    int paramIndex = 0;
    if (params != null && !params.isEmpty()) {
        for (Object paramValue : params) {
            query.setParameter(++paramIndex, paramValue);
        }
    }
    return query;
}
}

All the DB query strings are SELECT statements, because the application only provides read access to only a specific category of tables. The datasource is Tomcat JDBC pooled data source and the underlying database is a SQL based database that supports connection specific session variables. Both datasource and entitymanagerfactorbean are configured in a different @Configuration file.

Question

I have to pass a token from authentication context of the request to the db layer as a session variable, which would authenticate whether the application user trying to access a particular resource has access to that resource or not, using something similar to stored procedures. So basically, every time a user requests to read a resource, a session variable needs to be set using a value from the context of that request, before making the actual SELECT query.

Now, I know how to extract the token, but what I want to understand is how to set it to the session variable whenever a db connection is initialized for that read request. From other applications of my team which are using JDBC directly instead of Hibernate JPA, it is simple enough like so:

try (Statement stmt = conn.createStatement()) {
    stmt.executeUpdate("SET '" + variable + "' = '" + value + "'");
} catch (SQLException e) {
    throw e;
}

But since JPA does not expose the connection object directly, how do I ensure the session variable is set to the same connection as the one being used to execute the select statement.

Note: I understand the connection object can be accessed by unwrapping EntityManager instance to underlying Session object and then using the doReturningWork method, but I think that is an anti-pattern and would make supporting streaming result set a manual effort which is detrimental to the application.

0 Answers
Related