SPRING 整合IBATIS或者hibernate等持久数据层流程与实现

本文详细介绍了Spring如何整合IBATIS,包括SqlMapClientTemplate的使用和分析,以及Spring管理SqlMapClient的过程。通过SqlMapClientTemplate进行数据库CRUD操作,并探讨了与Hibernate整合的相似之处。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SPRING 整合IBATIS或者hibernate等持久数据层流程与实现

一、首先引用网上对spring整合的概述

Spring通过DAO模式,提供了对iBATIS的良好支持。SqlMapClient对象是iBATIS中的主要对象,我们可以通过配置让spring来管理SqlMapClient对象的创建。
与hibernate类似,Spring提供了SqlMapClientDaoSupport对象,我们的DAO可以继承这个类,通过它所提供的SqlMapClientTemplate对象来操纵数据库。看起来这些概念都与hibernate类似。
通过SqlMapClientTemplate来操纵数据库的CRUD是没有问题的。

我们本地使用IBATIS 大概流程就是这样:

1、通过实例化sqlMapConfig,这个对象;
eg:

    <bean id= "sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean" >
               <property name= "configLocations">
                      <list>
                            <value> classpath:sqlmap-config.xml</value >
                            <value> classpath:sqlmap-process-config.xml</value >
                      </list>
               </property>
        </bean>

2、实例化sqlmap-config.xml文件后,使用里面包含字节IBATIS的命名空间与SQL

<sqlMapConfig>
    <settings cacheModelsEnabled= "true" enhancementEnabled ="true"
    lazyLoadingEnabled="false" errorTracingEnabled= "true" maxRequests ="32"
    maxSessions="10" maxTransactions= "5" useStatementNamespaces ="true" />
       <sqlMap resource= "sqlmap/Source.xml"/>
</sqlMapConfig>

3、用户执行sql语句时,我们的dao会继承SqlMapClientTemplate,然
public class BaseDao extends SqlMapClientTemplate {

   @Override
public T find(PK id) {
return (T) super.queryForObject(getNameSpace() + ".FIND-BY-ID", id);
}
@Overrpublic PK save(T t) { return (PK) super.insert(getNameSpace() + ".SAVE", t); }  ......
.....

}以直接使用对应的SQL语句了;

二、SqlMapClientTemplate分析

1、打开SqlMapClientTemplate的源码:

/*
 * Copyright 2002-2007 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.springframework.orm.ibatis;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import com.ibatis.common.util.PaginatedList;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapExecutor;
import com.ibatis.sqlmap.client.SqlMapSession;
import com.ibatis.sqlmap.client.event.RowHandler;
import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;

import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
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;

/**
 * Helper class that simplifies data access via the iBATIS
 * {@link com.ibatis.sqlmap.client.SqlMapClient} API, converting checked
 * SQLExceptions into unchecked DataAccessExceptions, following the
 * <code>org.springframework.dao</code> exception hierarchy.
 * Uses the same {@link org.springframework.jdbc.support.SQLExceptionTranslator}
 * mechanism as {@link org.springframework.jdbc.core.JdbcTemplate}.
 *
 * <p>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.
 *
 * <p>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:
 *
 * <pre class="code">
 * 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;
 *   }
 * });</pre>
 *
 * 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 Juergen Hoeller
 * @since 24.02.2004
 * @see #execute
 * @see #setSqlMapClient
 * @see #setDataSource
 * @see #setExceptionTranslator
 * @see SqlMapClientFactoryBean#setDataSource
 * @see com.ibatis.sqlmap.client.SqlMapClient#getDataSource
 * @see com.ibatis.sqlmap.client.SqlMapExecutor
 */
public class SqlMapClientTemplate extends JdbcAccessor implements SqlMapClientOperations {

    private SqlMapClient sqlMapClient;

    private boolean lazyLoadingAvailable = true;


    /**
     * 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()
     */
    public DataSource getDataSource() {
        DataSource ds = super.getDataSource();
        return (ds != null ? ds : this.sqlMapClient.getDataSource());
    }

