广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Spring JDBC的使用详解
  • 867
分享到

Spring JDBC的使用详解

2024-04-02 19:04:59 867人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录JDBC介绍DriverManagerConnectionStatement/PreparedStatementResultSetJDBC访问数据库流程配置数据源使用JDBC操纵

JDBC介绍

从这篇文章开始,我们将会介绍SpringBoot另外一个核心的技术,即数据库访问技术,提到数据访问,学习Java的同学瞬间能就想起JDBC技术,JDBC 是 Java Database Connectivity 的全称,是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的一套标准的api,这套标准不同的数据库厂家之间共同准守,并提供各自的具体实现。如图所示:

这样设计的好处,就是Java程序只需要和JDBC API交互,从而屏蔽了访问数据库的复杂的实现,大大降低了Java程序访问数据库的复杂度。对于日常开发而言,我们只需要掌握JDBC API 规范中的几个核心编程对象即可,这些对象包括DriverManger、Connection、Statement及ResultSet。

DriverManager

DriverManager主要负责加载不同数据库厂家提供的驱动程序包(Driver),并且根据不同的请求向Java程序返回数据库连接(Connection)对象,先看下Driver接口的定义:


public interface Driver {
    //获取数据库连接
    Connection connect(String url, java.util.Properties info)
        throws sqlException;
    boolean acceptsURL(String url) throws SQLException;
    DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info)
                         throws SQLException;
    int getMajorVersion();
    int getMinorVersion();
    boolean jdbcCompliant();
    public Logger getParentLogger() throws SQLFeatureNotSupportedException;
}

Driver中有个重要的方法 connect,来提供Connection对象

不同的数据库对Driver,有具体的实现,以Mysql为例:


public class Driver extends NonReGISteringDriver implements java.sql.Driver {
    // 通过 DriverManager 注册 Driver
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
	}
	…
}

这里用到了DriverManager,DriverManager通过 registerDriver来注册不同数据库的Driver,并且还提供了getConnection返回数据库连接对象。

Connection

通过DriverManager可以获取Connetion对象,Connection对象可以理解与数据库连接的一种会话(Session),一个Connection对象代表一个数据库的连接,负责完成与数据库底层的通讯。

Connection对象提供了一组重载的方法来创建Statement和PreparedStatement,Statement和PreparedStatement是SQL执行的载体,另外Connection对象还会涉及事务相关的操作。

Connection对象最核心的几个方法如下:


public interface Connection  extends Wrapper, AutoCloseable {
	//创建 Statement
	Statement createStatement() throws SQLException;
	//创建 PreparedStatement
	PreparedStatement prepareStatement(String sql) throws SQLException;
	//提交
	void commit() throws SQLException;
	//回滚
	void rollback() throws SQLException;
	//关闭连接
	void close() throws SQLException;
}

Statement/PreparedStatement

Statement和PreparedStatement是由Connection对象来创建的,用来执行静态的SQL语句并且返回生成的结果集对象,这里存在两种类型,一种是普通的Statement,另外一种支持预编译的PreparedStatement。

所谓预编译,是指数据库的编译器会对 SQL 语句提前编译,然后将预编译的结果缓存到数据库中,下次执行时就可以通过替换参数并直接使用编译过的语句,从而大大提高 SQL 的执行效率。

以Statement为例,看下Statement最核心的方法:


public interface Statement extends Wrapper, AutoCloseable {
	//执行查询语句
	ResultSet executeQuery(String sql) throws SQLException; 
	//执行更新语句
	int executeUpdate(String sql) throws SQLException; 
	//执行 SQL 语句
	boolean execute(String sql) throws SQLException; 
	//执行批处理
    int[] executeBatch() throws SQLException;
}

ResultSet

通过Statement或PreparedStatement执行SQL语句,我们引出了另外一个对象即为ResultSet对象,代码如下:


public interface ResultSet extends Wrapper, AutoCloseable {
	//获取下一个结果
	boolean next() throws SQLException;
	//获取某一个类型的结果值
	Value getXXX(int columnIndex) throws SQLException;
	…
}

ResultSet对象提供了next()方法,用来对整个结果集遍历操作,如果next()方法返回为true,说明还有下一条记录,

我们可以调用 ResultSet 对象的一系列 getXXX() 方法来取得对应的结果值。

JDBC访问数据库流程

对于开发人员而言,通过JDBC的API是Java访问数据库的主要途径,下面用代码来展示下访问数据库的一个整体流程:


String url = "jdbc:mysql://localhost:3306/test" ;
String username = "root" ;
String passWord = "root" ;

//1.通过DriverManager获取connection连接
Connection connection = DriverManager.getConnection(url,username,password);

