Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1884283
  • 博文数量: 606
  • 博客积分: 9991
  • 博客等级: 中将
  • 技术积分: 5725
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-17 19:07
文章分类

全部博文(606)

文章存档

2011年(10)

2010年(67)

2009年(155)

2008年(386)

分类: Java

2010-07-29 19:08:13

IBatis2中提供了3种DataSource的配置:JNDI, Apache DBCP, IBatis自带的SimpleDataSource。但在IBatis3中只提供了两种DataSource: UNPOOLED, POOLED。
如果要实现自定义的DataSource,就需要通过扩展DataSourceFactory。本文就演示一下这个过程。
准备工作:Connection Pool的选择,通过搜索发现目前比较流行的免费数据库连接池主要有3种:Apache DBCP, C3P0, Proxool。
看了一下,Proxool的最新版本是0.9.1(2008-08-23), C3P0的最新版本是0.9.1.2(2007-05-21), DBCP最新版本是1.2.2(2007-04-04)
好像这3个项目都已经挺长时间没有更新了。但是总体评价上C3P0无论从稳定上还是效率上都要好一点。
(具体这3个项目谁更优秀,并不是本文的重点,本文主要是介绍一下如何在IBatis3中自定义数据源)
大致步骤:
1、实现org.apache.ibatis.datasource.DataSourceFactory接口,主要是2个方法
a、public DataSource getDataSource() 如何具体地得到一个数据源
b、public void setProperties(Properties properties) 如何设置数据源的参数属性
2、实现javax.sql.DataSource,这个就是提供给DataSourceFactory的实例
3、在IBatis3中引用新加入的数据源

1. 从代码中可以看出,IBatis3与IBatis2不同,不再通过一个Configuration类来进行数据源属性的设置,而是使用反射机制直接调用数据源的方法来设置参数。
这就要求配置文件中的参数名称必须与数据源类中的方法名匹配.

ProxoolDataSourceFactory.java
 

package com.xuanwu.ibatis;

import java.util.Properties;

import javax.sql.DataSource;

import org.apache.ibatis.datasource.DataSourceException;
import org.apache.ibatis.datasource.DataSourceFactory;
import org.apache.ibatis.reflection.MetaObject;

/**
 * fisher 2010-7-14 下午06:18:16
 *
 * Proxool数据源连接池工厂
 *
 * @see http://www.blogjava.net/usherlight/archive/2010/02/01/311493.html
 *
 */

public class ProxoolDataSourceFactory implements DataSourceFactory {

    private DataSource dataSource;

    public ProxoolDataSourceFactory() {
        dataSource = new ProxoolDataSourceWrap();
    }

    public DataSource getDataSource() {
        return dataSource;
    }

    /**
     * IBatis3与IBatis2不同,不再通过一个Configuration类来进行数据源属性的设置,
     * 而是使用反射机制直接调用数据源的方法来设置参数。
     */

    public void setProperties(Properties properties) {
        Properties driverProperties = new Properties();
        MetaObject metaDataSource = MetaObject.forObject(dataSource);
        for (Object key : properties.keySet()) {
            String propertyName = (String) key;
            if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {
                String value = properties.getProperty(propertyName);
                driverProperties.setProperty(propertyName
                        .substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);
            } else if (metaDataSource.hasSetter(propertyName)) {
                String value = (String) properties.get(propertyName);
                Object convertedValue = convertValue(metaDataSource,
                        propertyName, value);
                metaDataSource.setValue(propertyName, convertedValue);
            } else {
                throw new DataSourceException("Unkown DataSource property: "
                        + propertyName);
            }
        }
        if (driverProperties.size() > 0) {
            metaDataSource.setValue("driverProperties", driverProperties);
        }
    }

    @SuppressWarnings("unchecked")
    private Object convertValue(MetaObject metaDataSource, String propertyName,
            String value) {
        Object convertedValue = value;
        Class targetType = metaDataSource.getSetterType(propertyName);
        if (targetType == Integer.class || targetType == int.class) {
            convertedValue = Integer.valueOf(value);
        } else if (targetType == Long.class || targetType == long.class) {
            convertedValue = Long.valueOf(value);
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            convertedValue = Boolean.valueOf(value);
        }
        return convertedValue;
    }

