JdbcTemplate 的基本增删改查介绍

1. 前言

最近接触的项目使用 JdbcTemplate 比较频繁,以至于经常要去查API,在这里写一下常用的增删改查操作。

2. JdbcTemplate基本介绍

JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。它是Spring的一部分,我们不需要关系什么时候建立连接和释放资源。

在JdbcTemplate中执行SQL语句的方法大致分为3类:

  1. execute 方法:可以执行所有SQL语句,一般用于执行DDL语句(对表结构操作)。
  2. update 方法和 batchUpdate 方法:用于执行INSERTUPDATEDELETE等DML语句(对数据的增删改)。batchUpdate 方法用于执行批处理相关语句。
  3. query 方法和 queryXxx 方法:用于DQL数据查询语句(对数据的查询)。
  4. call 方法 :用于执行存储过程、函数相关语句。

对于连接池的配置这里不多介绍,只介绍增删改查操作。

3. 增删改操作

3.1 使用Update方法

API介绍:

public int update(final String sql) :用于执行 INSERTUPDATEDELETE等DML语句。

有个实体类

public class User implement Serializable {
  private int id;
  private String name;
  private age;
  ...
  //setter、getter
  ...
}

数据访问层操作

@Repository
public class UserDao{
  @Resource
  private JdbcTemplate jdbcTemplate;
  
  // JDBCTemplate 添加操作
  public static void create01() throws Exception {
     //和jdbc一样,使用 ?占位符防sql注入
     String sql = "INSERT INTO TB_USER VALUES (NULL, ?, ?);";

    jdbcTemplate.update(sql, "zhangsan", 22);
    jdbcTemplate.update(sql, "lisi", 24);
 	   
  }
  
  // JDBCTemplate 添加操作2
  public static void create02() throws Exception {
     String sql = "INSERT INTO TB_USER VALUES (NULL, ?, ?);";
	//使用Object[]数组作为参数,可更新多条数据
    Object[] args = new Object[]{"zhangsan",23,"lisi",24};
    jdbcTemplate.update(sql, args);
  }

  // JDBCTemplate 更新操作
  public static void update01() throws Exception {
      String sql = "UPDATE TB_USER SET name=?, age=? WHERE id=?;";

     Object[] args = new Object[]{"lucy",24,10};
    jdbcTemplate.update(sql, args);
  }
  
  
  // JDBCTemplate 删除操作
  public static void update01() throws Exception {
      String sql = "DELETE FROM TB_USER WHERE id=?;";

     Object[] args = new Object[]{9,10};
    jdbcTemplate.update(sql, args);
  }
  
}

3.2 批量操作 -- batchUpdate方法

@Repository
public class UserDao{
  @Resource
  private JdbcTemplate jdbcTemplate;
  
  @AutoWired
  private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
  
  public void batchCreate(List<User> list) {
    SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(list.toArray());
    String sql = "INSERT INTO TB_USER(NAME,AGE) VALUES(:name, :age)";
    namedParameterJdbcTemplate.batchUpdate(sql, batch);
  }
  
  //删除和修改操作也类似,就是sql语句的区别。
  
}

4. 查询操作

4.1 queryForInt返回一个int整数

public int queryForInt(String sql) :执行查询语句,返回一个int类型的值。

// queryForInt返回一个整数 -- 相当于使用了 COUNT(*) 
public static void demo01() throws Exception {
   String sql = "SELECT id FROM TB_USER WHERE age > 18;";
   int forInt = jdbcTemplate.queryForInt(sql);
   System.out.println(forInt);
}

4.2 queryForObject返回String

public T queryForObject(String sql, Class requiredType) :执行查询语句,返回一个指定类型的数据。

public static void demo02() throws Exception {
   String sql = "SELECT name FROM FROM WHERE id=10;";
   String name = jdbcTemplate.queryForObject(sql, String.class);
   System.out.println(name);
}

4.3 queryForMap返回一个Map集合

public Map<String, Object> queryForMap(String sql, Object... args) : 执行查询语句,将一条记录放到一个Map中。

public static void demo03() throws Exception {
   String sql = "SELECT * FROM TB_USER WHERE id=?;";
   Map<String, Object> map = jdbcTemplate.queryForMap(sql, 6);
   System.out.println(map);
}

4.4 queryForList返回一个List集合

public List<Map<String, Object>> queryForList(String sql) : 执行查询语句,返回一个List集合,List中存放的是Map类型的数据。

public static void demo04() throws Exception {
   String sql = "SELECT * FROM TB_USER WHERE age > ?;";
   List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, 18);
   for (Map<String, Object> map : list) {
      System.out.println(map);
   }
}

4.5 RowMapper返回自定义对象

public List query(String sql, RowMapper rowMapper) :执行查询语句,返回一个List集合,List中存放的是RowMapper指定类型的数据。

public static void demo05() throws Exception {
   String sql = "SELECT * FROM TB_USER WHERE age > ?;";
  List<User> list = jdbcTemplate.query(sql, new Object[]{18}, new RowMapper<User>(){
    @Override
    public User mapRow(ResultSet res, int i) throws SQLException {
      User user = new User();
      user.setId(res.getInt("ID"));
      user.setName(res.getString("NAME"));
      user.setAge(res.getInt("AGE"));
      return user;
    }
  });
   for (User user : list) {
      System.out.println(user);
   }
}

以上所提到的方法,存在很多重载方法,其主要是参数个数不一样,可根据自己需求使用。

5. 拓展类 NamedParameterJdbcTemplate

​ 在经典的 JDBC 用法中, SQL 参数是用占位符 ? 表示,并且受到位置的限制,定位参数的问题在于, 一旦参数的顺序发生变化, 就必须改变参数绑定。