//2.创建preparedStatement
PreparedStatement preparedStatement = connection.prepareStatement("select * from user");

//3.执行SQL返回ResultSet
ResultSet resultSet = preparedStatement.executeQuery();

//4.遍历resultSet结果集
while (resultSet.next()){
    //resultSet.getString("1");
}

//5.释放资源
resultSet.close();
preparedStatement.close();
connection.close();

配置数据源

上面我们在介绍JDBC的时候,Connection对象是通过DriverManager获取,Connection对象代表着和数据库的连接,每次通过DriverManager获取比较耗时,影响了系统的性能。那有没有办法能够复用Connection对象呢,答案是肯定的

JDBC给我们提供了DataSource接口来实现Connection的复用,核心代码如下:


public interface DataSource  extends CommonDataSource, Wrapper {
 
  Connection getConnection() throws SQLException;
 
  Connection getConnection(String username, String password)
    throws SQLException;
}

作为一种基础组件,不需要开发人员自己实现 DataSource,因为业界已经存在了很多优秀的实现方案,如 DBCP、C3P0 、Druid 、Hikari等

springBoot默认HikariDataSource作为DataSource的实现,现在我们SpringBoot为例,看下SpringBoot如何通过JDBC来操作数据库的,在进行数据库操作之前,我们首先需要先配置DataSource,SpringBoot配置DataSource非常简单,只需要在配置文件中添加DataSource的配置:


spring:
  # datasource 数据源配置内容
  datasource:
    url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root

使用JDBC操纵数据库

DataSource配好后,我们在本地的数据库服务中,创建一个test数据库,并且执行以下DDL创建user表


CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户名',
  `password` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

接下来我们创建一个实体类,实体类中属性和user表中字段一一对应


@Data
public class User {
    
    private Integer id;
    
    private String username;
    
    private String password;
    
    private Date createTime;

}

注意:这里使用了Lombok的@Data注解来生成get/set方法。

我们再定义一个UserDao接口,


public interface UserDao {
    
    Integer insert(User user);
    
    User selectById(Integer id);
    
    Integer updateById(User user);
    
    Integer deleteById(Integer id);
}

这里之所以要抽离出一个UserDao一层有两个原因:第一UserDao只封装了对use表的数据库操作,代码易于维护和管理,第二我们可以基于UserDao接口提供不同的实现来访问数据库,比如我们可以提供基于原生JDBC的实现,也可以用JDBCTemplate实现数据库的访问,还可以通过mybatis

接下来将通过代码形式来展示下SpringBoot是如何通过JDBC API对数据库进行CRUD操作的。我们来定义UserDao的具体实现类命名为:UserRawJdbcDao实现以下方法:

新增数据


