首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring JDBC 整合資料庫完整實戰:從 DataSource 到 JdbcTemplate 的最佳實務

     編輯:Java 相關知識

前言

Spring JDBC 是 Spring 框架提供的JDBC 抽象層,核心類別 JdbcTemplate 大幅簡化了資料庫操作樣板碼(連線獲取、Statement 建立、資源釋放、異常轉換)。本文示範從 XML 配置到註解驅動的完整整合流程,並涵蓋 CRUD、事務管理、RowMapper 等核心技術。

專案結構

src/main/java
├── cn.com.bean
│   └── Person.java                 # 實體類
├── cn.com.service
│   └── PersonService.java          # 服務介面
├── cn.com.service.impl
│   ├── PersonServiceImpl.java      # 服務實作
│   └── PersonRowMapper.java        # RowMapper 實作
└── cn.com.config
    └── DataSourceConfig.java       # Java Config 配置類 (替代 XML)

src/main/resources
├── application.properties          # 資料庫連線參數
└── schema.sql                      # 建表腳本

核心程式碼實作

1. 實體類別

package cn.com.bean;

public class Person {
    private Integer id;
    private String name;

    public Person() {}
    public Person(String name) { this.name = name; }
    // Getter/Setter/toString 略...
}

2. RowMapper 實作

package cn.com.service.impl;

import cn.com.bean.Person;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;

public class PersonRowMapper implements RowMapper {
    @Override
    public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
        Person person = new Person();
        person.setId(rs.getInt("id"));
        person.setName(rs.getString("name"));
        return person;
    }
}

3. 服務介面

package cn.com.service;

import cn.com.bean.Person;
import java.util.List;

public interface PersonService {
    void save(Person person);
    void update(Person person);
    Person getById(Integer id);
    List getAll();
    void deleteById(Integer id);
}

4. 服務實作 - 核心 JdbcTemplate 操作

package cn.com.service.impl;

import cn.com.bean.Person;
import cn.com.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

@Service
@Transactional // 類別層級事務,所有 public 方法自動加入事務
public class PersonServiceImpl implements PersonService {
    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public PersonServiceImpl(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public void save(Person person) {
        String sql = "INSERT INTO person (name) VALUES (?)";
        jdbcTemplate.update(sql, person.getName());
    }

    @Override
    public void update(Person person) {
        String sql = "UPDATE person SET name = ? WHERE id = ?";
        jdbcTemplate.update(sql, person.getName(), person.getId());
    }

    @Override
    public Person getById(Integer id) {
        String sql = "SELECT id, name FROM person WHERE id = ?";
        try {
            return jdbcTemplate.queryForObject(sql, new PersonRowMapper(), id);
        } catch (EmptyResultDataAccessException e) {
            return null; // 或拋出自定義異常
        }
    }

    @Override
    public List getAll() {
        String sql = "SELECT id, name FROM person";
        return jdbcTemplate.query(sql, new PersonRowMapper());
    }

    @Override
    public void deleteById(Integer id) {
        String sql = "DELETE FROM person WHERE id = ?";
        jdbcTemplate.update(sql, id);
    }
}

5. Java Config 配置類 (現代替代 XML)

package cn.com.config;

import org.springframework.context.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import com.zaxxer.hikari.HikariDataSource;

@Configuration
@ComponentScan("cn.com")
@EnableTransactionManagement // 啟用 @Transactional 支援
@PropertySource("classpath:application.properties")
public class DataSourceConfig {

    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.driver}")
    private String driver;

    @Bean
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        ds.setDriverClassName(driver);
        // 連線池優化參數
        ds.setMaximumPoolSize(20);
        ds.setMinimumIdle(5);
        ds.setConnectionTimeout(30000);
        ds.setIdleTimeout(600000);
        ds.setMaxLifetime(1800000);
        return ds;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

6. application.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_demo?useSSL=false&serverTimezone=UTC&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456

7. schema.sql

CREATE TABLE IF NOT EXISTS `person` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(50) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

JdbcTemplate 核心方法對照表

方法用途回傳值
update(sql, args...)INSERT/UPDATE/DELETEint (影響行數)
queryForObject(sql, RowMapper, args...)查詢單筆T (無結果拋 EmptyResultDataAccessException)
query(sql, RowMapper, args...)查詢多筆List
queryForMap(sql, args...)查詢單筆轉 MapMap
queryForList(sql, args...)查詢多筆轉 ListList>
batchUpdate(sql, List)批次更新int[]

事務管理最佳實務

  • @Transactional 位置:建議加在 Service 實作類 或 public 方法,避免加在介面(CGLIB 代理限制)
  • rollbackFor:預設只回滾 RuntimeException,需加 @Transactional(rollbackFor = Exception.class) 涵蓋受檢異常
  • propagation:REQUIRED (預設)、REQUIRES_NEW (獨立事務)、NESTED (巢狀保存點)
  • 隔離級別:READ_COMMITTED (大多數資料庫預設)、REPEATABLE_READ (MySQL 預設)

測試驗證

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DataSourceConfig.class)
public class PersonServiceTest {
    @Autowired
    private PersonService personService;

    @Test
    public void testCrud() {
        // Save
        Person p = new Person("張三");
        personService.save(p);
        assertNotNull(p.getId()); // 自動回寫自增 ID 需配合 GeneratedKeyHolder

        // Get
        Person found = personService.getById(p.getId());
        assertEquals("張三", found.getName());

        // Update
        found.setName("李四");
        personService.update(found);
        assertEquals("李四", personService.getById(p.getId()).getName());

        // List
        assertTrue(personService.getAll().size() >= 1);

        // Delete
        personService.deleteById(p.getId());
        assertNull(personService.getById(p.getId()));
    }
}

進階技巧:自動回寫自增主鍵

@Override
public void save(Person person) {
    String sql = "INSERT INTO person (name) VALUES (?)";
    KeyHolder keyHolder = new GeneratedKeyHolder();
    
    jdbcTemplate.update(connection -> {
        PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        ps.setString(1, person.getName());
        return ps;
    }, keyHolder);
    
    person.setId(keyHolder.getKey().intValue());
}

總結

Spring JDBC + JdbcTemplate 是 Java 資料庫操作的黃金平衡點:比 MyBatis 輕量、比原生 JDBC 安全簡潔、比 JPA 更可控。掌握 RowMapper、PreparedStatementCreator、TransactionTemplate 等核心介面,即可應對 90% 的關聯式資料庫操作場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved