chapter10_通过Spring和JDBC征服数据库_3_在Spring中使用JDBC

本文深入探讨了JDBC的优势及其在Spring框架中的高效应用。通过Spring的JdbcTemplate简化了数据库操作,避免了资源泄漏的风险,实现了增删改查等数据库操作的模板化。同时,介绍了RowMapper接口如何用于数据映射,以及SimpleJdbcInsert对象在插入操作中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • JDBC的__优势__

    (1) 不需要掌握其他查询语言, 建立在SQL之上

    (2) 可以在比较底层处理数据, 便于对数据访问进行性能调优

  • 失控的JDBC代码

    (1) 如果直接使用JDBC提供的操作数据库的API, 那么总是要写很多"模板代码": 建立连接、 准备语句、 关闭资源、 catch异常

    (2) 这些代码都是必要的, 否则会有资源泄漏的隐患

  • 使用JDBC模板

    (1) Spring将数据访问的模板代码抽象到了模板方法类之中

    (2) Spring提供了三个模板类

    1° JdbcTemplate

    2° NamedParameterJdbcTemplate

    3° SimpleJdbcTemplate

    对于大多数JDBC任务来说, 使用JdbcTemplate都是最好的方案

    (3) 将DataSource装配到一个JdbcTemplate对象中; 将JdbcTemplate装配到操作数据的Repository对象中, 就可以使用了!

    示例

      @Configuration
      public class JdbcConfig {
    
          @Bean
          @Profile("embedded")
          public DataSource dataSource() {
    
              return new EmbeddedDatabaseBuilder()
                      .setType(EmbeddedDatabaseType.H2)
                      .addScripts("classpath:spittr/db/jdbc/schema.sql", "classpath:spittr/db/jdbc/test-data.sql")
                      .build();
          }
    
          @Bean
          public JdbcTemplate jdbcTemplate(DataSource dataSource) {
    
              return new JdbcTemplate(dataSource);
          }
    
          @Bean
          public SpitterRepository spitterRepository(JdbcTemplate jdbcTemplate) {
    
              return new JdbcSpitterRepository(jdbcTemplate);
          }
    
          @Bean
          public SpittleRepository spittleRepository(JdbcTemplate jdbcTemplate) {
              return new JdbcSpittleRepository(jdbcTemplate);
          }
      }
    

    这样, 样本代码就被隐藏在JdbcTemplate类中了

  • RowMapper接口

    (1) 源码

      public interface RowMapper<T> {
    
          T mapRow(ResultSet rs, int rowNum) throws SQLException;
      }
    

    (2) 作用: 将ResultSet返回的每一行数据封装成用户自定义的对象, 从而实现解耦

    (3) 对于查询返回的每一行数据, JdbcTemplate都会调用一次RowMapper的mapRow()方法

    (4) 实现示例

      final class SpitterRowMapper implements RowMapper<Spitter> {
    
          public Spitter mapRow(ResultSet rs, int rowNum) throws SQLException {
    
              long id = rs.getLong("id");
              String username = rs.getString("username");
              String password = rs.getString("password");
              String fullName = rs.getString("fullname");
              String email = rs.getString("email");
              boolean updateByEmail = rs.getBoolean("updateByEmail");
    
              return new Spitter(id, username, password, fullName, email, updateByEmail);
          }
      }
    
  • 增删改查的实现

      public class JdbcSpitterRepository implements SpitterRepository {
    
          private JdbcTemplate jdbcTemplate;
    
          public JdbcSpitterRepository(JdbcTemplate jdbcTemplate) {
    
              this.jdbcTemplate = jdbcTemplate;
          }
    
          ...
      }
    

    (1)

    1° 不需要获取结果

      jdbcTemplate.update("INSERT INTO Spitter (username, password, fullname, email, updateByEmail) VALUES (?, ?, ?, ?, ?)",
              spitter.getUsername(),
              spitter.getPassword(),
              spitter.getFullName(),
              spitter.getEmail(),
              spitter.isUpdateByEmail());
    

    函数形式

      public int update(String sql, Object... args) throws DataAccessException
    

    返回的是插入操作影响的行数

    2° 使用SimpleJdbcInsert对象获取插入的某一列的结果

      SimpleJdbcInsert jdbcInsert
              = new SimpleJdbcInsert(jdbcTemplate).withTableName("Spitter");
    
      jdbcInsert.setGeneratedKeyName("id");
      Map<String, Object> args = new HashMap<String, Object>();
    
      args.put("username", spitter.getUsername());
      args.put("password", spitter.getPassword());
      args.put("fullname", spitter.getFullName());
      args.put("email", spitter.getEmail());
      args.put("updateByEmail", spitter.isUpdateByEmail());
    
      long spitterId = jdbcInsert.executeAndReturnKey(args).longValue();
    

    在指定了key为id以后, 可以在执行后获取key的值

    (2)

      jdbcTemplate.update("DELETE FROM Spittle WHERE id=?", id);
    

    (3)

      jdbcTemplate.update("UPDATE Spitter SET username=?, password=?, fullname=?,  email=?, updateByEmail=? where id=?",
                  spitter.getUsername(),
                  spitter.getPassword(),
                  spitter.getFullName(),
                  spitter.getEmail(),
                  spitter.isUpdateByEmail(),
                  id);
    

    (4)

    1° 使用RowMapper接口, 返回一行

      Spitter spitter = jdbcTemplate.queryForObject(
          "SELECT id, username, password, fullname, email, updateByEmail FROM Spitter WHERE id=?",
          new SpitterRowMapper(), 
          id);
    

    其中, SpitterRowMapper是我们实现的RowMapper接口, 它会将ResultSet的一行包装成我们需要的对象

    函数形式是

      public <T> T queryForObject(
          String sql, 
          RowMapper<T> rowMapper, 
          Object... args) throws DataAccessException;
    

    2° 使用RowMapper接口, 返回一个List

      List<Spitter> spitterList = jdbcTemplate.query(
          "SELECT id, username, password, fullname, email, updateByEmail FROM Spitter ORDER BY id",
          new SpitterRowMapper());
    

    函数形式是

      public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException;
    

    3° 不带RowMapper的形式

      long count = jdbcTemplate.queryForObject(
              "SELECT COUNT(id) FROM Spitter", Long.class);
    

    函数形式是

      public <T> T queryForObject(String sql, Class<T> requiredType) throws DataAccessException
    

    需要什么类型的返回值, 在Class中指定;

    阅读源码可以发现, 其实内部也有一个默认实现的SingleColumnRowMapper作为RowMapper

      return queryForObject(sql, getSingleColumnRowMapper(requiredType));
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值