# SpringBoot 中怎么利用JdbcTemplate操作數據庫
## 一、JdbcTemplate 概述
### 1.1 什么是 JdbcTemplate
JdbcTemplate 是 Spring 框架提供的一個核心 JDBC 工具類,它封裝了原生 JDBC API 的復雜操作,提供了更簡潔的數據庫訪問方式。主要特點包括:
- 自動管理資源(Connection/Statement/ResultSet)
- 簡化異常處理(將檢查異常轉換為運行時異常)
- 提供豐富的 CRUD 操作方法
- 支持命名參數和預編譯語句
### 1.2 與 MyBatis/JPA 的對比
| 特性 | JdbcTemplate | MyBatis | JPA/Hibernate |
|--------------|--------------------|--------------------|--------------------|
| 學習曲線 | 低 | 中 | 高 |
| 靈活性 | 極高 | 高 | 中 |
| 自動化程度 | 低(手動寫SQL) | 中(XML/注解) | 高(自動生成SQL) |
| 適用場景 | 簡單CRUD/復雜SQL | 復雜SQL映射 | 對象關系映射 |
## 二、SpringBoot 集成 JdbcTemplate
### 2.1 添加依賴
在 `pom.xml` 中添加 starter 和數據庫驅動:
```xml
<dependencies>
<!-- Spring Boot JDBC starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 數據庫驅動(以MySQL為例) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
</dependencies>
application.yml
配置示例:
spring:
datasource:
url: jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# HikariCP 連接池配置(默認)
hikari:
maximum-pool-size: 10
minimum-idle: 5
connection-timeout: 30000
通過構造器注入:
@Repository
public class UserDaoImpl implements UserDao {
private final JdbcTemplate jdbcTemplate;
@Autowired
public UserDaoImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
public int insert(User user) {
String sql = "INSERT INTO user(name, age, email) VALUES(?, ?, ?)";
return jdbcTemplate.update(
sql,
user.getName(),
user.getAge(),
user.getEmail()
);
}
// 批量插入
public int[] batchInsert(List<User> users) {
String sql = "INSERT INTO user(name, age, email) VALUES(?, ?, ?)";
return jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
User user = users.get(i);
ps.setString(1, user.getName());
ps.setInt(2, user.getAge());
ps.setString(3, user.getEmail());
}
@Override
public int getBatchSize() {
return users.size();
}
});
}
public User getById(Long id) {
String sql = "SELECT * FROM user WHERE id = ?";
return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) -> {
User user = new User();
user.setId(rs.getLong("id"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
user.setEmail(rs.getString("email"));
return user;
});
}
public List<User> listAll() {
String sql = "SELECT * FROM user";
return jdbcTemplate.query(sql, (rs, rowNum) -> {
User user = new User();
user.setId(rs.getLong("id"));
// 其他字段設置...
return user;
});
}
public int countUsers() {
String sql = "SELECT COUNT(*) FROM user";
return jdbcTemplate.queryForObject(sql, Integer.class);
}
// 更新
public int update(User user) {
String sql = "UPDATE user SET name=?, age=?, email=? WHERE id=?";
return jdbcTemplate.update(
sql,
user.getName(),
user.getAge(),
user.getEmail(),
user.getId()
);
}
// 刪除
public int delete(Long id) {
String sql = "DELETE FROM user WHERE id=?";
return jdbcTemplate.update(sql, id);
}
使用 NamedParameterJdbcTemplate
:
@Autowired
private NamedParameterJdbcTemplate namedJdbcTemplate;
public User getByName(String name) {
String sql = "SELECT * FROM user WHERE name = :name";
Map<String, Object> params = new HashMap<>();
params.put("name", name);
return namedJdbcTemplate.queryForObject(sql, params, (rs, rowNum) -> {
// 對象映射...
});
}
public void callProcedure() {
jdbcTemplate.execute("{call update_user_status(?, ?)}",
(CallableStatementCallback<Void>) cs -> {
cs.setLong(1, 1001L);
cs.registerOutParameter(2, Types.INTEGER);
cs.execute();
log.info("Out parameter: {}", cs.getInt(2));
return null;
});
}
在 Service 層添加 @Transactional
:
@Service
@Transactional
public class UserService {
@Autowired
private UserDao userDao;
public void transferBalance(Long fromId, Long toId, BigDecimal amount) {
userDao.deductBalance(fromId, amount);
// 模擬業務異常
if (amount.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("金額不能為負");
}
userDao.addBalance(toId, amount);
}
}
sql.properties
或常量類)StringBuilder
或 JOOQ// 1. 使用預編譯語句
jdbcTemplate.setFetchSize(100); // 設置批量獲取大小
// 2. 結果集處理優化
jdbcTemplate.query(sql, new ResultSetExtractor<List<User>>() {
@Override
public List<User> extractData(ResultSet rs) throws SQLException {
// 自定義高效處理邏輯
}
});
// 3. 連接池配置
spring.datasource.hikari.maximum-pool-size=20
try {
jdbcTemplate.update("INSERT...");
} catch (DuplicateKeyException e) {
// 處理唯一鍵沖突
} catch (DataAccessException e) {
// 處理其他數據庫異常
}
@Repository
public class UserDaoImpl implements UserDao {
private static final String INSERT_SQL = "INSERT...";
private static final String SELECT_BY_ID_SQL = "SELECT...";
private final JdbcTemplate jdbcTemplate;
@Override
public List<User> findByAgeGreaterThan(int age) {
return jdbcTemplate.query(
"SELECT * FROM user WHERE age > ? ORDER BY name",
new BeanPropertyRowMapper<>(User.class),
age
);
}
}
@SpringBootTest
class UserDaoTest {
@Autowired
private UserDao userDao;
@Test
@Transactional // 測試后自動回滾
void testInsert() {
User user = new User("test", 25, "test@example.com");
int affected = userDao.insert(user);
assertEquals(1, affected);
}
}
JdbcTemplate 在 SpringBoot 中的優勢: - 輕量級,無額外學習成本 - 適合簡單CRUD和存儲過程調用 - 與 Spring 生態完美集成
適用場景建議: - 小型項目或微服務中的簡單數據訪問 - 需要執行原生SQL的復雜查詢 - 與其他ORM框架混合使用 “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。