@Override
    public Integer insert(User user) {
      	final String SQL_INSERT = "INSERT INTO user(username, password, create_time) VALUES(?, ?, ?)";
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet rs = null;
        Integer count = 0;
        try{
            connection = dataSource.getConnection();
            statement = connection.prepareStatement(SQL_INSERT, Statement.RETURN_GENERATED_KEYS);
            statement.setString(1,user.getUsername());
            statement.setString(2,user.getPassword());
            statement.setTimestamp(3,new Timestamp(user.getCreateTime().getTime()));
            count = statement.executeUpdate();
            rs = statement.getGeneratedKeys();
            if(rs.next()){
                user.setId(rs.getInt(1));
            }
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            try {
                if(rs != null){
                    rs.close();
                }
                if(statement != null){
                    statement.close();
                }
                if(connection != null){
                    connection.close();
                }

            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
        return count;
    }

查询数据


@Override
    public User selectById(Integer id) {
        final String SQL_SELECT_ID = "SELECT id,username,password,create_time FROM user WHERE id = ?";
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet rs = null;
        User user = null;
        try{
            connection = dataSource.getConnection();
            statement = connection.prepareStatement(SQL_SELECT_ID);
            statement.setInt(1, id);
            rs = statement.executeQuery();
            if(rs.next()){
                user = new User();
                user.setId(rs.getInt("id"));
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                user.setCreateTime(rs.getTimestamp("create_time"));
            }
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            try {
                if(rs != null){
                    rs.close();
                }
                if(statement != null){
                    statement.close();
                }
                if(connection != null){
                    connection.close();
                }

            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return user;
    }

更新数据


@Override
    public Integer updateById(User user) {
        final String SQL_UPDATE = "UPDATE user SET username = ?, password = ? WHERE id = ?";
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet rs = null;
        Integer count = 0;

        try{
            connection = dataSource.getConnection();
            statement = connection.prepareStatement(SQL_UPDATE);
            statement.setString(1,user.getUsername());
            statement.setString(2,user.getPassword());
            statement.setInt(3,user.getId());
            count = statement.executeUpdate();
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            try {
                if(rs != null){
                    rs.close();
                }
                if(statement != null){
                    statement.close();
                }
                if(connection != null){
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return count;
    }

删除数据


@Override
    public Integer deleteById(Integer id) {
        final String SQL_DELETE = "DELETE FROM user WHERE id = ?";
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet rs = null;
        Integer count = 0;
        try{
            connection = dataSource.getConnection();
            statement = connection.prepareStatement(SQL_DELETE);
            statement.setInt(1,id);
            count = statement.executeUpdate();
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            try {
                if(rs != null){
                    rs.close();
                }
                if(statement != null){
                    statement.close();
                }
                if(connection != null){
                    connection.close();
                }

            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return count;
    }

到此,SpringBoot通过调用原生的JDBC的API完成对user表的CRUD操作,这代码对有代码洁癖的同学简直不能忍,有大量共性的代码,如创建Connection、Statement、ResultSet、资源的释放和异常的处理。这部分封装和优化SpringBoot已经处理过了,SpringBoot提供了JdbcTemplate模板工具类实现数据访问,它简化了JDBC API的使用方法。

使用JdbcTemplate操纵数据库

同UserRawJdbcDao,我们再定义UserDao的另外一套实现类命名为:UserJdbcDao,这套实现类是通过JdbcTemplate完成对数据库的操作,完成接口定义的方法如下:

新增数据


 
@Override
public Integer insert(User user){
  
    // 创建 KeyHolder 对象,设置返回的主键 ID
    KeyHolder keyHolder = new GeneratedKeyHolder();
    int count = jdbcTemplate.update(INSERT_PREPARED_STATEMENT_CREATOR_FACTORY.newPreparedStatementCreator(
            Arrays.asList(user.getUsername(),user.getPassword(),user.getCreateTime())),keyHolder);
    // 设置 ID 主键到 entity 实体中
    if (keyHolder.geTKEy() != null) {
        user.setId(keyHolder.getKey().intValue());
    }
    // 返回影响行数
    return count;
}

查询数据


  @Override
    public User selectById(Integer id){
        User result = jdbcTemplate.queryForObject("SELECT id, username, password, create_time FROM user WHERE id=?",
                new BeanPropertyRowMapper<>(User.class), id);
        return result;
    }

更新数据


  @Override
    public Integer updateById(User user) {
        return jdbcTemplate.update("UPDATE user SET username = ?, password = ? WHERE id = ?",
                user.getUsername(),user.getPassword(),user.getId());
    }

删除数据


@Override
    public Integer deleteById(Integer id){
        return jdbcTemplate.update("DELETE FROM user WHERE id = ?", id);
    }

小结

通过对比我们发现使用JdbcTemplate模板工具类可以大大减少JDBC访问数据库的代码复杂度,作为开发人员我们应该只关心业务逻辑的具体实现过程,对JDBC底层对象的创建,资源的释放,异常的捕获,应该交给框架统一维护和管理。

虽然JdbcTemplate减少的我们访问数据库的代码量,不过使用也有一些问题,比如:新增数据的时候默认无法返回生成主键的id,将SQL硬编码到Java代码中,如果SQL修改,需要重新编译Java代码,不利于系统的维护等。这时我们需要另外一个框架,它就是大名鼎鼎的Mybatis,下一篇我将会介绍SpringBoot如何整合Mybatis。

项目源码

GitHub:github.com/draGon8844/…

以上就是Spring JDBC的使用详解的详细内容,更多关于Spring JDBC的使用的资料请关注编程网其它相关文章!

--结束END--

本文标题: Spring JDBC的使用详解

本文链接: https://www.lsjlt.com/news/125100.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring JDBC的使用详解
    目录JDBC介绍DriverManagerConnectionStatement/PreparedStatementResultSetJDBC访问数据库流程配置数据源使用JDBC操纵...
    99+
    2022-11-12
  • spring对JDBC和orm的支持实例详解
    简介Spring提供的DAO(数据访问对象)支持主要的目的是便于以标准的方式使用不同的数据访问技术,如JDBC,Hibernate或者JDO等。它不仅可以让你方便地在这些持久化技术间切换, 而且让你在编码的时候不用考虑处理各种技术中特定的异...
    99+
    2023-05-31
    spring jdbc orm
  • jdbc基本使用详解
    JDBC全称Java DataBase Connectivity / java数据库连接,是使用java连接和操作数据库的最基本驱动工具。sun公司的javasoft部门开发最早的JDBC 1.0 随JDK...
    99+
    2022-10-18
  • 详解SpringBoot封装使用JDBC
    Spring Boot中可以在配置文件中直接进行数据库配置, spring.datasource.username= root spring.datasource.passwo...
    99+
    2022-11-12
  • Java中JDBC的使用教程详解
    目录概念快速入门步骤代码实现详解各个对象DriverManager:驱动管理对象Connection:数据库连接对象Statement:执行sql的对象ResultSet:结果集对象...
    99+
    2022-11-13
  • 如何使用JDBC操作数据库?JDBC API的使用详细解读
    文章目录 1. DriverManager 1.1 注册驱动 1.2 获取连接 2. Connection 2.1 获取执行sql的对象 ...
    99+
    2023-08-31
    数据库 mysql java
  • jdbc与druid连接池的使用详解
    使用jdbc实现对数据库的操作 Ⅰ 获取数据库连接 package org.example.utils; import java.sql.*; public class Java...
    99+
    2022-11-12
  • Spring-Retry的使用详解
    目录1 Spring-Retry的简介2 Spring中的应用1 导入maven坐标2 添加被调用类3 添加测试类3 SpringBoot中的应用1 导入maven坐标2 添加一个管...
    99+
    2022-11-12
  • Spring中ResponseBodyAdvice的使用详解
    目录1 ResponseBodyAdvice的简介2 ResponseBodyAdvice的使用1 准备一个SpringBoot项目环境3 添加一个返回包装类4 添加控制类5 接口测...
    99+
    2022-11-12
  • 一文带你学会Spring JDBC的使用
    目录1、JDBC2、使用2.1、配置数据源2.2、HikariCP2.3、JdbcTempLate1、JDBC JDBC 就是 数据库开发 操作的 代名词,因为只要是现代商业项目的开...
    99+
    2022-11-13
  • 详解Spring中的@PropertySource注解使用
    @PropertySource注解是Spring用于加载配置文件,默认支持.properties与.xml两种配置文件。@PropertySource属性如下: name:...
    99+
    2022-11-12
  • 详解Spring中Lookup注解的使用
    我们知道在spring容器中单独的一个抽象类是不能成为一个bean的,那么有没有办法呢?这个时候我们可以使用Lookup注解,我们可以看下spring的扫描bean部分逻辑。我们知道...
    99+
    2022-11-12
  • Spring中WebDataBinder使用详解
    Spring MVC Validator @InitBinder and WebDataBinder;Validator是一个用来我们自定义验证的sping接口,WebDataBinder 绑定你的自定义参数,你直接在你的控制器类中通过@I...
    99+
    2023-05-31
    spring webdatabinder dat
  • Spring Boot 使用Druid详解
    Druid是Java语言中最好的数据库连接池,并且能够提供强大的监控和扩展功能,下面来说明如何在 SpringBoot 中配置使用Druid。步骤: 在pom.xml中加载依赖 在application.properties中加入数据源配置...
    99+
    2023-05-31
    spring boot druid
  • spring缓存cache的使用详解
    目录spring缓存cache的使用springcache配置缓存存活时间spring缓存cache的使用 在spring配置文件中添加schema和spring对缓存注解的支持: ...
    99+
    2022-11-12
  • Spring P标签的使用详解
    目录Spring P标签的使用本例设计对象Topic、Speech和Speakerspring配置p标签问题今天学习spring遇到这样的一个问题解决方法如下Spring P标签的使...
    99+
    2022-11-12
  • Spring中ClassPathXmlApplicationContext类的使用详解
    ClassPathXmlApplicationContext类的使用 一、简单的用ApplicationContext做测试 获得Spring中定义的Bean实例(对象).可以用: ...
    99+
    2022-11-12
  • 详解Java使用JDBC连接MySQL数据库
    一:什么是数据库,为什么要有数据库? 数据,数据库,数据库管理系统和数据库系统是与数据库技术密切相关的四个基本概念。 数据库相信大家都耳熟能详了,其实数据库顾名思义就是存放数据的仓库...
    99+
    2022-11-12
  • 详解如何使用MyBatis简化JDBC开发
    目录1. 前言2. JDBC 存在的缺点3. MyBatis 优化4. MyBatis 快速入门5. 总结1. 前言 JavaEE 企业级 Java 项目中的经典三层架构为表现层,业...
    99+
    2023-01-29
    MyBatis简化JDBC开发 MyBatis简化JDBC MyBatis JDBC
  • Java Spring的使用注解开发详解
    目录使用注解开发1.bean2.属性如何注入3.衍生的注解4.自动装配5.作用域6.小结代码show1.新建一个模块:2.新建pojo包及类3.新建dao包及类4.新建service...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作