关于Spring连接数据库

小编 2026-06-16 阅读:1530 评论:0
目录 概述 JDBC JdbcTemplate jdbcTemplate查询query jdbcTemplate更新操作update/delete... jdbcTemplate最佳实践 数据...

目录

概述

JDBC

JdbcTemplate

jdbcTemplate查询query

jdbcTemplate更新操作update/delete...

jdbcTemplate最佳实践

数据库连接和DataSource


概述

Spring框架提供了可扩展的SQL数据库的支持。然而spring的东西使用久了之后,如果不去了解背后的原理的话可能越来越迷糊,本篇博客的目的是为了 分析spring框架如何实现的和各种数据库在各种场景下的连接配置的问题。我们将从最原生java数据库连接讲起。

JDBC

相信不少学习java的朋友在第一次接触数据库的时候,一定都接触过最原生的数据库连接,以mysql为例,大致代码按如下:

try{
    //加载JDBC驱动程序:
    Class.forName(\"com.mysql.jdbc.Driver\");

    String url = \"jdbc:mysql://127.0.0.1:3306/dbname\";
    String username = \"\";
    String password = \"\";

    // 创建与MySQL数据库的连接类的实例
    Connection conn = DriverManager.getConnection(url, username, password);

    // 用conn创建Statement对象类实例
    Statement sql_statement = conn.createStatement();

    // 执行sql
    ResultSet result = sql_statement.executeQuery(query);
    //处理结果
     ...
}catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                // 关闭连接
                try {
                    conn.close();
                    System.out.println(\"Database connection terminated\");
                } catch (Exception e) { /* ignore close errors */
                }
      }
 }

上面的代码就是纯jdbc的连接数据库代码,只需安装jdk导入java 的原生包就可以写出来,不需要使用任何第三方的包。

上述代码主要有下面这几个步骤:

  1. 加载JDBC驱动程序
  2. 创建数据库的连接(需要用户名密码等信息) 
  3. 创建一个Statement  
  4. 执行SQL语句(处理结果)
  5. 处理异常,关闭连接  

上面的代码可以看出一些问题,比如模版代码过多,对于一个用户来说,他可能只是想执行一条sql语句,并不想关心其他连接,异常处理,加载驱动的问题。我们可以很容易想到的是,如果有一个方法或者一个工具,让用户可以只需要指定好数据库连接信息,就可以执行各种数据库操作,岂不是非常好吗?这就是框架开发这想做的事情。

JdbcTemplate

JdbcTemplate是spring提供的最经典也是最流行的jdbc实现方式之一。现在除了JdbcTemplate之外,还有SimpleJdbcInsert,SimpleJdbcCall两个更新的实现方式。

JdbcTemplate是“最底层”的方法,所有其他spring的方法在他们的包装之下都使用了JdbcTemplate。

JdbcTemplate是spring JDBC core这个包中的重点类。 它处理资源的创建和释放,帮助我们避免常见错误,例如上面直接使用java原生代码而忘记关闭连接。 它执行核心JDBC工作流的基本任务(例如语句创建和执行),应用程序代码只需要提供SQL并提取结果。 JdbcTemplate类主要包含下面这些功能:

  • 执行SQL查询语句
  • 执行更新语句和存储过程调用
  • 对ResultSet实例执行迭代并提取返回的参数值。
  • 捕获JDBC异常并将它们转换为org.springframework.dao packag中定义的通用的,信息量更大的异常层次结构。

使用jdbcTemplate需要配置datasource。使用spring ioc容器的话,则可以把datasource配置为一个bean,直接让数据库操作的时候引用即可。spring文档特别指出:应始终将DataSource配置为Spring IoC容器中的bean。这说明spring对于ioc容器中的datasource bean提供了非常多方便的功能。

我们可以使用jdbcTemplate来执行查询,更新,以及一些其他操作。如下:

jdbcTemplate查询query

下面的例子是返回数据的数量

