DataSource 注入


對於不同的資料連接來源需求,Spring提供了javax.sql.DataSource注入,更換資料來源只要在Bean定義檔中修改配置,而不用修改任何一行程式。

因應不同的系統,應用程式可能使用不同的資料來源,例如純綷的使用JDBC、透過連接池、或是透過JNDI等等,資料來源的更動是底層的行為,這些行為不 應影響到上層的業務邏輯,為此,您可以在需要取得連接來源的Bean物件上保留一個Datasource注入的操作介面, Spring提供org.springframework.jdbc.datasource.DriverManagerDataSource來取得它的 實例,DriverManagerDataSource實作了javax.sql.DataSource,您可以在Bean定義檔中這麼撰寫:
...
<beans>
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName">
            <value>com.mysql.jdbc.Driver</value>
        </property>
        <property name="url">
            <value>jdbc:mysql://localhost:3306/demo</value>
        </property>
        <property name="username">
            <value>caterpillar</value>
        </property>
        <property name="password">
            <value>123456</value>
        </property>
    </bean>
    ...
</beans>

其中"driverClassName"、"url"、"username"、"password"四個屬性分別用來設定JDBC驅動程式類別、資料庫URL協定、使用者名稱、密碼。

在這邊實際使用一個程式來作為DataSource注入的示範,並也示範一下之前有關於DAO介紹的實作,假設您定義了一個DAO的操作介面如下:
  • IUserDAO.java
package onlyfun.caterpillar;

public interface IUserDAO {
public void insert(User user);
public User find(Integer id);
}

這邊關於DAO的介面定義只有insert()與find()兩個方法。在這個介面中所使用到的User類別則如下定義:
  • User.java
package onlyfun.caterpillar;

public class User {
private Integer id;
private String name;
private Integer age;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
}

接著您可以定義一個UserDAO類別,它實作了IUserDAO介面,是實際進行資料庫存取服務的物件,如下所示:
  • UserDAO.java
package onlyfun.caterpillar;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

public class UserDAO implements IUserDAO {
private DataSource dataSource;

public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

public void insert(User user) {
String name = user.getName();
int age = user.getAge().intValue();

Connection conn = null;
Statement stmt = null;

try {
conn = dataSource.getConnection();
stmt = conn.createStatement();
stmt.execute("INSERT INTO user (name,age) "
+ "VALUES('" + name + "'," + age + ")");
} catch (SQLException e) {
e.printStackTrace();
}
finally {
if(stmt != null) {
try {
stmt.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
}
}

public User find(Integer id) {
Connection conn = null;
Statement stmt = null;

try {
conn = dataSource.getConnection();
stmt = conn.createStatement();

ResultSet result = stmt.executeQuery(
"SELECT * FROM user WHERE id=" + id.intValue());
if(result.next()) {
Integer i = new Integer(result.getInt(1));
String name = result.getString(2);
Integer age = new Integer(result.getInt(3));
// 封裝為 User 物件
User user = new User();
user.setId(i);
user.setName(name);
user.setAge(age);

return user;
}
} catch (SQLException e) {
e.printStackTrace();
}
finally {
if(stmt != null) {
try {
stmt.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
}

return null;
}
}

UserDAO類別上宣告了一個setDataSource()方法,可以讓您注入DataSource的實例,您可以在Bean定義檔中進行依賴注入的定義,如下所示:
  • beans-config.xml
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/demo</value>
</property>
<property name="username">
<value>caterpillar</value>
</property>
<property name="password">
<value>123456</value>
</property>
</bean>

<bean id="userDAO"
class="onlyfun.caterpillar.UserDAO">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
</beans>

可以撰寫一個簡單的測試程式來操作UserDAO的實例,看看是否能進行資料的儲存與查詢:
  • SpringDAODemo.java
package onlyfun.caterpillar;

import org.springframework.context.ApplicationContext;
import org.springframework.context.
support.FileSystemXmlApplicationContext;

public class SpringDAODemo {
public static void main(String[] args) {
ApplicationContext context =
new FileSystemXmlApplicationContext(
"beans-config.xml");

User user = new User();

user.setName("caterpillar");
user.setAge(new Integer(30));

IUserDAO userDAO =
(IUserDAO) context.getBean("userDAO");

userDAO.insert(user);

user = userDAO.find(new Integer(1));

System.out.println("name: " + user.getName());
}
}

在進行程式的測試之前,當然的您要先開啟資料庫服務,並將beans-config.xml中相關的驅動程式類別、資料庫URL、使用者名稱與密碼等修改為您的設定,在這邊我所使用的是MySQL資料庫,而我所建立的user表格是使用以下的SQL來建立的:
CREATE TABLE user (
    id INT(11) NOT NULL auto_increment PRIMARY KEY,
    name VARCHAR(100) NOT NULL default '',
    age INT
);

程式的執行結果會先在資料庫的user表格中存入一筆資料,接著根據id值查詢出先前所存入的資料,最後結果會顯示"name: caterpillar"的文字。

您需要spring-core.jar、spring-beans.jar、spring-context.jar、spring-dao.jar與 spring-jdbc.jar這幾個檔案,如果您使用的是spring.jar,當中已經包括了相關API,另外也需要相依的commons- logging.jar,當然,為了使用JDBC,您必須要有JDBC驅動程式的jar檔。