    public void afterPropertiesSet() {
        if (this.sqlMapClient == null) {
            throw new IllegalArgumentException("Property 'sqlMapClient' is required");
        }
        if (this.sqlMapClient instanceof ExtendedSqlMapClient) {
            // Check whether iBATIS lazy loading is available, that is,
            // whether a DataSource was specified on the SqlMapClient itself.
            this.lazyLoadingAvailable = (((ExtendedSqlMapClient) this.sqlMapClient).getDelegate().getTxManager() != null);
        }
        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 <code>null</code>
     * @throws DataAccessException in case of SQL Maps errors
     */
    public Object execute(SqlMapClientCallback action) throws DataAccessException {
        Assert.notNull(action, "Callback object must not be null");
        Assert.notNull(this.sqlMapClient, "No SqlMapClient specified");

        // We always needs 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.isDebugEnabled()) {
            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.isDebugEnabled()) {
                        logger.debug("Obtained JDBC Connection [" + springCon + "] for iBATIS operation");
                    }
                }
                else {
                    if (logger.isDebugEnabled()) {
                        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();
            }
        }
    }

    /**
     * Execute the given data access action on a SqlMapExecutor,
     * expecting a List result.
     * @param action callback object that specifies the data access action
     * @return the List result
     * @throws DataAccessException in case of SQL Maps errors
     */
    public List executeWithListResult(SqlMapClientCallback action) throws DataAccessException {
        return (List) execute(action);
    }

    /**
     * Execute the given data access action on a SqlMapExecutor,
     * expecting a Map result.
     * @param action callback object that specifies the data access action
     * @return the Map result
     * @throws DataAccessException in case of SQL Maps errors
     */
    public Map executeWithMapResult(SqlMapClientCallback action) throws DataAccessException {
        return (Map) execute(action);
    }


    public Object queryForObject(String statementName) throws DataAccessException {
        return queryForObject(statementName, null);
    }

    public Object queryForObject(final String statementName, final Object parameterObject)
            throws DataAccessException {

        return execute(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForObject(statementName, parameterObject);
            }
        });
    }

    public Object queryForObject(
            final String statementName, final Object parameterObject, final Object resultObject)
            throws DataAccessException {

        return execute(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForObject(statementName, parameterObject, resultObject);
            }
        });
    }

    public List queryForList(String statementName) throws DataAccessException {
        return queryForList(statementName, null);
    }

    public List queryForList(final String statementName, final Object parameterObject)
            throws DataAccessException {

        return executeWithListResult(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForList(statementName, parameterObject);
            }
        });
    }

    public List queryForList(String statementName, int skipResults, int maxResults)
            throws DataAccessException {

        return queryForList(statementName, null, skipResults, maxResults);
    }

    public List queryForList(
            final String statementName, final Object parameterObject, final int skipResults, final int maxResults)
            throws DataAccessException {

        return executeWithListResult(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForList(statementName, parameterObject, skipResults, maxResults);
            }
        });
    }

    public void queryWithRowHandler(String statementName, RowHandler rowHandler)
            throws DataAccessException {

        queryWithRowHandler(statementName, null, rowHandler);
    }

    public void queryWithRowHandler(
            final String statementName, final Object parameterObject, final RowHandler rowHandler)
            throws DataAccessException {

        execute(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                executor.queryWithRowHandler(statementName, parameterObject, rowHandler);
                return null;
            }
        });
    }

    /**
     * @deprecated as of iBATIS 2.3.0
     */
    public PaginatedList queryForPaginatedList(String statementName, int pageSize)
            throws DataAccessException {

        return queryForPaginatedList(statementName, null, pageSize);
    }

    /**
     * @deprecated as of iBATIS 2.3.0
     */
    public PaginatedList queryForPaginatedList(
            final String statementName, final Object parameterObject, final int pageSize)
            throws DataAccessException {

        // Throw exception if lazy loading will not work.
        if (!this.lazyLoadingAvailable) {
            throw new InvalidDataAccessApiUsageException(
                    "SqlMapClient needs to have DataSource to allow for lazy loading" +
                    " - specify SqlMapClientFactoryBean's 'dataSource' property");
        }

        return (PaginatedList) execute(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForPaginatedList(statementName, parameterObject, pageSize);
            }
        });
    }

    public Map queryForMap(
            final String statementName, final Object parameterObject, final String keyProperty)
            throws DataAccessException {

        return executeWithMapResult(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForMap(statementName, parameterObject, keyProperty);
            }
        });
    }

    public Map queryForMap(
            final String statementName, final Object parameterObject, final String keyProperty, final String valueProperty)
            throws DataAccessException {

        return executeWithMapResult(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForMap(statementName, parameterObject, keyProperty, valueProperty);
            }
        });
    }

    public Object insert(String statementName) throws DataAccessException {
        return insert(statementName, null);
    }

    public Object insert(final String statementName, final Object parameterObject)
            throws DataAccessException {

        return execute(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.insert(statementName, parameterObject);
            }
        });
    }

    public int update(String statementName) throws DataAccessException {
        return update(statementName, null);
    }

    public int update(final String statementName, final Object parameterObject)
            throws DataAccessException {

        Integer result = (Integer) execute(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return new Integer(executor.update(statementName, parameterObject));
            }
        });
        return result.intValue();
    }

    public void update(String statementName, Object parameterObject, int requiredRowsAffected)
            throws DataAccessException {

        int actualRowsAffected = update(statementName, parameterObject);
        if (actualRowsAffected != requiredRowsAffected) {
            throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(
                    statementName, requiredRowsAffected, actualRowsAffected);
        }
    }

    public int delete(String statementName) throws DataAccessException {
        return delete(statementName, null);
    }

    public int delete(final String statementName, final Object parameterObject)
            throws DataAccessException {

        Integer result = (Integer) execute(new SqlMapClientCallback() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return new Integer(executor.delete(statementName, parameterObject));
            }
        });
        return result.intValue();
    }

    public void delete(String statementName, Object parameterObject, int requiredRowsAffected)
            throws DataAccessException {

        int actualRowsAffected = delete(statementName, parameterObject);
        if (actualRowsAffected != requiredRowsAffected) {
            throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(
                    statementName, requiredRowsAffected, actualRowsAffected);
        }
    }

}

