org.ibatis.spring.SqlMapClientTemplate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jbatis Show documentation
Show all versions of jbatis Show documentation
The jBATIS persistence framework will help you to significantly reduce the amount of Java code that you normally need to access a relational database. iBATIS simply maps JavaBeans to SQL statements using a very simple XML descriptor.
The newest version!
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ibatis.spring;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.ibatis.client.Dialect;
import org.ibatis.client.SqlMapClient;
import org.ibatis.persist.criteria.CriteriaBuilder;
import org.ibatis.persist.criteria.CriteriaDelete;
import org.ibatis.persist.criteria.CriteriaQuery;
import org.ibatis.persist.criteria.CriteriaUpdate;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.jdbc.support.JdbcAccessor;
import org.springframework.util.Assert;
import com.ibatis.common.ArrayMap;
import com.ibatis.sqlmap.client.SqlMapExecutor;
import com.ibatis.sqlmap.client.SqlMapSession;
import com.ibatis.sqlmap.client.event.RowHandler;
/**
* Helper class that simplifies data access via the iBATIS {@link com.ibatis.sqlmap.client.SqlMapClient} API, converting
* checked SQLExceptions into unchecked DataAccessExceptions, following the org.springframework.dao
* exception hierarchy. Uses the same {@link org.springframework.jdbc.support.SQLExceptionTranslator} mechanism as
* {@link org.springframework.jdbc.core.JdbcTemplate}.
*
*
* The main method of this class executes a callback that implements a data access action. Furthermore, this class
* provides numerous convenience methods that mirror {@link com.ibatis.sqlmap.client.SqlMapExecutor}'s execution
* methods.
*
*
* It is generally recommended to use the convenience methods on this template for plain query/insert/update/delete
* operations. However, for more complex operations like batch updates, a custom SqlMapClientCallback must be
* implemented, usually as anonymous inner class. For example:
*
*
* getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
* public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
* executor.startBatch();
* executor.update("insertSomething", "myParamValue");
* executor.update("insertSomethingElse", "myOtherParamValue");
* executor.executeBatch();
* return null;
* }
* });
*
*
* The template needs a SqlMapClient to work on, passed in via the "sqlMapClient" property. A Spring context typically
* uses a {@link SqlMapClientFactoryBean} to build the SqlMapClient. The template an additionally be configured with a
* DataSource for fetching Connections, although this is not necessary if a DataSource is specified for the SqlMapClient
* itself (typically through SqlMapClientFactoryBean's "dataSource" property).
*
* @author Song Sun
*/
public class SqlMapClientTemplate extends JdbcAccessor implements SqlMapClientOperations {
private SqlMapClient sqlMapClient;
/**
* Create a new SqlMapClientTemplate.
*/
public SqlMapClientTemplate() {
}
/**
* Create a new SqlMapTemplate.
*
* @param sqlMapClient
* iBATIS SqlMapClient that defines the mapped statements
*/
public SqlMapClientTemplate(SqlMapClient sqlMapClient) {
setSqlMapClient(sqlMapClient);
afterPropertiesSet();
}
/**
* Create a new SqlMapTemplate.
*
* @param dataSource
* JDBC DataSource to obtain connections from
* @param sqlMapClient
* iBATIS SqlMapClient that defines the mapped statements
*/
public SqlMapClientTemplate(DataSource dataSource, SqlMapClient sqlMapClient) {
setDataSource(dataSource);
setSqlMapClient(sqlMapClient);
afterPropertiesSet();
}
/**
* Set the iBATIS Database Layer SqlMapClient that defines the mapped statements.
*/
public void setSqlMapClient(SqlMapClient sqlMapClient) {
this.sqlMapClient = sqlMapClient;
}
/**
* Return the iBATIS Database Layer SqlMapClient that this template works with.
*/
public SqlMapClient getSqlMapClient() {
return this.sqlMapClient;
}
/**
* If no DataSource specified, use SqlMapClient's DataSource.
*
* @see com.ibatis.sqlmap.client.SqlMapClient#getDataSource()
*/
@Override
public DataSource getDataSource() {
DataSource ds = super.getDataSource();
return (ds != null ? ds : this.sqlMapClient.getDataSource());
}
/*
* (non-Javadoc)
* @see org.springframework.jdbc.support.JdbcAccessor#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() {
if (this.sqlMapClient == null) {
throw new IllegalArgumentException("Property 'sqlMapClient' is required");
}
super.afterPropertiesSet();
}
/**
* Execute the given data access action on a SqlMapExecutor.
*
* @param action
* callback object that specifies the data access action
* @return a result object returned by the action, or null
* @throws DataAccessException
* in case of SQL Maps errors
*/
public T execute(SqlMapClientCallback action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Assert.notNull(this.sqlMapClient, "No SqlMapClient specified");
// We always need to use a SqlMapSession, as we need to pass a Spring-managed
// Connection (potentially transactional) in. This shouldn't be necessary if
// we run against a TransactionAwareDataSourceProxy underneath, but unfortunately
// we still need it to make iBATIS batch execution work properly: If iBATIS
// doesn't recognize an existing transaction, it automatically executes the
// batch for every single statement...
SqlMapSession session = this.sqlMapClient.openSession();
if (logger.isTraceEnabled()) {
logger.debug("Opened SqlMapSession [" + session + "] for iBATIS operation");
}
Connection ibatisCon = null;
try {
Connection springCon = null;
DataSource dataSource = getDataSource();
boolean transactionAware = (dataSource instanceof TransactionAwareDataSourceProxy);
// Obtain JDBC Connection to operate on...
try {
ibatisCon = session.getCurrentConnection();
if (ibatisCon == null) {
springCon = (transactionAware ? dataSource.getConnection()
: DataSourceUtils.doGetConnection(dataSource));
session.setUserConnection(springCon);
if (logger.isTraceEnabled()) {
logger.debug("Obtained JDBC Connection [" + springCon + "] for iBATIS operation");
}
} else {
if (logger.isTraceEnabled()) {
logger.debug("Reusing JDBC Connection [" + ibatisCon + "] for iBATIS operation");
}
}
} catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
}
// Execute given callback...
try {
return action.doInSqlMapClient(session);
} catch (SQLException ex) {
throw getExceptionTranslator().translate("SqlMapClient operation", null, ex);
} finally {
try {
if (springCon != null) {
if (transactionAware) {
springCon.close();
} else {
DataSourceUtils.doReleaseConnection(springCon, dataSource);
}
}
} catch (Throwable ex) {
logger.debug("Could not close JDBC Connection", ex);
}
}
// Processing finished - potentially session still to be closed.
} finally {
// Only close SqlMapSession if we know we've actually opened it
// at the present level.
if (ibatisCon == null) {
session.close();
}
}
}
/*
* (non-Javadoc)
* @see org.ibatis.spring.SqlMapClientOperations#queryForObject(java.lang.String)
*/
public T queryForObject(String id) throws DataAccessException {
return queryForObject(id, null);
}
/*
* (non-Javadoc)
* @see org.ibatis.spring.SqlMapClientOperations#queryForObject(java.lang.String, java.lang.Object)
*/
public T queryForObject(final String id, final Object parameterObject) throws DataAccessException {
return execute(new SqlMapClientCallback() {
public T doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
return executor.queryForObject(id, parameterObject);
}
});
}
/*
* (non-Javadoc)
* @see org.ibatis.spring.SqlMapClientOperations#queryForObject(java.lang.String, java.lang.Object, java.lang.Object)
*/
public T queryForObject(final String id, final Object parameterObject, final Object resultObject)
throws DataAccessException {
return execute(new SqlMapClientCallback() {
public T doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
return executor.queryForObject(id, parameterObject, resultObject);
}
});
}
/*
* (non-Javadoc)
* @see org.ibatis.spring.SqlMapClientOperations#queryForList(java.lang.String)
*/
public List queryForList(String id) throws DataAccessException {
return queryForList(id, null);
}
/*
* (non-Javadoc)
* @see org.ibatis.spring.SqlMapClientOperations#queryForList(java.lang.String, java.lang.Object)
*/
public List queryForList(final String id, final Object parameterObject) throws DataAccessException {
return execute(new SqlMapClientCallback>() {
public List doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
return executor.queryForList(id, parameterObject);
}
});
}
/*
* (non-Javadoc)
* @see org.ibatis.spring.SqlMapClientOperations#queryForList(java.lang.String, int, int)
*/
public List queryForList(String id, int skipResults, int maxResults) throws DataAccessException {
return queryForList(id, null, skipResults, maxResults);
}
/*
* (non-Javadoc)
* @see org.ibatis.spring.SqlMapClientOperations#queryForList(java.lang.String, java.lang.Object, int, int)
*/
public List queryForList(final String id, final Object parameterObject, final int skipResults,
final int maxResults) throws DataAccessException {
return execute(new SqlMapClientCallback>() {
public List doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
return executor.queryForList(id, parameterObject, skipResults, maxResults);
}
});
}
/*
* (non-Javadoc)
* @see org.ibatis.spring.SqlMapClientOperations#queryWithRowHandler(java.lang.String, com.ibatis.sqlmap.client.event.RowHandler)
*/
public void queryWithRowHandler(String id, RowHandler rowHandler) throws DataAccessException {
queryWithRowHandler(id, null, rowHandler);
}
/*
* (non-Javadoc)
* @see org.ibatis.spring.SqlMapClientOperations#queryWithRowHandler(java.lang.String, java.lang.Object, com.ibatis.sqlmap.client.event.RowHandler)
*/
public void queryWithRowHandler(final String id, final Object parameterObject, final RowHandler rowHandler)
throws DataAccessException {
execute(new SqlMapClientCallback