spring对jdbc的支持

在传统的web开发过程中,进行JDBC编程是十分痛苦的,如下,是我自己写的一个从mysql数据库中取出数据的代码

package com.nenu.software;

import java.sql.*;

/**
 * @author: software-liuwang
 * @time: 2017/11/18 21:07
 * @description : 传统jdbc连接mysql
 */
public class Tradition {

    //jdbc驱动
    private final static String DRIVER = "com.mysql.jdbc.Driver";
    //连接地址
    private final static String URL = "jdbc:mysql://localhost:3306/db_test";
    //mysql用户名
    private final static String USERNAME = "root";
    //mysql密码
    private final static String PASSWORD = "root";



    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            //加载驱动
            Class.forName(DRIVER);
            //获取Connection
            conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            //定义sql语句
            String sql = "SELECT * FROM `t_news`";
            //创建预处理对象
            pstmt = conn.prepareStatement(sql);
            //获取结果集
            rs = pstmt.executeQuery();
            //操作结果集
            while(rs.next()) {
                System.out.println("id = " + rs.getInt("id"));
                System.out.println("name = " + rs.getString("name"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

            if(pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

            if(conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

    }

}

上面的代码片段冗长,由于长时间不用,在写上面的代码段的时候,我发现很多地方我需要参考之前的项目,所以很容易出错。

有人在写项目的时候可能会写一套自己的DB类,简化开发代码,但由于是自己封装的,所以不够通用。而Spring的JDBC提供了一套JDBC框架,用于简化JDBC开发。

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

Spring JDBC抽象框由四部分组成:datasource、support、core、object
Spring JDBC架构图
support包:提供将JDBC异常转换为DAO非检查异常转换类、一些工具类如JdbcUtils等。
datasource包:提供简化访问JDBC 数据源(javax.sql.DataSource实现)工具类,并提供了一些DataSource简单实现类从而能使从这些DataSource获取的连接能自动得到Spring管理事务支持。
core包:提供JDBC模板类实现及可变部分的回调接口,还提供SimpleJdbcInsert等简单辅助类。
object包:提供关系数据库的对象表示形式,如MappingSqlQuery、SqlUpdate、SqlCall、SqlFunction、StoredProcedure等类,该包是基于core包JDBC模板类实现。

这里说一下core包提供的JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它完成的。

JdbcTemplate类帮助我们消除了冗长的代码,帮我们做哪些固定部分,如连接的创建和关闭,我们只做需要做的事情即可

JdbcTemplate类对可变部分采用回调接口方式实现,如ConnectionCallback通过回调接口返回给用户一个连接,从而可以使用该连接做任何事情、StatementCallback通过回调接口返回给用户一个Statement,从而可以使用该Statement做任何事情等等

前边我们已经使用过传统JDBC编程方式,接下来让我们看下Spring JDBC框架提供的更好的解决方案

<!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <!-- jdbc连接mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.25</version>
        </dependency>

        <!-- spring中jdbc所需要的jar -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>3.2.18.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>3.1.0.RELEASE</version>
        </dependency>

在使用JdbcTemplate模板类时必须通过DataSource获取数据库连接,Spring JDBC提供了DriverManagerDataSource实现,它通过包装”DriverManager.getConnection”获取数据库连接

package com.nenu.software.spring;

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

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

/**
 * @author: software-liuwang
 * @time: 2017/11/19 10:37
 * @description : 在使用JdbcTemplate模板时必须通过DataSource获取数据库连接,Spring JDBC提供了DriverManagerDataSource实现,它
 *                通过包装"DriverManager.getConnection"获取数据库连接。
 */
public class TestJdbcTemplate {

    //jdbc驱动
    private final static String DRIVER = "com.mysql.jdbc.Driver";
    //连接地址
    private final static String URL = "jdbc:mysql://localhost:3306/db_test";
    //mysql用户名
    private final static String USERNAME = "root";
    //mysql密码
    private final static String PASSWORD = "root";

    private static JdbcTemplate jdbcTemplate;

    /**
     * 在此方法中定义了DataSource并使用DataSource对象创建了JdbcTemplate对象
     */
    @BeforeClass        //junit的注解,在测试方法之前执行,且只执行一次
    public static void setUpClass() {
        //构建DriverManagerDataSource对象
        DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
        //加载驱动
        dataSource.setDriverClassName(DRIVER);
        //构建JdbcTemplate
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    /**
     * 先定义SQL,再调用JdbcTemplate的方法执行SQL,最后通过RowCallbackHandler回调处理ResultSet结果集
     */
    @Test
    public void test() {
        //声明SQL
        String sql = "SELECT * FROM `t_news`";
        jdbcTemplate.query(sql, new RowCallbackHandler() {
            public void processRow(ResultSet rs) throws SQLException {
                //处理结果集
                String name = rs.getString("name");
                System.out.println("name = " + name);
            }
        });
    }
}

输出结果
这里写图片描述

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

接下来让我们看一下如何使用JdbcTemplate来实现增删改查

package com.nenu.software.spring;

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

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

/**
 * @author: software-liuwang
 * @time: 2017/11/19 11:11
 * @description : 使用JdbcTemplate实现增删改查
 */
public class TestJdbcTemplate_1 {

    //jdbc驱动
    private final static String DRIVER = "com.mysql.jdbc.Driver";
    //连接地址
    private final static String URL = "jdbc:mysql://localhost:3306/db_test";
    //mysql用户名
    private final static String USERNAME = "root";
    //mysql密码
    private final static String PASSWORD = "root";

    private static JdbcTemplate jdbcTemplate;

    /**
     * 在此方法中定义了DataSource并使用DataSource对象创建了JdbcTemplate对象
     */
    @BeforeClass
    public static void setUpClass() {
        //构建DriverManagerDataSource对象
        DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
        //加载驱动
        dataSource.setDriverClassName(DRIVER);
        //构建JdbcTemplate
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Before
    public void createTable() {
        String createTableSql = "CREATE TABLE `t_test` (" +
                "  `id` int(11) NOT NULL AUTO_INCREMENT," +
                "  `test_name` varchar(50) DEFAULT NULL," +
                "  PRIMARY KEY (`id`)" +
                ")";
        jdbcTemplate.update(createTableSql);
    }
    @After
    public void dropTable() {
        String dropTableSql = "DROP TABLE `t_test`";
        jdbcTemplate.execute(dropTableSql);
    }

    private void insert() {
        jdbcTemplate.update("INSERT INTO `t_test`(`test_name`) VALUES ('name1')");
        jdbcTemplate.update("INSERT INTO `t_test`(`test_name`) VALUES ('name2')");

        //spring3.2.2后,jdbcTemplate.qyeryForInt()方法过时,现在一般使用jdbc.queryForObject
//        System.out.println("count after insert = " + jdbcTemplate.queryForInt("SELECT COUNT(*) FROM `t_test`"));
        System.out.println("count after insert = " + jdbcTemplate.queryForObject("SELECT COUNT(*) FROM `t_test`", Integer.class));
    }
    private void delete() {
        jdbcTemplate.update("DELETE FROM `t_test` WHERE `test_name` = 'name2'");
        System.out.println("count after delete = " + jdbcTemplate.queryForObject("SELECT COUNT(*) FROM `t_test`", Integer.class));
    }
    private void update() {
        jdbcTemplate.update("UPDATE `t_test` SET `test_name` = 'name3' WHERE `test_name` = 'name1'");
        System.out.println("count name3 after update = " + jdbcTemplate.queryForObject("SELECT COUNT(*) FROM `t_test`", Integer.class));
    }
    private void select() {
        jdbcTemplate.query("SELECT * FROM `t_test`", new RowCallbackHandler() {
            public void processRow(ResultSet rs) throws SQLException {
                System.out.print("-----id : " + rs.getInt("id"));
                System.out.println(", name : " + rs.getString("test_name"));
            }
        });
    }

    @Test
    public void test() {
        insert();
        delete();
        update();
        select();
    }

}

输出结果
这里写图片描述

JdbcTemplate主要提供以下五类方法:

execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
(
    补一波课:
    SQL语言分为这么几种:
    (1)数据定义语言(DDL):用来建立数据库、数据库对象和定义列的命令。包括:create、alter、drop
    (2)数据操纵语言(DML):用来操纵数据库中数据的命令。包括:select、insert、update、delete。
    (3)数据控制语言(DCL):用来控制数据库组件的存取许可、权限等的命令。包括:grant、deny、revoke
    (4)其他语言元素:如流程控制语言、内嵌函数、批处理语句等。
)
**update方法及batchUpdate方法:**update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
query方法及queryForXXX方法:用于执行查询相关语句;
需要提及的是queryForXXX方法有些已经过时了,已经改成queryForObject和queryForList方法了
call方法:用于执行存储过程、函数相关语句。

除此之外,JdbcTemplate类还支持很多回调类,比如ConnectionCallback,能够通过回调获取JdbcTemplate提供的Connection,类似的比如StatementCallback,PreparedStatementCallback,这里就不做过多介绍了

除此之外,Spring还提供了另外的两个模板类:

SimpleJdbcTemplate:也是基于JdbcTemplate的类,但利用java5+的可变参数列表和自动装箱和拆箱从而获取更简洁的代码,但是自从Spring3.1开始,JdbcTemplate和NamedParameterJdbcTemplate都提供了SimpleJdbcTemplate的功能,所以Spring3.1之后,SimpleJdbcTemplate就被标记为过时了。

NamedParameterJdbcTemplate:它能够在执行查询时把值绑定到SQL里的命名参数,而不是使用索引参数
举个例子:

package com.nenu.software.spring;

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

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: software-liuwang
 * @time: 2017/11/20 14:10
 * @description :
 */
public class TestNamedParameterJdbcTemplate {
    //jdbc驱动
    private final static String DRIVER = "com.mysql.jdbc.Driver";
    //连接地址
    private final static String URL = "jdbc:mysql://localhost:3306/db_test";
    //mysql用户名
    private final static String USERNAME = "root";
    //mysql密码
    private final static String PASSWORD = "root";

    private static JdbcTemplate jdbcTemplate;

    /**
     * 在此方法中定义了DataSource并使用DataSource对象创建了JdbcTemplate对象
     */
    @BeforeClass        //junit的注解,在测试方法之前执行,且只执行一次
    public static void setUpClass() {
        //构建DriverManagerDataSource对象
        DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
        //加载驱动
        dataSource.setDriverClassName(DRIVER);
        //构建JdbcTemplate
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Test
    public void testNamedParameterJdbcTemplate1() {
        NamedParameterJdbcTemplate namedParameterJdbcTemplate = null;
        namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);

//        String insertSql = "INSERT INTO `t_test`(`test_name`) VALUES (:name)";
//        String selectSql = "SELECT * FROM `t_test` WHERE `test_name` = :name";
//        String deleteSql = "DELETE FROM `t_test` WHERE `test_name` = :name";
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("name", "name5");
//        namedParameterJdbcTemplate.update(insertSql, paramMap);
//        namedParameterJdbcTemplate.query(selectSql, paramMap, new RowCallbackHandler() {
//            public void processRow(ResultSet resultSet) throws SQLException {
//                System.out.println(resultSet.getString("test_name"));
//            }
//        });

//        namedParameterJdbcTemplate.update(deleteSql, paramMap);
    }

}

NamedParameterJdbcTemplate类为命名参数设值有两种方式:java.util.Map和SqlParameterSource:
(1)java.util.Map:使用Map键数据来对应命名参数,而Map值数据用于设值
(2)SqlParameterSource:默认有MapSqlParameterSource和BeanPropertySqlParameterSource实现;MapSqlParameterSource实现非常简单,只是封装了java.util.Map;而BeanPropertySqlParameterSource封装了一个JavaBean对象,通过JavaBean对象属性来决定命名参数的值
我们先定义一个实体类

package com.nenu.software.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author: software-liuwang
 * @time: 2017/11/20 14:44
 * @description :
 */
@Entity
@Table(name = "t_test")
public class TestEntity {
    //id
    @Id
    private Integer id;

    //name
    @Column(name = "test_name")
    private String testName;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTestName() {
        return testName;
    }

    public void setTestName(String testName) {
        this.testName = testName;
    }
}

测试类

 //BeanPropertySqlParameterSource为从命名参数设值
    @Test
    public void testNamedParamterJdbcTemplate2() {
        NamedParameterJdbcTemplate namedParameterJdbcTemplate = null;
        namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);

        TestEntity testEntity = new TestEntity();
        testEntity.setTestName("name666");

        String insertSql = "INSERT INTO `t_test`(`test_name`) VALUES(:testName)";
        SqlParameterSource paramSource = new BeanPropertySqlParameterSource(testEntity);
        namedParameterJdbcTemplate.update(insertSql, paramSource);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值