目录
使用JDBC
为 JDBC 数据库访问选择一种方法
您可以从多种方法中进行选择,以形成您的 JDBC 数据库访问的基础。除了三种风格之外JdbcTemplate
,一种新的SimpleJdbcInsert
和 SimpleJdbcCall
方法优化了数据库元数据,RDBMS 对象风格采用了一种更面向对象的方法,类似于 JDO 查询设计。一旦开始使用其中一种方法,您仍然可以混合搭配以包含来自不同方法的功能。所有方法都需要兼容 JDBC 2.0 的驱动程序,而一些高级功能需要 JDBC 3.0 驱动程序。
JdbcTemplate
是经典且最流行的 Spring JDBC 方法。这种“最低级别”的方法和所有其他方法都在幕后使用 JdbcTemplate。NamedParameterJdbcTemplate
包装 aJdbcTemplate
以提供命名参数而不是传统的 JDBC?
占位符。当 SQL 语句有多个参数时,这种方法提供了更好的文档和易用性。SimpleJdbcInsert
并SimpleJdbcCall
优化数据库元数据以限制必要配置的数量。这种方法简化了编码,因此您只需提供表或过程的名称,并提供与列名匹配的参数映射。这仅在数据库提供足够的元数据时才有效。如果数据库不提供此元数据,则必须提供参数的显式配置。- RDBMS 对象(包括
MappingSqlQuery
、SqlUpdate
和StoredProcedure
)要求您在初始化数据访问层期间创建可重用和线程安全的对象。这种方法是在 JDO Query 之后建模的,您可以在其中定义查询字符串、声明参数并编译查询。一旦你这样做了, 就可以使用各种参数值多次调用execute(…)
、update(…)
和方法。findObject(…)
使用JdbcTemplate
JdbcTemplate
是 JDBC 核心包中的中心类。它处理资源的创建和释放,帮助您避免常见错误,例如忘记关闭连接。它执行核心 JDBC 工作流的基本任务(例如语句创建和执行),让应用程序代码提供 SQL 和提取结果。JdbcTemplate
班级:
- 运行 SQL 查询
- 更新语句和存储过程调用
- 对实例执行迭代
ResultSet
并提取返回的参数值。 - 捕获 JDBC 异常并将它们转换为
org.springframework.dao
包中定义的通用、信息更丰富的异常层次结构。
当你使用JdbcTemplate
你的代码时,你只需要实现回调接口,给他们一个明确定义的契约。
查询 ( SELECT
)
以下查询获取关系中的行数:
int rowCount = this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class);
以下查询使用绑定变量:
int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject(
"select count(*) from t_actor where first_name = ?", Integer.class, "Joe");
以下查询查找 String
:
String lastName = this.jdbcTemplate.queryForObject(
"select last_name from t_actor where id = ?",
String.class, 1212L);
以下查询查找并填充单个域对象:
Actor actor = jdbcTemplate.queryForObject(
"select first_name, last_name from t_actor where id = ?",
(resultSet, rowNum) -> {
Actor newActor = new Actor();
newActor.setFirstName(resultSet.getString("first_name"));
newActor.setLastName(resultSet.getString("last_name"));
return newActor;
},
1212L);
以下查询查找并填充域对象列表:
List<Actor> actors = this.jdbcTemplate.query(
"select first_name, last_name from t_actor",
(resultSet, rowNum) -> {
Actor actor = new Actor();
actor.setFirstName(resultSet.getString("first_name"));
actor.setLastName(resultSet.getString("last_name"));
return actor;
});
如果最后两个代码片段实际上存在于同一个应用程序中,那么删除两个RowMapper
lambda 表达式中存在的重复项并将它们提取到单个字段中,然后可以根据需要由 DAO 方法引用,这将是有意义的。例如,最好将前面的代码片段编写如下:
private final RowMapper<Actor> actorRowMapper = (resultSet, rowNum) -> {
Actor actor = new Actor();
actor.setFirstName(resultSet.getString("first_name"));
actor.setLastName(resultSet.getString("last_name"));
return actor;
};
public List<Actor> findAllActors() {
return this.jdbcTemplate.query("select first_name, last_name from t_actor", actorRowMapper);
}
更新 ( INSERT
, UPDATE
, 和DELETE
)JdbcTemplate
您可以使用该update(..)
方法执行插入、更新和删除操作。参数值通常作为变量参数提供,或者作为对象数组提供。
以下示例插入一个新条目:
this.jdbcTemplate.update(
"insert into t_actor (first_name, last_name) values (?, ?)",
"Leonor", "Watling");
以下示例更新现有条目:
this.jdbcTemplate.update(
"update t_actor set last_name = ? where id = ?",
"Banjo", 5276L);
以下示例删除一个条目:
this.jdbcTemplate.update(
"delete from t_actor where id = ?",
Long.valueOf(actorId));
其他JdbcTemplate
操作
您可以使用该execute(..)
方法运行任意 SQL。因此,该方法通常用于 DDL 语句。它被带有回调接口、绑定变量数组等的变体严重超载。以下示例创建一个表:
this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
以下示例调用存储过程:
this.jdbcTemplate.update(
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
Long.valueOf(unionId));
JdbcTemplate
最佳实践
一旦配置,该类的实例JdbcTemplate
是线程安全的。这很重要,因为这意味着您可以配置 单个实例,JdbcTemplate
然后安全地将这个共享引用注入到多个 DAO(或存储库)中。是有状态的JdbcTemplate
,因为它维护对 的引用DataSource
,但这种状态不是会话状态。
使用JdbcTemplate
类时的常见做法是DataSource
在 Spring 配置文件中配置 ,然后将该共享DataSource
bean 依赖注入到 DAO 类中。JdbcTemplate
是在 setter 中为DataSource
. 这导致 DAO 类似于以下内容:
public class JdbcCorporateEventDao implements CorporateEventDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
以下示例显示了相应的 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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="corporateEventDao" class="com.example.JdbcCorporateEventDao">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
</beans>
显式配置的替代方法是使用组件扫描和注释支持来进行依赖注入。在这种情况下,您可以使用 注释该类@Repository
(这使其成为组件扫描的候选对象)并使用注释DataSource
setter 方法@Autowired
。以下示例显示了如何执行此操作:
@Repository
public class JdbcCorporateEventDao implements CorporateEventDao {
private JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
1 | 用 注释类@Repository 。 |
---|---|
2 | 用注释DataSource setter 方法@Autowired 。 |
3 | JdbcTemplate 用DataSource . _ |
以下示例显示了相应的 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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- Scans within the base package of the application for @Component classes to configure as beans -->
<context:component-scan base-package="org.springframework.docs.test" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
</beans>
如果你使用 Spring 的JdbcDaoSupport
类并且你的各种 JDBC 支持的 DAO 类从它扩展,你的子类setDataSource(..)
从该类继承一个方法 JdbcDaoSupport
。你可以选择是否继承这个类。提供该类 JdbcDaoSupport
只是为了方便。
JdbcTemplate
无论您选择使用(或不使用)上述哪种模板初始化样式,每次要运行 SQL 时都很少需要创建一个类的新实例。配置后,JdbcTemplate
实例是线程安全的。如果您的应用程序访问多个数据库,您可能需要多个JdbcTemplate
实例,这需要多个DataSources
并且随后需要多个不同配置的JdbcTemplate
实例。
检索自动生成的主键
一种update()
方便的方法支持检索数据库生成的主键。另一个参数是 KeyHolder
,它包含从更新成功返回时生成的主键。没有标准的单一方法来创建适当的PreparedStatement
。
final String INSERT_SQL = "insert into my_test (name) values(?)";
final String name = "Rob";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(INSERT_SQL, new String[] { "id" });
ps.setString(1, name);
return ps;
}, keyHolder);
// keyHolder.getKey() now contains the generated key
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY