JDBCTemplate 的使用

223 阅读2分钟

● 基本介绍

  1. 通过 Spring 可以配置数据源,从而完成对数据表的操作
  2. JdbcTemplate 是 Spring 提供的访问数据库的技术。可以将 JDBC 的常用操作封装为模板方法。

使用API的技巧

  1. 先确定API的名字
  2. 根据API提供的相应的参数
  3. 把自己的调用思路清晰

 使用 JdbcTemplate

查询 (SELECT

单行单列

第一种方式

这种写法是更推荐的方式,特别适用于查询单行单列并将结果映射到指定类型的情况。通过传递结果的预期类型作为requiredType参数,您可以确保查询结果将直接映射到该类型,而不需要手动编写RowMapper实现。

@Test  
public void test11() {  
	ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml");  
	JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);  
	  
	// 确定API  
	// public <T> T queryForObject(String sql, Class<T> requiredType, @Nullable Object... args)
	String sql = "select name from monster where id = ?";  
	  
	String name = jdbcTemplate.queryForObject(sql, String.class, 200);  
	System.out.println("name = " + name);  
}

第二种方式

@Test  
public void test10() {  
	ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml");  
	JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);  
	  
	// 确定API  
	// <T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args)  
	String sql = "select name from monster where id = ?";  
	String name = jdbcTemplate.queryForObject(sql,  
	(ResultSet rs, int rowNum) -> rs.getString("name"), 200);  
	System.out.println("name = " + name);  
  
}

单个对象

第一种方式

@Test  
public void test6() {  
	ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml");  
	JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);  
	  
	// 确定API  
	// <T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args)  
	String sql = "select id AS `monsterId`, name, skill from monster where id = ?";  
	  
	//这里有一个细节就是名称需要一样, 即查询的表字需要和查询的字段保持一致  
	RowMapper<Monster> rowMapper = new RowMapper<Monster>() {  
	@Override  
	public Monster mapRow(ResultSet rs, int rowNum) throws SQLException {  
			Monster monster = new Monster();  
			monster.setSkill(rs.getString("skill"));  
			monster.setName(rs.getString("name"));  
			monster.setMonsterId(rs.getInt("monsterId"));  
			return monster;  
		}  
	};  
	  
	// 可以使用lambda表达式简化  
	Monster monster = jdbcTemplate.queryForObject(sql, rowMapper, 100);  
	  
	System.out.println("monster = " + monster);  
}

第二种方式

@Test  
public void test7() {  
	ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml");  
	JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);  
	  
	// 确定API  
	// <T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args)  
	String sql = "select id AS `monsterId`, name, skill from monster where id = ?";  
	// 使用子类实现对象的封装  
	RowMapper<Monster> rowMapper = new BeanPropertyRowMapper<>(Monster.class);  
	Monster monster = jdbcTemplate.queryForObject(sql, rowMapper, 100);  
	System.out.println("monster = " + monster);  
  
}
  • test6()方法使用了匿名内部类实现的RowMapper,在mapRow()方法中手动设置了查询结果的映射关系,将查询结果映射到Monster对象中。
  • test7()方法使用了BeanPropertyRowMapper,它是Spring提供的一种方便的RowMapper实现,可以根据结果集的列名和目标对象的属性名进行自动映射。

两种写法都是可以的,但有一些考虑因素可以帮助您选择适合您的情况:

  • 如果您的查询结果需要进行自定义的映射逻辑,或者需要处理一些特殊的转换操作,您可以选择test6()的写法,并通过自定义的RowMapper实现进行映射。
  • 如果您的查询结果与目标对象的属性名和类型完全一致,或者您不需要进行额外的映射操作,您可以选择test7()的写法,并使用BeanPropertyRowMapper进行自动映射。

总体而言,test7()的写法更加简洁和方便,因为它利用了BeanPropertyRowMapper的自动映射功能,可以减少手动编写映射逻辑的工作量。然而,如果您需要更复杂的映射逻辑或转换操作,test6()的写法可以给您更大的灵活性

多个对象

方式一

@Test  
public void test9() {  
	ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml");  
	JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);  
	  
	// 确定API  
	String sql = "select id AS `monsterId`, name, skill from monster where id > ?";  
	
	RowMapper<Monster> rowMapper = new BeanPropertyRowMapper<>(Monster.class);  
	
	List<Monster> query = jdbcTemplate.query(sql, rowMapper, 100);  
	
	for (Monster monster : query) {  
		System.out.println("monster = " + monster);  
	}  
  
}

方式二

@Test  
public void test8() {  
	ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml");  
	JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);  
	  
	// 确定API  
	// <T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args)  
	String sql = "select id AS `monsterId`, name, skill from monster where id > ?";  

	// 使用lambda表达式简化
	List<Monster> monsterList = jdbcTemplate.query(sql, 
	(ResultSet rs, int rowNum) -> {  
		Monster monsters = new Monster(rs.getInt("monsterId"), rs.getString("name"), rs.getString("skill"));  
		return monsters;  
	}, 100);  
	  
	for (Monster monster : monsterList) {  
		System.out.println("monster = " + monster);  
	}  
  
}

更新(INSERTUPDATE 和 DELETE

你可以使用 update(..) 方法来执行插入、更新和删除操作。参数值通常作为变量参数提供,或者作为一个对象数组提供

INSERT

this.jdbcTemplate.update( "insert into t_actor (first_name, last_name) values (?, ?)", "Leonor", "Watling");

如何实现插入多条数据 ?

@Test  
public void test5() {  
	ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml");  
	JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);  
	  
	// 1. 批量插入 猜测update => 根据参数修改名称是 batchUpdate// 2. 根据参数提供数据  
	String sql = "insert into monster values (?, ?, ?)";  
	List<Object[]> list = new ArrayList<>();  
	list.add(new Object[]{700, "老鼠精", "偷吃粮食"});  
	list.add(new Object[]{800, "老猫精", "抓老鼠"});  
	// 3. 调试  
	// 说明:  
	// 返回结果是一个数组, 每一个元素对应的上面的sql语句影响的行数  
	int[] ints = jdbcTemplate.batchUpdate(sql, list);  
	// 4. 输出  
	for (int anInt : ints) {  
	System.out.println("anInt: " + anInt);  
	}  
	  
	System.out.println("add ok ~");  
}

UPDATE

this.jdbcTemplate.update(
        "update t_actor set last_name = ? where id = ?",
        "Banjo", 5276L);

DELETE

this.jdbcTemplate.update(
        "delete from t_actor where id = ?",
        Long.valueOf(actorId));

使用 NamedParameterJdbcTemplate

具名参数

具名参数的写法具有以下特点:

  • 使用冒号(:)作为参数的前缀,例如:id:name:skill
  • 冒号后面的字符串是参数的名称,用于在Map对象中进行参数值的映射。
  • SQL语句中的具名参数和实际的参数值将在执行时进行匹配和替换。
@Test  
public void test12() {  
	ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml");  
	NamedParameterJdbcTemplate namedParameterJdbcTemplate = ioc.getBean(NamedParameterJdbcTemplate.class);  
	  
	// 具名参数  
	// :id, :name, :skill 不需要知道表的结构  
	String sql = "insert into monster values (:id, :name, :skill)";  
	Map<String, Object> map = new HashMap<>();  
	map.put("id", 900);  
	map.put("name", "蚂蚁精");  
	map.put("skill", "喜欢打洞");  
	int affected = namedParameterJdbcTemplate.update(sql, map);  
	System.out.println("affected = " + affected);  
  
}

xml文件

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
	xmlns:context="http://www.springframework.org/schema/context"  
	xsi:schemaLocation="http://www.springframework.org/schema/beans">  
	  
	<!-- 配置数据源对象-DataSource-->  
	<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">  
	<property name="user" value="root"/>  
	<property name="password" value="hsp"/>  
	<property name="driverClass" value="com.mysql.jdbc.Driver"/>  
	<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring"/>  
	</bean>  
	  
	<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">  
	<property name="dataSource" ref="dataSource"/>  
	</bean>  
	  
	<!-- 配置 NamedParameterJdbcTemplate--><bean class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" id="parameterJdbcTemplate">  
	<!-- 通过构造器, 设置属性-->  
	<constructor-arg name="dataSource" ref="dataSource" />  
	</bean>  

</beans>

中文文档地址: springdoc.cn/