int rowCount = this.jdbcTemplate.queryForObject(\"select count(*) from t_actor\", Integer.class);

下面的查询是返回一个字符串:

String lastName = this.jdbcTemplate.queryForObject(
        \"select last_name from t_actor where id = ?\",
        new Object[]{1212L}, String.class);

也可以查询并填充单个对象:

Actor actor = this.jdbcTemplate.queryForObject(
        \"select first_name, last_name from t_actor where id = ?\",
        new Object[]{1212L},
        new RowMapper<Actor>() {
            public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
                Actor actor = new Actor();
                actor.setFirstName(rs.getString(\"first_name\"));
                actor.setLastName(rs.getString(\"last_name\"));
                return actor;
            }
        });

查询并填充一系列对象:

List<Actor> actors = this.jdbcTemplate.query(
        \"select first_name, last_name from t_actor\",
        new RowMapper<Actor>() {
            public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
                Actor actor = new Actor();
                actor.setFirstName(rs.getString(\"first_name\"));
                actor.setLastName(rs.getString(\"last_name\"));
                return actor;
            }
        });

在应用程序当中为了分离逻辑,我们常常将上述代码的RowMapper逻辑提出去,变成如下两个方法:

public List<Actor> findAllActors() {
    return this.jdbcTemplate.query( \"select first_name, last_name from t_actor\", new ActorMapper());
}

private static final class ActorMapper implements RowMapper<Actor> {

    public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
        Actor actor = new Actor();
        actor.setFirstName(rs.getString(\"first_name\"));
        actor.setLastName(rs.getString(\"last_name\"));
        return actor;
    }
}

值得一提的是,上述代码在spring batch的读数据环节也有应用。

jdbcTemplate更新操作update/delete...

下面是一个insert插入的例子:

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

下面是一个更新update的例子:

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

下面是一个删除的例子:

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

事实上上述三个操作我们可以看到调用的都是jdbcTemplate的同一个方法,只是sql语句不同。

jdbcTemplate最佳实践

使用jdbcTemplate的好处有线程安全,配置简单,只需一次配置即可等有点。在使用jdbcTemplate的时候也有最佳实践可以遵循。

使用JdbcTemplate类时的常见做法是在Spring配置文件中配置DataSource,然后将共享的DataSource的bean依赖注入到DAO类中。 JdbcTemplate是在DataSource的setter中创建的。 这意味着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...
}

对应的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
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://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>

在使用springboot开发的实际体验中,我们常常用java注解配置以及application.properties配置文件代替上述内容,但是其内容都是一样的,必定有驱动名,url,用户名,密码等信息,这就是和我们使用原生jdbc代码去连数据库有联系的地方。无论使用何种方式,该有的一个也不会少。

无论您选择使用上述哪种模板初始化样式,每次要运行SQL时,很少有需要创建JdbcTemplate类的新实例。 配置完成后,JdbcTemplate实例是线程安全的。 如果我们应用程序访问多个数据库,则可能需要多个JdbcTemplate实例(例如做数据迁移,就是一个典型的场景),这需要多个DataSource,随后需要多个不同配置的JdbcTemplate实例。

关于JdbcTemplate的内容我们暂时了解到这里,他当然还提供了很多其他方法,可以在需要使用时直接查看其文档或者接口即可。

数据库连接和DataSource

我们在上面已极多次提到了DataSource,可以猜出它是spring用来管理数据库连接的,现在,我们专门来研究一下dataSource的内容。

Spring通过DataSource获取与数据库的连接。 DataSource是java定义的JDBC规范的一部分,是一个通用的连接工厂。 它允许容器或框架从应用程序代码中隐藏连接池和事务管理问题。在大型项目中,作为开发人员,则无需了解有关如何连接到数据库的详细信息。 这是设置数据源的管理员的责任。 

使用Spring的JDBC层时,可以从JNDI获取数据源,也可以使用第三方提供的连接池实现配置自己的数据源。 流行的实现是Apache Jakarta Commons DBCP和C3P0。 Spring发行版中的实现仅用于测试目的,不提供池。

以下示例是如何在Java中配置DriverManagerDataSource类型的datasource的例子:

DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(\"org.hsqldb.jdbcDriver\");
dataSource.setUrl(\"jdbc:hsqldb:hsql://localhost:\");
dataSource.setUsername(\"sa\");
dataSource.setPassword(\"\");

可以看到配置的就是连接数据库必须的信息。

下面是一个DBCP实现的DataSource配置

<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\"/>

虽然实现类不一样,其他其要求的配置都是一样的。

除了上述的配置方式外,我们还有下面这些方法配置datasource

  • 使用DataSourceUtils类提供的功能,
  • 实现SmartDataSource
  • 继承AbstractDataSource
  • 使用SingleConnectionDataSource
  • 使用DriverManagerDataSource
  • 使用TransactionAwareDataSourceProxy

上述方式就不一一展开,我们可以在使用时根据需求选择。

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表