20. Spring 2.0 良信林(冊手術技 – http://openhome.cc )
JdbcTemplateDemo UserDAO.java
package onlyfun.caterpillar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class UserDAO implements IUserDAO {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
public void insert(User user) {
String name = user.getName();
int age = user.getAge().intValue();
jdbcTemplate.update("INSERT INTO user (name,age) "
+ "VALUES('" + name + "'," + age + ")");
}
public User find(Integer id) {
List rows = jdbcTemplate.queryForList(
"SELECT * FROM user WHERE id=" + id.intValue());
Iterator it = rows.iterator();
if(it.hasNext()) {
Map userMap = (Map) it.next();
Integer i = new Integer(userMap.get("id").toString());
String name = userMap.get("name").toString();
Integer age =
new Integer(userMap.get("age").toString());
User user = new User();
user.setId(i);
user.setName(name);
user.setAge(age);
2
25. Chapter 5 JDBC 援支易交、
package org.springframework.jdbc.core;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public interface BatchPreparedStatementSetter {
void setValues(PreparedStatement ps,
int i) throws SQLException;
int getBatchSize();
}
在以可 如例 JdbcTemplateDemo 及面介 的中 案 專
IUserDAO UserDAO
個一加增上別類 insertUsers() : 容 內 的 下 以 是 像 ,作 實 與 義 定 的 法 方
...
public int[] insertUsers(final List users) {
String sql = "INSERT INTO user (name,age) VALUES(?,?)";
BatchPreparedStatementSetter setter =
new BatchPreparedStatementSetter() {
public void setValues(
PreparedStatement ps, int i) throws SQLException {
User user = (User) users.get(i);
ps.setString(1, user.getName());
ps.setInt(2, user.getAge().intValue());
}
public int getBatchSize() {
return users.size();
}
};
return jdbcTemplate.batchUpdate(sql, setter);
}
...
果如 JDBC 果如 , 能 功 的 它 用 使 接直則 , 話 的 理 處 次 批 援 支 式 程 動 驅
則,援支不 Spring 。 理 處 次 批 擬 模以新 更 理 處 個 一 個 一 動 自 會
2
26. Spring 2.0 良信林(冊手術技 – http://openhome.cc )
5.2.3 JdbcTemplate 查詢
用使 JdbcTemplate 用使以可,時詢查行進 queryForXXX() ,法方等
用使如例 queryForInt() :數筆料資的中格表 回傳法方
user
jdbcTemplate.queryForInt("SELECT COUNT(*) FROM user");
用使以可也 queryForObject() 回傳 如 例 , 件 物 果 結 的 後 詢 查 個 一 回 傳
:件物 個一
String
String name = (String) jdbcTemplate.queryForObject(
"SELECT name FROM USER WHERE id = ?",
new Object[] {id},
java.lang.String.class);
使以可則,料資筆多回傳果如,料資筆一單是都的回傳子例個兩面上
:如例,法方
queryForList() 用
List rows = jdbcTemplate.queryForList(
"SELECT * FROM user WHERE id=" + id.intValue());
的中果結詢查表代件物 個每,件物 是的括包中 的回傳
List Map Map
位欄用使要,值的中位欄得取要,容內位欄個多括包料資筆每,料資筆一
" :如例, ) (鍵 為作稱名
K ey "
...
Iterator it = rows.iterator();
while(it.hasNext()) {
Map userMap = (Map) it.next();
System.out.println(userMap.get("id"));
System.out.println(userMap.get("name"));
System.out.println(userMap.get("age"));
...
}
...
26
27. Chapter 5 JDBC 援支易交、
作實以可您
org.springframework.jdbc.core.RowCallbackHandler 介
下一改修如例,回傳再理處些一作先後之料資到詢查在,面 5.2.1 的
在,下如法方 的
JdbcTemplateDemo中案專 UserDAO find() RowCallback-
(
Handler 的單簡作實中法方 的
processRow() ORM O bject-Relational
Mapping :作動)
...
public User find(Integer id) {
final User user = new User();
jdbcTemplate.query(
"SELECT * FROM user WHERE id = ?",
new Object[] {id},
new RowCallbackHandler() {
public void processRow(ResultSet rs)
throws SQLException {
user.setId(new Integer(rs.getInt("id")));
user.setName(rs.getString("name"));
user.setAge(new Integer(rs.getInt("age")));
}
});
return user;
}
...
作實先以可則,件物的果結詢查多很回取要次一果如 org.springframe-
:如例,面介
work.jdbc.core.RowMapper
package onlyfun.caterpillar;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
public class UserRowMapper implements RowMapper {
public Object mapRow(ResultSet rs,
27
28. Spring 2.0 良信林(冊手術技 – http://openhome.cc )
int rowNum) throws SQLException {
User user = new User();
user.setId(new Integer(rs.getInt("id")));
user.setName(rs.getString("name"));
user.setAge(new Integer(rs.getInt("age")));
return user;
}
}
在 Spring 2.0 ,中 詢查,除移被經已別類作實其與面介
R esultReader
受接接直在現法方 RowMapper :時法方 用使如例,例實
queryForObject()
...
public User find(Integer id) {
User user = (User) jdbcTemplate.queryForObject(
"select * from user where id=?",
new Object[] {id},
new UserRowMapper());
return user;
}
...
用使已果結的回傳 UserRowMapper 為裝封之將,義定的 User 。件 物
:範示個一的時法方 用使是下以
query()
List users = jdbcTemplate.query("select * from user",
new UserRowMapper());
for(int i = 0; i < users.size(); i++) {
User user = (User) users.get(i);
System.out.println("tId:t" + user.getId());
System.out.println("tName:t" + user.getName());
System.out.println("tAge:n" + user.getAge());
}
28
29. Chapter 5 JDBC 援支易交、
為 裝封 已 並,果 結 的 來出詢 查 中 庫 料 資 從 了 括 包,中 件 物 的 回 傳
List
User 。例實的別類
5.2.4 JdbcTemplate 的 Lob 支援
( 與
J DBC) ( 用使以可中 在
C lob C haracter large object B lob B inary large
透以可中
object 。存儲行進案檔位進二與案檔字文對針別分以,) S pring
如 例(庫 料 資 定 特 理 處 免 避 以 ,
JdbcTemplate 與
CLOB 理處來
BLOB 過
資 的 您 設 假 , 說 來 子 例 個 舉 。 題 問 異 差 、 的)
Oracle 9i Clob B lob MySQL
:下如格表庫料
CREATE TABLE test (
id INT AUTO_INCREMENT PRIMARY,
txt TEXT,
image BLOB
);
料資至存儲之將想並,案檔位進二與案檔字文個一進讀別分在現設假
:如例, 用使以可則,中庫
JdbcTemplate
final File binaryFile = new File("wish.jpg");
final File txtFile = new File("test.txt");
final InputStream is = new FileInputStream(binaryFile);
final Reader reader = new FileReader(txtFile);
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
final LobHandler lobHandler = new DefaultLobHandler();
jdbcTemplate.execute("INSERT INTO test (txt, image) VALUES(?, ?)",
new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
protected void setValues(PreparedStatement pstmt,
LobCreator lobCreator) throws SQLException,DataAccessException {
lobCreator.setClobAsCharacterStream(
pstmt, 1, reader, (int) txtFile.length());
2
30. Spring 2.0 良信林(冊手術技 – http://openhome.cc )
lobCreator.setBlobAsBinaryStream(
pstmt, 2, is, (int) binaryFile.length());
}
});
reader.close();
is.close();
,時件物 立建在
AbstractLobCreatingPreparedStatementCallback
或 ( 於對,例實
LobHandler 個一遞傳要 MySQL M S SQL Server Oracle
的定特
10g 於對,可即 用使邊這,)
DefaultLobHandler Oracle 9i LOB
用使,中作實法方 在。 OracleLobHandler用使以可,理處 setValues()
與一第示表 、 引索,流串源來的 與 定設別分來
LogCreator Blob Clob 1 2
。度 長 取 讀 定 指 並 , 置 位 的 元 字 位 佔 個 二 第
' ?'
的下以用使以可,案檔為存另並,來出取讀料資將中庫料資從要果如
:式程
final Writer writer = new FileWriter("test_bak.txt");
final OutputStream os = new FileOutputStream(new File(wish_bak.jpg"));
jdbcTemplate.query("SELECT txt,image FROM test WHERE id = ?",
new Object[] {new Integer(1)},
new AbstractLobStreamingResultSetExtractor() {
protected void streamData(ResultSet rs)
throws SQLException, IOException, DataAccessException {
FileCopyUtils.copy(
lobHandler.getClobAsCharacterStream(rs, 1), writer);
FileCopyUtils.copy(
lobHandler.getBlobAsBinaryStream(rs, 2), os);
}
});
writer.close();
os.close();
用使邊這在 FileCopyUtils 的 copy() 將,法方 LogHandler 流串的得取
出輸案檔給接轉接直 FileWriter 、 F ileOutputStream 。件物
3
38. Spring 2.0 良信林(冊手術技 – http://openhome.cc )
用使以可在現 NamedParameterJdbcTemplate :式方的下以為寫改
String sql = "SELECT * FROM user WHERE id=:userId";
SqlParameterSource namedParameters =
new MapSqlParameterSource("userId", id);
NamedParameterJdbcTemplate jdbcTemplate =
new NamedParameterJdbcTemplate(dataSource);
List rows = jdbcTemplate.queryForList(sql, namedParameters);
用使是邊這在,式方定指的值際實 ":userId" 數參名命到意注
以可也您。值際實與數參名命定指接直時構建在,
SqlParameterSource
Map : 如 例,值 際 實 的 數 參 名 命 個 多 定 指 來 件 物 用 使
String sql = "INSERT INTO user (name,age) VALUES(:userName, :userAge)";
Map namedParameters = new HashMap();
namedParameters.put("userName", name);
namedParameters.put("userAge", age);
NamedParameterJdbcTemplate jdbcTemplate =
new NamedParameterJdbcTemplate(dataSource);
jdbcTemplate.update(sql, namedParameters);
個一據根以可也您 POJO ( P lain Old Java Object 名命為作值的件物)
:如 例 , 據 依 的 值 數 參
String sql = "INSERT INTO user (name,age) VALUES(:name, :age)";
SqlParameterSource namedParameters =
new BeanPropertySqlParameterSource(user);
NamedParameterJdbcTemplate jdbcTemplate =
new NamedParameterJdbcTemplate(dataSource);
jdbcTemplate.update(sql, namedParameters);
中其 " user" 是件物的考參所 JdbcTemplateDemo 。例實 的中案專 User
將體具下以 的案專
JdbcTemplateDemo UserDAO 用使為寫改,別類
NameParameterJdbcTemplate :式方的
38
39. Chapter 5 JDBC 援支易交、
NamedParameterDemo UserDAO.java
package onlyfun.caterpillar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.core.namedparam
.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam
.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam
.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
public class UserDAO implements IUserDAO {
private NamedParameterJdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
public void insert(User user) {
String sql = "INSERT INTO user (name,age) VALUES(:name, :age)";
SqlParameterSource namedParameters =
new BeanPropertySqlParameterSource(user);
jdbcTemplate.update(sql, namedParameters);
}
public User find(Integer id) {
String sql = "SELECT * FROM user WHERE id=:userId";
SqlParameterSource namedParameters =
new MapSqlParameterSource("userId", id);
List rows = jdbcTemplate.queryForList(sql, namedParameters);
Iterator it = rows.iterator();
if(it.hasNext()) {
Map userMap = (Map) it.next();
Integer i = new Integer(userMap.get("id").toString());
3
40. Spring 2.0 良信林(冊手術技 – http://openhome.cc )
String name = userMap.get("name").toString();
Integer age =
new Integer(userMap.get("age").toString());
User user = new User();
user.setId(i);
user.setName(name);
user.setAge(age);
return user;
}
return null;
}
}
5.2.8 Spring 2.0 的 SimpleJdbcTemplate
中 用利以可則,本版的上以 是 的用使您果如
JDK 5.0 Spring 2.0
這是能可您來原如例,能功) (型泛的供提所
SimpleJdbcTemplate G eneric
:料資詢查麼
public User find(Integer id) {
String sql = "SELECT * FROM user WHERE id=?";
RowMapper mapper = new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
User user = new User();
user.setId(new Integer(rs.getInt("id")));
user.setName(rs.getString("name"));
user.setAge(new Integer(rs.getInt("age")));
return user;
}
};
JdbcTemplate simpleJdbcTemplate =
new JdbcTemplate(this.getDataSource());
4
41. Chapter 5 JDBC 援支易交、
return (User) jdbcTemplate.queryForObject(sql, mapper, id);
}
用改若 SimpleJdbcTemplate :寫撰下如以可則,
public User find(Integer id) {
String sql = "SELECT * FROM user WHERE id=?";
ParameterizedRowMapper<User> mapper =
new ParameterizedRowMapper<User>() {
public User mapRow(ResultSet rs, int rowNum)
throws SQLException {
User user = new User();
user.setId(new Integer(rs.getInt("id")));
user.setName(rs.getString("name"));
user.setAge(new Integer(rs.getInt("age")));
return user;
}
};
SimpleJdbcTemplate simpleJdbcTemplate =
new SimpleJdbcTemplate(this.getDataSource());
return simpleJdbcTemplate.queryForObject(sql, mapper, id);
}
在接直以可,能功的型泛到用使中當,到意注以可 mapRow()之法方
的 User 而,例實 回傳後 SimpleJdbcTemplate queryForObject() 以可也法方
將下以。例實 的果結詢查回傳接直 User JdbcTemplateDemo 的案專
:式方的
UserDAO 用使為寫改 SimpleJdbcTemplate
SimpleJdbcTemplateDemo UserDAO.java
package onlyfun.caterpillar;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
41
42. Spring 2.0 良信林(冊手術技 – http://openhome.cc )
public class UserDAO implements IUserDAO {
private SimpleJdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
public void insert(User user) {
String sql = "INSERT INTO user (name,age) VALUES(?, ?)";
String name = user.getName();
Integer age = user.getAge();
jdbcTemplate.update(sql, new Object[] {name, age});
}
public User find(Integer id) {
String sql = "SELECT * FROM user WHERE id=?";
ParameterizedRowMapper<User> mapper =
new ParameterizedRowMapper<User>() {
public User mapRow(ResultSet rs, int rowNum)
throws SQLException {
User user = new User();
user.setId(new Integer(rs.getInt("id")));
user.setName(rs.getString("name"));
user.setAge(new Integer(rs.getInt("age")));
return user;
}
};
return jdbcTemplate.queryForObject(sql, mapper, id);
}
}
42
47. Chapter 5 JDBC 援支易交、
def = new DefaultTransactionDefinition();
def.setPropagationBehavior(
TransactionDefinition.PROPAGATION_REQUIRED);
}
public void insert(User user) {
String name = user.getName();
int age = user.getAge().intValue();
TransactionStatus status =
transactionManager.getTransaction(def);
try {
jdbcTemplate.update("INSERT INTO user (name,age) "
+ "VALUES('" + name + "'," + age + ")");
//的面下 SQL
易交試測以用,誤錯有
jdbcTemplate.update("INSER INTO user (name,age) "
+ "VALUES('" + name + "'," + age + ")");
}
catch(DataAccessException e) {
transactionManager.rollback(status);
throw e;
}
transactionManager.commit(status);
}
public User find(Integer id) {
List rows = jdbcTemplate.queryForList(
"SELECT * FROM user WHERE id=" + id.intValue());
Iterator it = rows.iterator();
if(it.hasNext()) {
Map userMap = (Map) it.next();
Integer i = new Integer(
userMap.get("id").toString());
String name = userMap.get("name").toString();
Integer age = new Integer(
userMap.get("age").toString());
User user = new User();
user.setId(i);
user.setName(name);
47
48. Spring 2.0 良信林(冊手術技 – http://openhome.cc )
user.setAge(age);
return user;
}
return null;
}
}
易交行進來 insert() 了用使中法方 在
DataSourceTransactionManager
在, 的易交行進會中塊區 則,外例了生發果如,理管
catch Rollback insert()
實 此 因 ,) 個 一 了 寫 少 法 方 意 注 ( 的誤 錯 入 寫 意 故 中 法 方
SQL INSERT T
。 中 庫 料 資 至存儲 被 會 不 並 料 資 上 際
格 表 的 易 交 援 支 立 建 須 必,理 處 易 交 行 進 庫 料 資
MySQL 用使要
如 的格 表立建來用邊這,型類格表的
InnoDB 如例,型類 SQL
:示所下
CREATE TABLE user (
id INT(11) NOT NULL auto_increment PRIMARY KEY,
name VARCHAR(100) NOT NULL default '',
age INT
) TYPE = InnoDB;
用 使 是 法 方 的 理 管易交 式 程 編 現 實 個 一 另 TransactionTemplate 它,
:示所下如,例實 TransactionManager 個一要需
...
TransactionTemplate transactionTemplate =
new TransactionTemplate(transactionManager);
...
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
return jdbcTemplate.update("INSERT INTO user (name,age) "
+ "VALUES('" + name + "'," + age + ")");
48