Spring的JDBC详解

本文详细介绍了Spring对JDBC的支持,包括JdbcTemplate、NamedParameterJdbcTemplate和SimpleJdbcTemplate的使用,以及关系数据库对象化的操作。从预编译语句、结果集处理回调到存储过程和函数的调用,全方位展示了Spring JDBC简化数据库操作的方法。
摘要由CSDN通过智能技术生成

Spring的JDBC详解

一、引言

1.JDBC回顾

传统应用程序开发中,进行JDBC编程是相当繁琐的,但却是我们入门必须掌握的技能。

步骤如下:
1.获取JDBC连接
2.声明SQL
3.预编译SQL
4.执行SQL
5.处理结果集
6.释放结果集
7.释放Statement
8.提交事务
9.处理异常并回滚事务
10.释放JDBC连接

缺点:1.冗长、重复
2.显示事务控制
3.每个步骤不可获取
4.显示处理受检查异常
Spring JDBC
声明SQL
处理结果集
优点:
    1.简单、简洁
    2.Spring事务管理
    3.只做需要做的
    4.一致的非检查异常体系

2.Spring对JDBC的支持

Spring通过抽象JDBC访问并一致的API来简化JDBC编程的工作量。我们只需要声明SQL、调用合适的SpringJDBC框架API、处理结果集即可。事务由Spring管理,并将JDBC受查异常转换为Spring一致的非受查异常,从而简化开发。

Spring主要提供JDBC模板方式、关系数据库对象方式和SimpleJbbc方式三种

JDBC模板方式:Spring JDBC框架提供以下几种模板类来简化JDBC编程,实现GoF模板设计模式,将可变部分和非可变部分分离,可变部分采用回调接口方式由用户来实现:如JdbcTemplate、NamedParameterJdbcTemplate、SimpleJdbcTemplate。

关系数据库操作对象化方式:
SpringJDBC框架提供了将关系数据库操作对象化的表示形式,从而使用户可以采用面向对象编程来完成对数据库的访问,如MappingSqlQuery、SqlUpdate、SqlCall、SqlFunction、StoredProcedure等类。这些类的实现一旦建立即可重用并且是线程安全的。

SimpleJdbc方式:Spring JDBC框架还提供了SimpleJdbc方式来简化JDBC编程,SimpleJdbcInsert、SimpleJdbcCall来简化数据库表插入、存储过程或函数访问。

Spring JDBC还提供了一些强大的工具类,如DataSourceUtils来再必要的好似好手工获取数据库连接等。

3.Spirng的JDBC架构

JDBC抽象框架由四部分组成:datasource support core object

support包:将JDBC异常转换为DAO非检查异常转换类、一些工具类如JdbcUtils等。

datasource包:提供简化访问JDBC数据源(javax.sql.DataSource实现)工具类,并提供了一些DataSource简单实现类从而能使从这些DataSource获取的连击能自动得到Spring管理事务支持

core包:提供JDBC模板类实现及可变部分的回调接口,还提供SimpleJdbcInsert等简单辅助类。

object包:提供关系数据库的对象表示形式,如MappingSqlQuery、SqlUpdate、SqlCall、SqlFunction、StoredProcedure等类,该包是基于core包JDBC模板类实现
1.准备需要的jar包并添加到类路径中
//JDBC抽象框架模块
org.springframework.jdbc-3.0.1.RELEASE-A.jar
//Spring事务管理及一致的DAO访问及非检查异常模块
org.springframework.transaction-3.0.1.RELEASE-A.jar
//mysql驱动
mysql-connector-java-5.1.7-bin.jar
2.准备数据库支持
create database study_db;

use study_db;

create table user(
    u_id int primary key auto_icrement, --用户编号
    u_name varchar(20),--用户名
    u_pass varchar(20),--密码
    type_id--用户类型
)

create table user_type(
    t_id int primary key auto_icrement,--用户类型编号
    t_name varchar(20)--类型名称
)

--为user表type_id列添加对应user_type表的外键约束
alter table user add
constraint FK_type_id foreign key (type_id) references user_type(t_id)

insert into user_type(t_name) values('系统管理员');
insert into user_type(t_name) values('网站管理员');
insert into user_type(t_name) values('普通用户');

insert into user(u_name,u_pass,type_id) values('Admin1','Admin1',1); 
insert into user(u_name,u_pass,type_id) values('Admin2','Admin2',2);
insert into user(u_name,u_pass,type_id) values('Users1','Users1',3);

传统JDBC编程替代方案
在使用JdbcTemplate模板类时必须通过DataSource获取数据库连接,Spring JDBC提供了DriverManagerDataSource实现,

3.编写数据库表对应实体类
package com.lizhenhua.test.pojo;

public class User {
   
