Spring系列之使用JDBC-18

使用JDBC

为 JDBC 数据库访问选择一种方法

您可以从多种方法中进行选择,以形成您的 JDBC 数据库访问的基础。除了三种风格之外JdbcTemplate,一种新的SimpleJdbcInsertSimpleJdbcCall方法优化了数据库元数据,RDBMS 对象风格采用了一种更面向对象的方法,类似于 JDO 查询设计。一旦开始使用其中一种方法,您仍然可以混合搭配以包含来自不同方法的功能。所有方法都需要兼容 JDBC 2.0 的驱动程序,而一些高级功能需要 JDBC 3.0 驱动程序。

  • JdbcTemplate是经典且最流行的 Spring JDBC 方法。这种“最低级别”的方法和所有其他方法都在幕后使用 JdbcTemplate。
  • NamedParameterJdbcTemplate包装 aJdbcTemplate以提供命名参数而不是传统的 JDBC?占位符。当 SQL 语句有多个参数时,这种方法提供了更好的文档和易用性。
  • SimpleJdbcInsertSimpleJdbcCall优化数据库元数据以限制必要配置的数量。这种方法简化了编码,因此您只需提供表或过程的名称,并提供与列名匹配的参数映射。这仅在数据库提供足够的元数据时才有效。如果数据库不提供此元数据,则必须提供参数的显式配置。
  • RDBMS 对象(包括MappingSqlQuerySqlUpdateStoredProcedure)要求您在初始化数据访问层期间创建可重用和线程安全的对象。这种方法是在 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;
        });

如果最后两个代码片段实际上存在于同一个应用程序中,那么删除两个RowMapperlambda 表达式中存在的重复项并将它们提取到单个字段中,然后可以根据需要由 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 配置文件中配置 ,然后将该共享DataSourcebean 依赖注入到 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 (这使其成为组件扫描的候选对象)并使用注释DataSourcesetter 方法@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用注释DataSourcesetter 方法@Autowired
3JdbcTemplateDataSource. _

以下示例显示了相应的 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吕布辕门

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值