Spring的JDBC封裝,很大一部分就是借助Template模式實(shí)現(xiàn),它提供了一個(gè)優(yōu)秀的
JDBC模板庫,借助這個(gè)工具,我們可以簡單有效的對(duì)傳統(tǒng)的JDBC編碼方式加以改進(jìn)。
dbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'");
再對(duì)上面的例子進(jìn)行一些改進(jìn),通過PrepareStatement執(zhí)行update操作以避免SQL
njection 漏洞
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate
.update(
"UPDATE user SET age = ? WHERE id = ?",
new PreparedStatementSetter() {
public void setValues(PreparedStatementSetter ps)
throws SQLException {
ps.setInt(1, 18);
ps.setString(2, "erica");
}
}
)
可以看到,上面引用了update方法的另一個(gè)版本,傳入的參數(shù)有兩個(gè),第一個(gè)用于創(chuàng)建
PreparedStatement的SQL。第二個(gè)參數(shù)是為PreparedStatement設(shè)定參數(shù)的
PreparedStatementSetter。
第二個(gè)參數(shù)的使用方法比較獨(dú)到,我們動(dòng)態(tài)新建了一個(gè)PreparedStatementSetter類,
并實(shí)現(xiàn)了這個(gè)抽象類的setValues方法。之后將這個(gè)類的引用作為參數(shù)傳遞給update。
update接受參數(shù)之后,即可調(diào)用第二個(gè)參數(shù)提供的方法完成PreparedStatement的初始
化。
上面演示了update方法的使用(同樣的操作適用于update、insert、delete)。下面是
一個(gè)查詢的示例。
final List userList = new ArrayList();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate
.query(
"SELECT name, sex, address FROM user WHERE age > 18",
new RowCallbackHandler() {
public void processRow(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getString("name"));
user.setSex(rs.getString("sex"));
user.setAddress(rs.getString("address"));
userList.add(product);
}
}
)
下面我們通過已學(xué)習(xí)持的久性封裝知識(shí),繼續(xù)討論事務(wù)管理
為了實(shí)現(xiàn)數(shù)據(jù)操作的原子性,我們需要在程序中引入事務(wù)邏輯,在JdbcTemplate中引入
事務(wù)機(jī)制,在Spring中有兩種方式:
1. 代碼控制的事務(wù)管理
2. 參數(shù)化配置的事務(wù)管理
下面就這兩種方式進(jìn)行介紹。
代碼控制的事務(wù)管理
首先,進(jìn)行以下配置,假設(shè)配置文件為(Application-Context.xml)
(摘自開發(fā)指南:夏昕)
1、Application-Context.xml
<beans>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>net.sourceforge.jtds.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value>
</property>
<property name="username">
<value>test</value>
</property>
<property name="password">
<value>changeit</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransac
tionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="transactionManager">
<ref local="transactionManager" />
</property>
</bean>
</beans>
2、UserDAO
public class UserDAO {
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(PlatformTransactionManager
transactionManager) {
this.transactionManager = transactionManager;
}
public DataSource executeTestSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insertUser() {
TransactionTemplate tt =
new TransactionTemplate(getTransactionManager());
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update(
"insert into users (username) values ('xiaxin');");
jt.update(
"insert into users (id,username) values(2,
'erica');");
return null;
}
});
}
}
3、TestCase
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
UserDAO userDAO = (UserDAO) factory.getBean("userDAO");
userDAO.insertUser();
參數(shù)化配置的事務(wù)管理
在上面的Application-Context.xml增加一個(gè)事務(wù)代理(UserDAOProxy)配置,同時(shí),由于事務(wù)由容器管理,UserDAO不再需要TransactionManager設(shè)定,將其移除:
<bean id="UserDAOProxy"
class="org.springframework.transaction.interceptor.Transac
tionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
與之對(duì)應(yīng),UserDAO.insertUser的代碼修改如下:
public void insertUser(RegisterInfo regInfo) {
JdbcTemplate jt = new JdbcTemplate(executeTestSource());
jt.update("insert into users (username) values ('xiaxin');");
jt.update("insert into users (id,username) values (2,'erica');");
}
比上面簡單了很多吧!
測(cè)試代碼修改如下:
InputStream is = new FileInputStream("Application-Context.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
//注意這里須通過代理Bean"userDAOProxy"獲得引用,而不是直接getBean(“userDA
//此外這里還存在一個(gè)有關(guān)強(qiáng)制轉(zhuǎn)型的潛在問題,請(qǐng)參見Hibernate in Spring一節(jié)后
//關(guān)于強(qiáng)制轉(zhuǎn)型的補(bǔ)充描述。
UserDAO userDAO = (UserDAO) factory.getBean("userDAOProxy");
userDAO.insertUser();