    private Integer uid;
    private String username;
    private String password;
    private Integer typeId;

    @Override
    public String toString() {
        return "User [password=" + password + ", typeId=" + typeId + ", uid="
                + uid + ", username=" + username + "]";
    }
    public User() {
        super();
    }
    public User(Integer uid, String username, String password, Integer typeId) {
        super();
        this.uid = uid;
        this.username = username;
        this.password = password;
        this.typeId = typeId;
    }
    public Integer getUid() {
        return uid;
    }
    public void setUid(Integer uid) {
        this.uid = uid;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public Integer getTypeId() {
        return typeId;
    }
    public void setTypeId(Integer typeId) {
        this.typeId = typeId;
    }

}

这是一个普通的User类,在Spring中称之为POJO。

4.编写测试类
package com.lizhenhua.test;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.junit.BeforeClass;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import com.lizhenhua.test.pojo.User;

public class Test {
   
    private static JdbcTemplate jdbcTemplate;
    @BeforeClass
    public static void setUpClass(){
        //url指定了数据库study_db
        String url="jdbc:mysql://localhost:3306/study_db";
        //数据库用户名
        String username = "root";
        //数据库密码
        String password = "root";
        //声明并初始化数据源
        DriverManagerDataSource dataSource = new DriverManagerDataSource(url, username, password);
        //使用数据源对象创建JdbcTemplate对象,该对象是线程安全的
        jdbcTemplate =  new JdbcTemplate(dataSource);
    }
    @org.junit.Test
    public void test(){
        //1.声明SQL
        String sql = "SELECT * FROM USER";
        jdbcTemplate.query(sql, new RowCallbackHandler(){

            @Override
            public void processRow(ResultSet rs) throws SQLException {
                //2.处理结果集
                User user = new User(rs.getInt(1), rs.getString(2), rs.getString(3), rs.getInt(4));
                //3.打印数据库用户信息
                System.out.println(user);
            }

        });
    }
}

@BeforeClass:表示在所有测试方法之前执行,且只执行一次。

JdbcTemplate执行流程:首先定义SQL,其次调用JdbcTemplate方法执行SQL,最后通过RowCallbackHandler回调处理ResultSet结果集。

二、Spring的JDBC类

2.1JdbcTemplate

如何使用JdbcTemplate增删改查
package com.lizhenhua.test;

import java.sql.ResultSet;
import java.sql.SQLException;


import org.junit.BeforeClass;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import com.lizhenhua.test.pojo.User;

public class Test {
   
    private static JdbcTemplate jdbcTemplate;
    @BeforeClass
    public static void setUpClass(){
        String url="jdbc:mysql://localhost:3306/study_db";
        String username = "root";
        String password = "root";
        DriverManagerDataSource dataSource = new DriverManagerDataSource(url, username, password);
        jdbcTemplate =  new JdbcTemplate(dataSource);
    }

    public void test(){
        //1.声明SQL
        String sql = "SELECT * FROM USER";
        jdbcTemplate.query(sql, new RowCallbackHandler(){

            @Override
            public void processRow(ResultSet rs) throws SQLException {
                //2.处理结果集
                User user = new User(rs.getInt(1), rs.getString(2), rs.getString(3), rs.getInt(4));
                System.out.println(user);
            }

        });
    }
    @org.junit.Test
    public void testCURD(){
        insert();
        update();
        drop();
        select();

    }
    private void select() {

        //1.声明SQL
        String sql = "SELECT * FROM USER";
        jdbcTemplate.query(sql, new RowCallbackHandler(){

            @Override
            public void processRow(ResultSet rs) throws SQLException {
                //2.处理结果集
                User user = new User(rs.getInt(1), rs.getString(2), rs.getString(3), rs.getInt(4));
                System.out.println(user);
            }

        });
    }
    private void drop() {
        int i = jdbcTemplate.update("delete from user where u_id = ? ",9);
        //判断是否删除study03成功
        org.junit.Assert.assertEquals(1, i);
    }
    private void update() {
        int i = jdbcTemplate.update("update user set u_pass=? where u_id = ?",new Object[] {
  "study02000000",7});
        //判断是否修改成功
        org.junit.Assert.assertEquals(1, i);
    }
    private void insert() { 
        int   i = jdbcTemplate.update("insert into user(u_name,u_pass,type_id) values('study01','study01',1)");
        int j = jdbcTemplate.update("insert into user(u_name,u_pass,type_id) values('study02','study02',1)");
        int k = jdbcTemplate.update("insert into user(u_name,u_pass,type_id) values(?,?,?)",new Object[]{
  "study03","study03",1});
        //判断是否插入三条记录是否成功
        org.junit.Assert.assertEquals(3, i+j+k);
    }
}
JdbcTemplate主要提供的方法说明:

execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;
batchUpdate方法用于执行批处理相关语句;
query方法及queryForXXX方法:用于执行查询相关语句
call方法:用于执行存储过程、函数相关语句。



JdbcTemplate类支持的回调类:
预编译语句及存储过程创建回调:用于根据JdbcTemplate提供的连接创建相应的语句。

PreparedStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Connection创建相关的PreparedStatement
CallableStatementCreator:通过回调获取JdbcTemplate提供的Connection,邮用户使用该Connection创建相关的CallableStatement

预编译语句设置回调:用于给预编译语句相应参数设值。