    private static final String DRIVER_PROPERTY_PREFIX = "driver.";
    private static final int DRIVER_PROPERTY_PREFIX_LENGTH = DRIVER_PROPERTY_PREFIX
            .length();

}

2. 数据源类,其中的一堆setter就是用于设置属性的。
ProxoolDataSourceWrap.java


 

package com.xuanwu.ibatis;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.logicalcobwebs.proxool.ProxoolDataSource;

/**
 * fisher 2010-7-14 下午06:18:16
 *
 * 数据源配置。配置文件xml上dataSource设置的属性与连接池对应桥梁。
 *
 * @see http://www.blogjava.net/usherlight/archive/2010/02/01/311493.html
 */

public class ProxoolDataSourceWrap implements DataSource {
    
    private ProxoolDataSource dataSource;

    public ProxoolDataSourceWrap() {
        this.dataSource = new ProxoolDataSource();
    }

    public Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public Connection getConnection(String username, String password)
            throws SQLException {
        return dataSource.getConnection(username, password);
    }

    public PrintWriter getLogWriter() throws SQLException {
        return dataSource.getLogWriter();
    }

    public int getLoginTimeout() throws SQLException {
        return dataSource.getLoginTimeout();
    }

    public void setLogWriter(PrintWriter out) throws SQLException {
        dataSource.setLogWriter(out);
    }

    public void setLoginTimeout(int seconds) throws SQLException {
        dataSource.setLoginTimeout(seconds);
    }

    /** 以下setter,对应ibatis-config.xml dataSource下的property **/
    //    

    //        

    //        

    //        

    //        

    //        ...............

    //    

    /** ProxoolDataSource setter源码 **/
    // cpd.setAlias(getAlias());

    // cpd.setDriver(getDriver());

    // cpd.setFatalSqlExceptionsAsString(getFatalSqlExceptionsAsString());

    // cpd.setFatalSqlExceptionWrapper(getFatalSqlExceptionWrapperClass());

    // cpd.setHouseKeepingSleepTime(getHouseKeepingSleepTime());

    // cpd.setHouseKeepingTestSql(getHouseKeepingTestSql());

    // cpd.setMaximumActiveTime(getMaximumActiveTime());

    // cpd.setMaximumConnectionCount(getMaximumConnectionCount());

    // cpd.setMaximumConnectionLifetime(getMaximumConnectionLifetime());

    // cpd.setMinimumConnectionCount(getMinimumConnectionCount());

    // cpd.setOverloadWithoutRefusalLifetime(getOverloadWithoutRefusalLifetime());

    // cpd.setPrototypeCount(getPrototypeCount());

    // cpd.setRecentlyStartedThreshold(getRecentlyStartedThreshold());

    // cpd.setSimultaneousBuildThrottle(getSimultaneousBuildThrottle());

    // cpd.setStatistics(getStatistics());

    // cpd.setStatisticsLogLevel(getStatisticsLogLevel());

    // cpd.setTrace(isTrace());

    // cpd.setUrl(getDriverUrl());

    // cpd.setVerbose(isVerbose());

    // cpd.setJmx(isJmx());

    // cpd.setJmxAgentId(getJmxAgentId());

    // cpd.setTestAfterUse(isTestAfterUse());

    // cpd.setTestBeforeUse(isTestBeforeUse());

    // cpd.setDelegateProperties(this.delegateProperties);

    // cpd.setUser(getUser());

    // cpd.setPassword(getPassword());

    

    public void setAlias(String alias) {
        dataSource.setAlias(alias);
    }
    
    public synchronized void setDriver(String driver) {
        try {
            dataSource.setDriver(driver);
        } catch (Exception e) {
        }
    }

    public void setFatalSqlExceptionsAsString(String fatalSqlExceptionsAsString) {
        dataSource.setFatalSqlExceptionsAsString(fatalSqlExceptionsAsString);
    }