1、在在基类JdbcAccessor的设计中,我们可以通过源码进入,看到里面主要是在对DataSource数据源进行管理和配置,也就是我们平常配置的 dataSource;
2、在接口SqlMapClientOperations中,主要声明了我们可以通过ibatis操作数据库的基本操作方法。比如我们常用的:
Object queryForObject(String statementName) throws DataAccessException;

/**
 * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForObject(String, Object)
 * @throws org.springframework.dao.DataAccessException in case of errors
 */
Object queryForObject(String statementName, Object parameterObject)
        throws DataAccessException;

/**
 * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForObject(String, Object, Object)
 * @throws org.springframework.dao.DataAccessException in case of errors
 */
Object queryForObject(String statementName, Object parameterObject, Object resultObject)
        throws DataAccessException;

/**
 * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForList(String)
 * @throws org.springframework.dao.DataAccessException in case of errors
 */
List queryForList(String statementName) throws DataAccessException;

3、类SqlMapClientTemplate就是集成了对IBATIS语法与处理的实现类;

注:我们刚才说了就是 JdbcAccessor用来管理dataSource 在SqlMapClient中也存在一个dataSource ,通过上面的源码我们可以看到,在初始化SqlMapClientTemplate的时候,会判断如果SqlMapClient已经注入了就是用已经SqlMapClient里面的数据,如果没有 就在bean里面进行查找;

三、总结

在spring整合对应持久化数据层的时候,应该都会有个支持对应组件的类来实现对其的操作,比如 hibernate 的

public class HibernateTemplate extends HibernateAccessor implements HibernateOperations

这个类是spring集成hibernate 的类,看结构与SqlMapClientTemplate几乎一致;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值