    PreparedStatementStetter:通过回调获取JdbcTemplate提供的PreparedStatement,由用户来对相应的预编译语句相应参数设值。

    BatchPreparedStatementSetter: 类似于PreparedStatementSetter,但用于批处理,需要指定批处理大小。

自定义功能回调:提供给用户一个扩展点,用户可以在指定类型的扩展点执行任何数量需要的操作

    ConnectionCallback:通过回调获取JdbcTemplate提供的Connection,用户可在该Connection执行任何数量的操作;

    StatementCallback:通过回调获取JdbcTemplate提供的Statement,用户可以在该Statement执行任何数量的操作

    PreparedStatementCallback:通过回调获取JdbcTemplate提供的PreparedStatement,用户可以在该PreparedStatement执行任何数量的操作

    CallableStatementCallback:通过回调获取JdbcTemplate提供的CallableStatement,用户可以在该CallableStatement执行任何数量的操作

结果集处理回调:通过回调处理ResultSet或将ResultSet转换为相应的类型

    RowMapper:用于将结果集每行数据转换为需要的类型,用户需实现方法mapRow(ResultSet rs , int rowNum)来完成将每行数据转换为相应的类型。

    RowCallbackHandler:用于处理ResultSet的每一行结果,用户需实现方法processRow(ResultSet rs)来完成处理,在该方法中无需执行rs.next(),该操作由JdbcTemplate来执行,用户只需按行获取数据然后处理即可。

    ResultSetExtractor:用于结果集数据提取,用户需实现方法extractData(ResultSet rs)来处理结果集,用户必须处理整个结果集

接下来我们看下具体示例吧,在示例中不可能介绍到JdbcTemplate全部方法及回调类的使用方法,我们只介绍代表性的,其余的使用都是类似的。

1.预编译语句及预编译过程创建回调、自定义功能回调使用:
@Test
    public void testPrepareStatement1(){
        //以返回所有用户信息为例
        List<User> users = jdbcTemplate.execute(new PreparedStatementCreator() {
  //PreparedStatementCreaator通过回调获取JdbcTemplate提供的Connection,由用户使用该Connection创建相关的PreparedStatement
            //createPreparedStatement(Connection con)用于创建java.sql.PreparedStatement预处理对象
            @Override
            public PreparedStatement createPreparedStatement(Connection con)
                    throws SQLException {
                    //Connection是java.sql.Connection,因此我们就可以向使用原生JDBC连接对象
                    //返回user表中的记录数
                return con.prepareStatement("select * from user");
            }
        }, new PreparedStatementCallback<List<User>>() {
  //PreparedStatementCallback<T> 通过回调获取JdbcTemplate提供的PreparedStatement,用户可以在该PreparedStatement执行任何数量的操作
                                                        //注意<T>是回调返回的结果类型

            @Override
            public List<User> doInPreparedStatement(PreparedStatement pst)
                    throws SQLException, DataAccessException {
  //用户自行处理java.sql.PreparedStatement对象
                    //返回结果
                    List<User> users = new LinkedList<User>();
                    //执行预处理语句
                    pst.execute();
                    //获得预处理结果集
                    ResultSet rs = pst.getResultSet();
                    //处理结果集
                    while (rs.next()) {
                        User user = new User(rs.getInt(1), rs.getString(2), rs.getString(3), rs.getInt(4));
                        users.add(user);
                    }
                    return users;
            }
        });
        //打印所用用户信息
        for (User user : count) {
            System.out.println(user);
        }
    }

首先使用PreparedStatementCreator创建一个预编译语句,其次由JdbcTemplate通过PreparedStatementCallback回调传回,由用户决定该PreparedStatement。此处我们使用的是execute方法。

此种方式最好用来执行DLL语句,不然写法与JDBC编程并无太多差别。

2.预编译设值回调使用
@Test
    public void testPrepareStatement2(){
        String insertSql = "insert into user(u_name,u_pass,type_id) values(?,?,?)";
        //方式一:通过PreparedStatementSetter对预编译sql语句中的占位符进行设值。
        int count = jdbcTemplate.update(insertSql, 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值