    public void setHouseKeepingSleepTime(int houseKeepingSleepTime) {
        dataSource.setHouseKeepingSleepTime(houseKeepingSleepTime);
    }

    public void setHouseKeepingTestSql(String houseKeepingTestSql) {
        dataSource.setHouseKeepingTestSql(houseKeepingTestSql);
    }

    public void setMaximumActiveTime(int maximumActiveTime) {
        dataSource.setMaximumActiveTime(maximumActiveTime);
    }

    public void setMaximumConnectionCount(int maximumConnectionCount) {
        dataSource.setMaximumConnectionCount(maximumConnectionCount);
    }

    public void setMaximumConnectionLifetime(int maximumConnectionLifetime) {
        dataSource.setMaximumConnectionLifetime(maximumConnectionLifetime);
    }

    public void setMinimumConnectionCount(int minimumConnectionCount) {
        dataSource.setMinimumConnectionCount(minimumConnectionCount);
    }

    public void setOverloadWithoutRefusalLifetime(int overloadWithoutRefusalLifetime) {
        dataSource.setOverloadWithoutRefusalLifetime(overloadWithoutRefusalLifetime);
    }

    public void setPrototypeCount(int prototypeCount) {
        dataSource.setPrototypeCount(prototypeCount);
    }

    public void setRecentlyStartedThreshold(int recentlyStartedThreshold) {
        dataSource.setRecentlyStartedThreshold(recentlyStartedThreshold);
    }

    public void setSimultaneousBuildThrottle(int simultaneousBuildThrottle) {
        dataSource.setSimultaneousBuildThrottle(simultaneousBuildThrottle);
    }

    public void setStatistics(String statistics) {
        dataSource.setStatistics(statistics);
    }

    public void setStatisticsLogLevel(String statisticsLogLevel) {
        dataSource.setStatisticsLogLevel(statisticsLogLevel);
    }

    public void setTrace(boolean trace) {
        dataSource.setTrace(trace);
    }

    public void setUrl(String url) {
        dataSource.setDriverUrl(url);
    }

    public void setVerbose(boolean verbose) {
        dataSource.setVerbose(verbose);
    }

    public void setJmx(boolean jmx) {
        dataSource.setJmx(jmx);
    }

    public void setJmxAgentId(String jmxAgentId) {
        dataSource.setJmxAgentId(jmxAgentId);
    }

    public void setTestAfterUse(boolean testAfterUse) {
        dataSource.setTestAfterUse(testAfterUse);
    }

    public void setTestBeforeUse(boolean testBeforeUse) {
        dataSource.setTestBeforeUse(testBeforeUse);
    }

    public void setDelegateProperties(String delegateProperties) {
        dataSource.setDelegateProperties(delegateProperties);
    }

    public void setUser(String user) {
        dataSource.setUser(user);
    }

    public void setPassword(String password) {
        dataSource.setPassword(password);
    }

    public void setUsername(String username) {
        dataSource.setUser(username);
    }
}


3. 在配置文件Configuration.xml中,可以先定义数据源的别称,然后就象POOLED和UNPOOLED一样使用别称来引用数据源。

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
  "">
<configuration>
    <properties resource="conf/jdbc-development.properties" />
    <settings>
        <setting name="cacheEnabled" value="false"/>
    </settings>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="conf/ibatis/ibatis-base-mapper.xml"/>
        <mapper resource="conf/ibatis/ibatis-difmnetmt-mapper.xml"/>
        <mapper resource="conf/ibatis/ibatis-test-mapper.xml"/>
    </mappers>
</configuration>

 

相关资料:

1. iBatis官网用户手册:

2. IBatis3中使用自定义数据源C3P0http://www.blogjava.net/usherlight/archive/2010/02/01/311493.html

3. 在ibatis2中使用proxool数据源http://wt8414.javaeye.com/blog/514824

4. spring配置ibatis的jdbc方式和proxool、c3p0连接池方式http://www.blogjava.net/landor2004/archive/2009/07/01/284978.html

阅读(1899) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~