在 Spring JDBC 框架中, 绑定 SQL 参数的另一种选择是使用具名参数(named parameter)

那么什么是具名参数?

具名参数: SQL 按名称(以冒号开头)而不是按位置进行指定. 具名参数更易于维护, 也提升了可读性. 具名参数由框架类在运行时用占位符取代

具名参数只在 NamedParameterJdbcTemplate 中得到支持。

NamedParameterJdbcTemplate可以使用全部jdbcTemplate方法。

NamedParameterJdbcTemplate类拓展了JdbcTemplate类,对JdbcTemplate类进行了封装从而支持命名参数特性。

NamedParameterJdbcTemplate主要提供以下三类方法:execute方法、queryqueryForXXX方法、update及batchUpdate方法。

案例:

具名新增:

@Test
public void testNamedParameter(){
    String sql = "insert into user (username,password) values (:username,:password)";
    User u = new User();
    u.setUsername("555");
    SqlParameterSource sqlParameterSource=new BeanPropertySqlParameterSource(u);
    namedParameterJdbcTemplate.update(sql,sqlParameterSource);
}

这样我们就可以根据pojo类的属性值使用JDBC来操作数据库了。

获取新增的主键:
NamedParameterJdbcTemplate还新增了KeyHolder类,使用它我们可以获得主键,类似Mybatis中的useGeneratedKeys。

@Test
public void testKeyHolder(){
    String sql = "insert into user (username,password) values (:username,:password)";
    User u = new User();
    u.setUsername("555");
    SqlParameterSource sqlParameterSource=new BeanPropertySqlParameterSource(u);
    KeyHolder keyHolder = new GeneratedKeyHolder();
    namedParameterJdbcTemplate.update(sql, sqlParameterSource, keyHolder);
    int k = keyHolder.getKey().intValue();
    System.out.println(k);
}

输出结果就是新增的主键。

6. 存储过程调用

6.1 jdbcTemplate 调用

public void buildTableData(String source) {
 	// 设置存储过程参数
    List<SqlParameter> parameters = Arrays.asList(new SqlParameter(Types.VARCHAR)); 
  	// 执行存储过程
    Map<String, Object> resultMap = jdbcTemplate.call(con -> {
      CallableStatement cs = con.prepareCall("CALL P_TMP_PW_CONTAINER_NRJB(?)");
      cs.setString(1, source);//设置入参
      return cs;
    }, parameters);
  
  	// 从结果中获取输出参数的值
    String empName = (String) resultMap.get("emp_name");
    String deptName = (String) resultMap.get("dept_name");
  
}

6.2 SimpleJdbcCall 调用

相比于 jdbcTemplate 调用存储过程,SimpleJdbcCall 有着更多的优势,SimpleJdbcCall 会自动为德比,MySQL,微软SQL服务器,甲骨文,DB2,系统库和后greSQL数据库检测“IN”和“OUT”参数。对于任何其他数据库,需要显式声明所有参数。

public void searchUsersWithCount(String by, String direction, int size, int offset) {
 	// 配置 SimpleJdbcCall
    SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate)
      	//设置存储过程名
        .withProcedureName("count_search_users_proc")
      	//因为自动检测“IN”和“OUT”参数,这一段可省略
        /*.declareParameters( 
            new SqlParameter("order_by", Types.NVARCHAR),
            new SqlParameter("direction", Types.VARCHAR),
            new SqlParameter("limit_", Types.INTEGER),
            new SqlParameter("offset_", Types.INTEGER);*/
      	//设置结果集
      	.returningResultSet("employeeName", (rs, rowNum) -> rs.getString("name"));
    
    // 执行存储过程
    Map<String, Object> out = simpleJdbcCall.execute(
        new MapSqlParameterSource("order_by", by)
        .addValue("direction", direction)
        .addValue("limit_", size)
        .addValue("offset_", offset));
     
    // 处理结果
    String employeeName = (String) result.get("employeeName");
    System.out.println("Employee Name: " + employeeName);
 }

SimpleJdbcCallJdbcTemplate 都是 Spring JDBC 框架提供的用于简化 JDBC 编程的工具,但它们的设计和使用方式有所不同。

  1. SimpleJdbcCall
    • 用途:主要用于调用存储过程。
    • 特点:提供了更为简洁的接口,专门用于执行存储过程,并提供了一些便捷的方法来处理存储过程的输入参数、输出参数和返回结果集。
    • 示例:在上面的例子中,你可以看到 SimpleJdbcCall 的使用方法,它直接指定了存储过程的名称,并且可以配置返回结果集的处理方式。
  2. JdbcTemplate
    • 用途:用于执行 SQL 语句,包括但不限于存储过程的调用。
    • 特点:提供了更为通用的接口,可以执行任意的 SQL 语句,包括增删改查和存储过程的调用。但是需要手动处理参数和结果集。
    • 示例:在前面的对话中提到了一些 JdbcTemplate 的方法,如 callexecute,它们可以用于执行存储过程,但需要更多的参数配置和结果处理。

对比

  • 如果你只需要执行存储过程,并且希望代码简洁、易于理解,那么使用 SimpleJdbcCall 更为合适。
  • 如果你需要执行各种类型的 SQL 语句,并且需要更多的灵活性和控制,那么使用 JdbcTemplate 更适合。
  • 在处理存储过程时,SimpleJdbcCall 提供了更为直观和方便的方法,而 JdbcTemplate 则更为通用,适用于各种情况下的 SQL 执行需求。

有哪里写的不对,欢迎提出建议~

posted @ 2021-12-29 10:31  乐子不痞  阅读(3095)  评论(0编辑  收藏  举报
回到顶部