Helper class that simplifies Hibernate data access code, and converts
checked HibernateExceptions into unchecked DataAccessExceptions,
following the
exception hierarchy.
Uses the same SQLExceptionTranslator mechanism as JdbcTemplate.
Typically used to implement data access or business logic services that
use Hibernate within their implementation but are Hibernate-agnostic in their
interface. The latter or code calling the latter only have to deal with
domain objects, query objects, and org.springframework.dao exceptions.
The central method is "execute", supporting Hibernate code implementing
the HibernateCallback interface. It provides Hibernate Session handling
such that neither the HibernateCallback implementation nor the calling
code needs to explicitly care about retrieving/closing Hibernate Sessions,
or handling Session lifecycle exceptions. For typical single step actions,
there are various convenience methods (find, load, saveOrUpdate, delete).
Can be used within a service implementation via direct instantiation
with a SessionFactory reference, or get prepared in an application context
and given to services as bean reference. Note: The SessionFactory should
always be configured as bean in the application context, in the first case
given to the service directly, in the second case to the prepared template.
This class can be considered a programmatic alternative to
HibernateInterceptor. The major advantage is its straightforwardness, the
major disadvantage that no checked application exceptions can get thrown
from within data access code. Such checks and the actual throwing of such
exceptions can often be deferred to after callback execution, though.
Note that even if HibernateTransactionManager is used for transaction
demarcation in higher-level services, all those services above the data
access layer don't need need to be Hibernate-aware. Setting such a special
PlatformTransactionManager is a configuration issue: For example,
switching to JTA is just a matter of Spring configuration (use
JtaTransactionManager instead) that does not affect application code.
LocalSessionFactoryBean is the preferred way of obtaining a reference
to a specific Hibernate SessionFactory, at least in a non-EJB environment.
Alternatively, use a JndiObjectFactoryBean to fetch a SessionFactory
from JNDI (possibly set up via a JCA Connector).
Note that operations that return an Iterator (i.e. iterate)
are supposed to be used within Spring-driven or JTA-driven transactions
(with HibernateTransactionManager, JtaTransactionManager, or EJB CMT).
Else, the Iterator won't be able to read results from its ResultSet anymore,
as the underlying Hibernate Session will already have been closed.
Lazy loading will also just work with an open Hibernate Session,
either within a transaction or within OpenSessionInViewFilter/Interceptor.
Furthermore, some operations just make sense within transactions,
for example: contains, evict, lock,
flush, clear.
Note: Spring's Hibernate support requires Hibernate 2.1 (as of Spring 1.0).
| Method from org.springframework.orm.hibernate.HibernateTemplate Detail: |
protected void applyNamedParameterToQuery(Query queryObject,
String paramName,
Object value,
Type type) throws HibernateException {
if (value instanceof Collection) {
if (type != null) {
queryObject.setParameterList(paramName, (Collection) value, type);
}
else {
queryObject.setParameterList(paramName, (Collection) value);
}
}
else if (value instanceof Object[]) {
if (type != null) {
queryObject.setParameterList(paramName, (Object[]) value, type);
}
else {
queryObject.setParameterList(paramName, (Object[]) value);
}
}
else {
if (type != null) {
queryObject.setParameter(paramName, value, type);
}
else {
queryObject.setParameter(paramName, value);
}
}
}
Apply the given name parameter to the given Query object. |
protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {
if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER &&
FlushMode.NEVER.equals(session.getFlushMode())) {
throw new InvalidDataAccessApiUsageException(
"Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session " +
"into FlushMode.AUTO or remove 'readOnly' marker from transaction definition");
}
}
Check whether write operations are allowed on the given Session.
Default implementation throws an InvalidDataAccessApiUsageException
in case of FlushMode.NEVER. Can be overridden in subclasses. |
public void clear() throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
session.clear();
return null;
}
}, true);
}
|
public void closeIterator(Iterator it) throws DataAccessException {
try {
Hibernate.close(it);
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
|
public boolean contains(Object entity) throws DataAccessException {
Boolean result = (Boolean) execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
return new Boolean(session.contains(entity));
}
}, true);
return result.booleanValue();
}
|
protected Session createSessionProxy(Session session) {
return (Session) Proxy.newProxyInstance(
getClass().getClassLoader(),
new Class[] {Session.class},
new CloseSuppressingInvocationHandler(session));
}
Create a close-suppressing proxy for the given Hibernate Session.
The proxy also prepares returned Query and Criteria objects. |
public void delete(Object entity) throws DataAccessException {
delete(entity, null);
}
|
public int delete(String queryString) throws DataAccessException {
return delete(queryString, (Object[]) null, (Type[]) null);
}
|
public void delete(Object entity,
LockMode lockMode) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
if (lockMode != null) {
session.lock(entity, lockMode);
}
session.delete(entity);
return null;
}
}, true);
}
|
public int delete(String queryString,
Object value,
Type type) throws DataAccessException {
return delete(queryString, new Object[] {value}, new Type[] {type});
}
|
public int delete(String queryString,
Object[] values,
Type[] types) throws DataAccessException {
if (values != null && types != null && values.length != types.length) {
throw new IllegalArgumentException("Length of values array must match length of types array");
}
Integer deleteCount = (Integer) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
if (values != null) {
return new Integer(session.delete(queryString, values, types));
}
else {
return new Integer(session.delete(queryString));
}
}
}, true);
return deleteCount.intValue();
}
|
public void deleteAll(Collection entities) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
for (Iterator it = entities.iterator(); it.hasNext();) {
session.delete(it.next());
}
return null;
}
}, true);
}
|
public void evict(Object entity) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
session.evict(entity);
return null;
}
}, true);
}
|
public Object execute(HibernateCallback action) throws DataAccessException {
return execute(action, isExposeNativeSession());
}
|
public Object execute(HibernateCallback action,
boolean exposeNativeSession) throws DataAccessException {
Session session = getSession();
boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());
if (!existingTransaction && getFlushMode() == FLUSH_NEVER) {
session.setFlushMode(FlushMode.NEVER);
}
try {
Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));
Object result = action.doInHibernate(sessionToExpose);
flushIfNecessary(session, existingTransaction);
return result;
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
catch (SQLException ex) {
throw convertJdbcAccessException(ex);
}
catch (RuntimeException ex) {
// callback code threw application exception
throw ex;
}
finally {
SessionFactoryUtils.closeSessionIfNecessary(session, getSessionFactory());
}
}
Execute the action specified by the given action object within a Session. |
public List executeFind(HibernateCallback action) throws DataAccessException {
return (List) execute(action, isExposeNativeSession());
}
|
public List find(String queryString) throws DataAccessException {
return find(queryString, (Object[]) null, (Type[]) null);
}
|
public List find(String queryString,
Object value) throws DataAccessException {
return find(queryString, new Object[] {value}, (Type[]) null);
}
|
public List find(String queryString,
Object[] values) throws DataAccessException {
return find(queryString, values, (Type[]) null);
}
|
public List find(String queryString,
Object value,
Type type) throws DataAccessException {
return find(queryString, new Object[] {value}, new Type[] {type});
}
|
public List find(String queryString,
Object[] values,
Type[] types) throws DataAccessException {
if (values != null && types != null && values.length != types.length) {
throw new IllegalArgumentException("Length of values array must match length of types array");
}
return (List) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
if (types != null && types[i] != null) {
queryObject.setParameter(i, values[i], types[i]);
}
else {
queryObject.setParameter(i, values[i]);
}
}
}
return queryObject.list();
}
}, true);
}
|
public List findByNamedParam(String queryString,
String paramName,
Object value) throws DataAccessException {
return findByNamedParam(queryString, paramName, value, null);
}
|
public List findByNamedParam(String queryString,
String[] paramNames,
Object[] values) throws DataAccessException {
return findByNamedParam(queryString, paramNames, values, null);
}
|
public List findByNamedParam(String queryString,
String paramName,
Object value,
Type type) throws DataAccessException {
return findByNamedParam(queryString, new String[] {paramName}, new Object[] {value}, new Type[] {type});
}
|
public List findByNamedParam(String queryString,
String[] paramNames,
Object[] values,
Type[] types) throws DataAccessException {
if (paramNames.length != values.length) {
throw new IllegalArgumentException("Length of paramNames array must match length of values array");
}
if (types != null && paramNames.length != types.length) {
throw new IllegalArgumentException("Length of paramNames array must match length of types array");
}
return (List) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
applyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null));
}
}
return queryObject.list();
}
}, true);
}
|
public List findByNamedQuery(String queryName) throws DataAccessException {
return findByNamedQuery(queryName, (Object[]) null, (Type[]) null);
}
|
public List findByNamedQuery(String queryName,
Object value) throws DataAccessException {
return findByNamedQuery(queryName, new Object[] {value}, (Type[]) null);
}
|
public List findByNamedQuery(String queryName,
Object[] values) throws DataAccessException {
return findByNamedQuery(queryName, values, (Type[]) null);
}
|
public List findByNamedQuery(String queryName,
Object value,
Type type) throws DataAccessException {
return findByNamedQuery(queryName, new Object[] {value}, new Type[] {type});
}
|
public List findByNamedQuery(String queryName,
Object[] values,
Type[] types) throws DataAccessException {
if (values != null && types != null && values.length != types.length) {
throw new IllegalArgumentException("Length of values array must match length of types array");
}
return (List) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.getNamedQuery(queryName);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
if (types != null && types[i] != null) {
queryObject.setParameter(i, values[i], types[i]);
}
else {
queryObject.setParameter(i, values[i]);
}
}
}
return queryObject.list();
}
}, true);
}
|
public List findByNamedQueryAndNamedParam(String queryName,
String paramName,
Object value) throws DataAccessException {
return findByNamedQueryAndNamedParam(queryName, paramName, value, null);
}
|
public List findByNamedQueryAndNamedParam(String queryName,
String[] paramNames,
Object[] values) throws DataAccessException {
return findByNamedQueryAndNamedParam(queryName, paramNames, values, null);
}
|
public List findByNamedQueryAndNamedParam(String queryName,
String paramName,
Object value,
Type type) throws DataAccessException {
return findByNamedQueryAndNamedParam(
queryName, new String[] {paramName}, new Object[] {value}, new Type[] {type});
}
|
public List findByNamedQueryAndNamedParam(String queryName,
String[] paramNames,
Object[] values,
Type[] types) throws DataAccessException {
if (paramNames != null && values != null && paramNames.length != values.length) {
throw new IllegalArgumentException("Length of paramNames array must match length of values array");
}
if (values != null && types != null && paramNames.length != types.length) {
throw new IllegalArgumentException("Length of paramNames array must match length of types array");
}
return (List) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.getNamedQuery(queryName);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
applyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null));
}
}
return queryObject.list();
}
}, true);
}
|
public List findByNamedQueryAndValueBean(String queryName,
Object valueBean) throws DataAccessException {
return (List) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.getNamedQuery(queryName);
prepareQuery(queryObject);
queryObject.setProperties(valueBean);
return queryObject.list();
}
}, true);
}
|
public List findByValueBean(String queryString,
Object valueBean) throws DataAccessException {
return (List) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
queryObject.setProperties(valueBean);
return queryObject.list();
}
}, true);
}
|
public void flush() throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
session.flush();
return null;
}
}, true);
}
|
public Object get(Class entityClass,
Serializable id) throws DataAccessException {
return get(entityClass, id, null);
}
|
public Object get(Class entityClass,
Serializable id,
LockMode lockMode) throws DataAccessException {
return execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
return session.get(entityClass, id, lockMode);
}
else {
return session.get(entityClass, id);
}
}
}, true);
}
|
public String getQueryCacheRegion() {
return queryCacheRegion;
}
Return the name of the cache region for queries executed by this template. |
protected Session getSession() {
if (isAlwaysUseNewSession()) {
return SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor());
}
else if (!isAllowCreate()) {
return SessionFactoryUtils.getSession(getSessionFactory(), false);
}
else {
return SessionFactoryUtils.getSession(
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
}
}
Return a Session for use by this template.
Returns a new Session in case of "alwaysUseNewSession" (using the same
JDBC Connection as a transactional Session, if applicable), a pre-bound
Session in case of "allowCreate" turned off, and a pre-bound or new Session
else (new only if no transactional or otherwise pre-bound Session exists). |
public void initialize(Object proxy) throws DataAccessException {
try {
Hibernate.initialize(proxy);
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
|
public boolean isAllowCreate() {
return allowCreate;
}
Return if a new Session should be created if no thread-bound found. |
public boolean isAlwaysUseNewSession() {
return alwaysUseNewSession;
}
Return whether to always use a new Hibernate Session for this template. |
public boolean isCacheQueries() {
return cacheQueries;
}
Return whether to cache all queries executed by this template. |
public boolean isCheckWriteOperations() {
return checkWriteOperations;
}
Return whether to check that the Hibernate Session is not in read-only
mode in case of write operations (save/update/delete). |
public boolean isExposeNativeSession() {
return exposeNativeSession;
}
Return whether to expose the native Hibernate Session to HibernateCallback
code, or rather a Session proxy. |
public Iterator iterate(String queryString) throws DataAccessException {
return iterate(queryString, (Object[]) null, (Type[]) null);
}
|
public Iterator iterate(String queryString,
Object value) throws DataAccessException {
return iterate(queryString, new Object[] {value}, (Type[]) null);
}
|
public Iterator iterate(String queryString,
Object[] values) throws DataAccessException {
return iterate(queryString, values, (Type[]) null);
}
|
public Iterator iterate(String queryString,
Object value,
Type type) throws DataAccessException {
return iterate(queryString, new Object[] {value}, new Type[] {type});
}
|
public Iterator iterate(String queryString,
Object[] values,
Type[] types) throws DataAccessException {
if (values != null && types != null && values.length != types.length) {
throw new IllegalArgumentException("Length of values array must match length of types array");
}
return (Iterator) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
if (types != null && types[i] != null) {
queryObject.setParameter(i, values[i], types[i]);
}
else {
queryObject.setParameter(i, values[i]);
}
}
}
return queryObject.iterate();
}
}, true);
}
|
public Object load(Class entityClass,
Serializable id) throws DataAccessException {
return load(entityClass, id, null);
}
|
public void load(Object entity,
Serializable id) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
session.load(entity, id);
return null;
}
}, true);
}
|
public Object load(Class entityClass,
Serializable id,
LockMode lockMode) throws DataAccessException {
return execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
return session.load(entityClass, id, lockMode);
}
else {
return session.load(entityClass, id);
}
}
}, true);
}
|
public List loadAll(Class entityClass) throws DataAccessException {
return (List) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria criteria = session.createCriteria(entityClass);
prepareCriteria(criteria);
return criteria.list();
}
}, true);
}
|
public void lock(Object entity,
LockMode lockMode) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
session.lock(entity, lockMode);
return null;
}
}, true);
}
|
protected void prepareCriteria(Criteria criteria) {
if (isCacheQueries()) {
criteria.setCacheable(true);
if (getQueryCacheRegion() != null) {
criteria.setCacheRegion(getQueryCacheRegion());
}
}
SessionFactoryUtils.applyTransactionTimeout(criteria, getSessionFactory());
}
Prepare the given Criteria object, applying cache settings and/or
a transaction timeout. |
protected void prepareQuery(Query queryObject) {
if (isCacheQueries()) {
queryObject.setCacheable(true);
if (getQueryCacheRegion() != null) {
queryObject.setCacheRegion(getQueryCacheRegion());
}
}
SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
}
Prepare the given Query object, applying cache settings and/or
a transaction timeout. |
public void refresh(Object entity) throws DataAccessException {
refresh(entity, null);
}
|
public void refresh(Object entity,
LockMode lockMode) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
session.refresh(entity, lockMode);
}
else {
session.refresh(entity);
}
return null;
}
}, true);
}
|
public Serializable save(Object entity) throws DataAccessException {
return (Serializable) execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
return session.save(entity);
}
}, true);
}
|
public void save(Object entity,
Serializable id) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
session.save(entity, id);
return null;
}
}, true);
}
|
public void saveOrUpdate(Object entity) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
session.saveOrUpdate(entity);
return null;
}
}, true);
}
|
public void saveOrUpdateAll(Collection entities) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
for (Iterator it = entities.iterator(); it.hasNext();) {
session.saveOrUpdate(it.next());
}
return null;
}
}, true);
}
|
public Object saveOrUpdateCopy(Object entity) throws DataAccessException {
return execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
return session.saveOrUpdateCopy(entity);
}
}, true);
}
|
public void setAllowCreate(boolean allowCreate) {
this.allowCreate = allowCreate;
}
Set if a new Session should be created if no thread-bound found.
HibernateTemplate is aware of a respective Session bound to the
current thread, for example when using HibernateTransactionManager.
If allowCreate is true, a new Session will be created if none found.
If false, an IllegalStateException will get thrown in this case. |
public void setAlwaysUseNewSession(boolean alwaysUseNewSession) {
this.alwaysUseNewSession = alwaysUseNewSession;
}
Set whether to always use a new Hibernate Session for this template.
Default is false; if activated, all operations on this template will
work on a new Hibernate Session even in case of a pre-bound Session
(for example, within a transaction or OpenSessionInViewFilter).
Within a transaction, a new Hibernate Session used by this template
will participate in the transaction through using the same JDBC
Connection. In such a scenario, multiple Sessions will participate
in the same database transaction.
Turn this on for operations that are supposed to always execute
independently, without side effects caused by a shared Hibernate
Session. |
public void setCacheQueries(boolean cacheQueries) {
this.cacheQueries = cacheQueries;
}
Set whether to cache all queries executed by this template.
If this is true, all Query and Criteria objects created by
this template will be marked as cacheable (including all
queries through find methods).
To specify the query region to be used for queries cached
by this template, set the "queryCacheRegion" property. |
public void setCheckWriteOperations(boolean checkWriteOperations) {
this.checkWriteOperations = checkWriteOperations;
}
Set whether to check that the Hibernate Session is not in read-only mode
in case of write operations (save/update/delete).
Default is true, for fail-fast behavior when attempting write operations
within a read-only transaction. Turn this off to allow save/update/delete
on a Session with flush mode NEVER. |
public void setExposeNativeSession(boolean exposeNativeSession) {
this.exposeNativeSession = exposeNativeSession;
}
Set whether to expose the native Hibernate Session to HibernateCallback
code. Default is false; instead, a Session proxy will be returned,
suppressing close calls and automatically applying
query cache settings and transaction timeouts. |
public void setQueryCacheRegion(String queryCacheRegion) {
this.queryCacheRegion = queryCacheRegion;
}
Set the name of the cache region for queries executed by this template.
If this is specified, it will be applied to all Query and Criteria objects
created by this template (including all queries through find methods).
The cache region will not take effect unless queries created by this
template are configured to be cached via the "cacheQueries" property. |
public void update(Object entity) throws DataAccessException {
update(entity, null);
}
|
public void update(Object entity,
LockMode lockMode) throws DataAccessException {
execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
checkWriteOperationAllowed(session);
session.update(entity);
if (lockMode != null) {
session.lock(entity, lockMode);
}
return null;
}
}, true);
}
|