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类来进行数据源属性的设置,而是使用反射机制直接调用数据源的方法来设置参数。
这就要求配置文件中的参数名称必须与数据源类中的方法名匹配.
1 public class C3p0DataSourceFactory implements DataSourceFactory {
2
3 private DataSource dataSource;
4
5 public C3p0DataSourceFactory() {
6 dataSource = new C3p0DataSource();
7 }
8
9 public DataSource getDataSource() {
10 return dataSource;
11 }
12
13 public void setProperties(Properties properties) {
14 Properties driverProperties = new Properties();
15 MetaObject metaDataSource = MetaObject.forObject(dataSource);
16 for (Object key : properties.keySet()) {
17 String propertyName = (String) key;
18 if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {
19 String value = properties.getProperty(propertyName);
20 driverProperties.setProperty(propertyName
21 .substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);
22 } else if (metaDataSource.hasSetter(propertyName)) {
23 String value = (String) properties.get(propertyName);
24 Object convertedValue = convertValue(metaDataSource,
25 propertyName, value);
26 metaDataSource.setValue(propertyName, convertedValue);
27 } else {
28 throw new DataSourceException("Unkown DataSource property: "
29 + propertyName);
30 }
31 }
32 if (driverProperties.size() > 0) {
33 metaDataSource.setValue("driverProperties", driverProperties);
34 }
35 }
36
37 @SuppressWarnings("unchecked")
38 private Object convertValue(MetaObject metaDataSource, String propertyName,
39 String value) {
40 Object convertedValue = value;
41 Class targetType = metaDataSource.getSetterType(propertyName);
42 if (targetType == Integer.class || targetType == int.class) {
43 convertedValue = Integer.valueOf(value);
44 } else if (targetType == Long.class || targetType == long.class) {
45 convertedValue = Long.valueOf(value);
46 } else if (targetType == Boolean.class || targetType == boolean.class) {
47 convertedValue = Boolean.valueOf(value);
48 }
49 return convertedValue;
50 }
51
52 private static final String DRIVER_PROPERTY_PREFIX = "driver.";
53 private static final int DRIVER_PROPERTY_PREFIX_LENGTH = DRIVER_PROPERTY_PREFIX
54 .length();
55
56 }
57
2. 数据源类,其中的一堆setter就是用于设置属性的。
1 public class C3p0DataSource implements DataSource {
2
3 private ComboPooledDataSource dataSource;
4 public C3p0DataSource() {
5 this.dataSource = new ComboPooledDataSource();
6 }
7
8 public Connection getConnection() throws SQLException {
9 return dataSource.getConnection();
10 }
11
12 public Connection getConnection(String username, String password)
13 throws SQLException {
14 return dataSource.getConnection(username, password);
15 }
16
17 public PrintWriter getLogWriter() throws SQLException {
18 return dataSource.getLogWriter();
19 }
20
21 public int getLoginTimeout() throws SQLException {
22 return dataSource.getLoginTimeout();
23 }
24
25 public void setLogWriter(PrintWriter out) throws SQLException {
26 dataSource.setLogWriter(out);
27 }
28
29 public void setLoginTimeout(int seconds) throws SQLException {
30 dataSource.setLoginTimeout(seconds);
31 }
32
33
34 public synchronized void setDriver(String driver) {
35 try {
36 dataSource.setDriverClass(driver);
37 } catch (Exception e) {
38 }
39 }
40
41 public void setUrl(String url) {
42 dataSource.setJdbcUrl(url);
43 }
44
45 public void setUsername(String username) {
46 dataSource.setUser(username);
47 }
48
49 public void setPassword(String password) {
50 dataSource.setPassword(password);
51 }
52
53 public void setInitialPoolSize(int initialPoolSize) {
54 dataSource.setInitialPoolSize(initialPoolSize);
55 }
56
57 public void setMaxPoolSize(int maxPoolSize) {
58 dataSource.setMaxPoolSize(maxPoolSize);
59 }
60
61 public void setMinPoolSize(int minPoolSize) {
62 dataSource.setMinPoolSize(minPoolSize);
63 }
64
65 public void setPreferredTestQuery(String preferredTestQuery) {
66 dataSource.setPreferredTestQuery(preferredTestQuery);
67 }
68
69 public void setPoolPingQuery(String poolPingQuery) {
70 dataSource.setPreferredTestQuery(poolPingQuery);
71 }
72 }
3. 在配置文件Configuration.xml中,可以先定义数据源的别称,然后就象POOLED和UNPOOLED一样使用别称来引用数据源。
<Configuration>
...
<typeAlias>
<typeAlias type="com.test.datasource.C3p0DataSourceFactory" alias="C3P0"/>
</typeAlias>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="C3P0">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="poolPingQuery" value="${pingquery}"/>
</dataSource>
</environment>
</environments>
...
<Configuration>