Spring的持久化用於簡化數據的操作。
數據源
數據源有多種類型:JNDI、連接池、JDBC。
JNDI的配置方法。例子中使用Tomcat作爲Web容器。首先要在context.xml中加上下面這段代碼。
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="javauser" password="javadude" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/javatest"/>
重啓Tomcat之後就可以在應用中通過下面的配置直接訪問數據源了。
<jee:jndi-lookup id="dataSource" jndi-name="/jdbc/TestDB" resource-ref="true"/>
連接池配置。另外一種方法是使用數據庫連接池作爲數據源。一般比較主流的連接池爲Apache DBCP。它需要像下面這樣配置。
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/javatest"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="initialSize" value="5"/>
<property name="maxActive" value="10"/>
</bean>
JDBC配置。
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/javatest"/>
<property name="username" value="test"/>
<property name="password" value="test"/>
</bean>
JDBC模板
寫過JDBC程序的人都知道,異常處理部分佔據了很多代碼。爲了消滅這些樣板代碼,Spring提供了JDBC模板。
下面將通過例子介紹如何使用JdbcTemplate訪問數據。首先是bean的配置,創建一個全局的jdbcTemplate。
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
下面的例子演示了插入一行新數據的過程。
// 匿名參數
public void addUser(User user) {
jdbcTemplate.update("INSERT INTO user (username,password) VALUES (?,?)",
user.getUsername(),
user.getPassword());
}
// 命名參數
public void addUser(User user) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("username", user.getUsername());
params.put("password", user.getPassword());
jdbcTemplate.update("INSERT INTO user (username,password) VALUES (:username, :password)", params);
}
下面的例子演示了從數據庫中讀取數據的過程。其中RowMapper的作用是將一行數據轉換爲一個對象。
public List<User> getUserList() {
return jdbcTemplate.query(
"SELECT id,username,password FROM user",
new RowMapper<User>() {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getInt(1));
user.setUsername(rs.getNString(2));
user.setPassword(rs.getNString(3));
return user;
}
}
);
}
事務
Spring中的事務是通過專門的類來管理的,名爲TransactionManager。需要如下的bean配置。
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
配置完成之後就可以使用transactionManager執行事務了。下面是執行事務的例子。
public void test() {
transactionTemplate.execute(new TransactionCallback<Void>() {
public Void doInTransaction(TransactionStatus status) {
jdbcTemplate.update("INSERT INTO ...",x,y,z);
}
}
}
從代碼中可以看到transactionTemplate和jdbcTemplate是兩個普通的bean,我們沒有告訴它們之間的聯繫。那不禁要問,jdbcTemplate怎麼知道在不在事務中,在哪個transactionTemplate中?我查看了源代碼之後得出了結論。每個數據庫連接一次只能打開一個事務,所以jdbcTemplate只要獲取到transactionTemplate的數據庫連接即可,數據庫連接自帶事務管理。transactionTemplate在開始事務的時候會將當前的數據庫連接放入TransactionSynchronizationManager(TSM)中的ThreadLocal中。jdbcTemplate從TSM獲取當前的數據庫連接,即可提交SQL請求,事務由數據庫連接控制,jdbcTemplate無須考慮事務。