YMNNALFT:使用 JdbcTemplate 的轻量级 SQL 数据映射器

工程 | Josh Long | 2021年02月01日 | ...

欢迎来到《你可能不需要另一个库来实现它》(YMNNALFT) 系列的又一篇!自 2016 年以来,我花了很多时间在我的 Spring Tips 视频中阐述(或者说,我一直在尝试!)Spring 生态系统中一些更巨大的机遇。然而,今天我带着不同的精神来找你们,希望能关注那些小巧、有时隐藏但作用非凡的宝藏,它们可以为你省去一个额外的第三方依赖及其隐含的复杂性。

我想,我第一次使用 Spring,是在 15 多年前,那时我使用了 JdbcTemplate,它消除了直接使用 JDBC 时令人眼花缭乱且冗长的操作。你可能知道,JDBC 是“Just Don't Break, Compiler!”(只是不要出错,编译器!)的缩写,它的设计初衷是通过提供一个 API 来测试 JVM 每种方法 65535 字节的字节码限制,因为它提供的方法总是需要比这个限制更多的代码行才能完成即使是最基本的操作。

言归正传。有人告诉我,JDBC 实际上是 Java 数据库连接 API。继续...

当时我无法将 Spring 作为框架用在项目中,但我可以将 Spring 作为一种库引入。最初我引入它主要是为了访问 JdbcTemplate,以及整个各种 *Template 对象的概念。

模板对象是控制反转原则的一个绝佳示例。你让模板对象完成 90% 的工作,并为其提供一个回调,当模板需要你的输入时,就会调用它。模板颠倒了应用程序的流程;它们处理繁琐的工作,然后在该做你想做的事情时才让你参与进来。它们就像迷你框架

JdbcTemplate 是 Java 生态系统中知名度最高的模板之一,这并非没有原因。JDBC 是 Java 生态系统中用于处理 SQL 数据库的低级 API。它非常强大,并且已经主导了几十年。但归根结底,它非常低级。你自己编写这部分代码将无法走得很远。

当时,替代方案是脆弱的技术,如 Hibernate、Apache OJB、各种稍微不兼容的 JDO 实现、iBatis,或者——天哪!——EJB 1.x 或 2.x 持久化实体 Bean。大多数这些方案对于我当时想做的工作来说都过于笨重。我喜欢 iBatis(并且继续喜欢它的 后继者 MyBatis),但我发现仅使用 JdbcTemplate 就能取得很大的进展。

JdbcTemplate 是处理 SQL 数据库的丰富类结构和各种抽象的一部分。如今,Spring 开发者甚至有了 JDBC 的一个非阻塞、响应式替代方案:R2DBC。尽管如此,如今大多数数据访问逻辑(如果不是其他的话)都间接使用了 JDBC,让我们来看一个例子。

代码如下

package bootiful.data;

import lombok.SneakyThrows;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.util.FileCopyUtils;

import javax.sql.DataSource;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;

@SpringBootApplication
public class BootifulApplication {

	public static void main(String[] args) {
		SpringApplication.run(BootifulApplication.class, args);
	}

	@Bean
	DataSource dataSource() {
		return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
	}

	@SneakyThrows
	private String loadSql() {
		Resource resource = new ClassPathResource("/initialization.sql");
		try (Reader r = new InputStreamReader(resource.getInputStream())) {
			return FileCopyUtils.copyToString(r);
		}
	}

	@Bean
	ApplicationListener<ApplicationReadyEvent> ready(DataSource dataSource) {
		return event -> {
			String sql = loadSql();
			String[] names = new String[] { "Spencer", "Violetta", "Madhura", "Yuxin", "Stéphane", "Dr. Syer" };
			JdbcTemplate template = new JdbcTemplate(dataSource);
			template.execute(sql);
			for (var name : names) {
				template.update("insert into CUSTOMER(name) values(?)", name);
			}
			List<Customer> results = template.query("select * from CUSTOMER",
					(resultSet, i) -> new Customer(resultSet.getInt("id"), resultSet.getString("name")));
			results.forEach(System.out::println);
		};
	}

}

如果你不介意卷起袖子写一点 SQL(为什么不呢?SQL太棒了!),那么使用 JdbcTemplate 和 JDBC 模块中的各种命令类,你会感觉如鱼得水。如果不是,Spring 依然能满足你的需求,它为 JOOQ、Hibernate、JPA、MyBatis、Spring Data JPA、Spring Data JDBC 等以 JDBC 为中心的数据访问技术提供了丰富的集成,以及其他许多选项。

你喜欢这种一目了然的宝石挖掘方式吗?你学到了什么吗?一如既往,我渴望听到你的反馈,所以请 在 Twitter (@starbuxman) 上畅所欲言!我将带着另一期《YMNNALFT》回来,所以千万不要错过。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获得支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一份简单的订阅。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看所有