Spring学习手册(12)—— Spring JDBC数据库访问

通过学习Spring的IOC技术和AOP技术,我们可以管理类之间的依赖并从另一个角度来设计和实现项目中身份校验、日志记录等功能。为使项目能真正的面向用户,我们需要把数据进行持久化:用户更改提交的信息可以再次被访问到。因此,接下来的文章中我们将学习Spring的数据访问功能。
我们将会先学习Spring基于JDBC的数据访问方式,为提高代码效率我们将进一步学习讲解Mybatis框架。

为了更好更方便的理解文章内容需要以下知识储备和环境准备工作:

  • 基本的SQL知识;
  • 基础的java访问数据库知识;
  • 本机安装mysql;

一、DataSource配置

DataSource是JDBC规范的一部分,它是一个通用连接工厂类。通过它容器或框架可以隐藏连接池和事务管理的代码细节。Spring通过DataSource来获取数据库的连接,因此我们使用Spring来访问数据库,首先要配置DataSourcebean。
Spring支持三种DataSource配置方式:

  • JDBC方式
  • DBCP方式
  • C3P0方式

我们会以XML配置方式展示三种配置方式,但是本文我们依然主要使用JDBC方式。

1.1 JDBC配置方式

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <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"/>

上面为Spring JDBC配置方式模版,我们将类DriverManagerDataSource定义为dataSource的bean,并且为该dataSource配置属性。需要注意的是该配置模版中我们使用了${}方式为属性设置值,其中真实的值我们配置在jdbc.properties文件中,使用<context:property-placeholder location="jdbc.properties"/>将配置信息加载,Spring会使用该文件内的键值对替换${}jdbc.properties文件样式如下:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/score_manager
jdbc.username=root
jdbc.password=root 

其中jdbc.driverClassName设置数据驱动类,这里使用mysql数据驱动,jdbc.url指定连接数据库,这里指向本地数据库,端口3306,数据库名为score_manager。jdbc.usernamejdbc.password设置访问数据库的用户名和密码,具体根据你数据库配置进行更改。
当然,如果是用于学习或试验,我们可以直接将jdbc.properties的内容写到DataSource配置文件中,上述配置文件可写成如下方式,效果相同:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/score_manager"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>

1.2 DBCP配置方式

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

该配置方式与JDBC配置方式相似,这里就不进一步陈述了。但需要注意的是,具体的driverClassNameurl配置方式,需要查看具体的数据库产品文档说明。

1.3 C3P0配置方式

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass" value="${jdbc.driverClassName}"/>
    <property name="jdbcUrl" value="${jdbc.url}"/>
    <property name="user" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

<context:property-placeholder location="jdbc.properties"/>

二、Spring JDBC访问数据

Spring框架的JDBC抽象为开发者提供高效、便捷的数据库访问操作。Spring为我们提供了如下工具类来访问数据库:

  • JdbcTemplate
  • NamedParameterJdbcTemplate
  • SimpleJdbcInsert
  • SimpleJdbcCall

其中JdbcTemplate是Spring JDBC抽象中最核心的类;NamedParameterJdbcTemplate类封装了JdbcTemplate,使用命名参数来代替SQL语句中的?

2.1 JdbcTemplate

Jdbc配置

代码模版

public class StudentDAOImpl  implements StudentDAO{
    
    private JdbcTemplate jdbcTemplate;

    //数据访问方法
    ......
    //属性注入
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
}

如上代码实现,我们持有JdbcTemplate类的私有属性,并且使用set注入的方式将配置好的Datasource传入,初始化jdbcTemplate变量。

XML文件配置:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/score_manager"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>

<bean id="studentDao" class="com.liangwei.learnspring.dao.impl.StudentDAOImpl">
    <property name="dataSource" ref="dataSource"/>
</bean>

JdbcTemplate提供了丰富的方法用于执行数据库访问:查询、插入、更新、删除。我们这里大致介绍下queryupdate等方法。

查找

查询
JdbcTemplate提供了多种查询方法,若我们期望查询的为单个符合条件的结果,则可食用queryForObject方法,若多行,则可直接使用query方法。

查询符合数据的行数:

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

根据多个条件查询某个结果

String name = this.jdbcTemplate.queryForObject("select name from student where id = ? and gender=? ",String.class,1,"F");

当然我们也可以使用如下语句:

String name = this.jdbcTemplate.queryForObject("select name from student where id = ? and gender=? ",new Object[]{1,"F"},String.class);

查询自定义的数据类型对象:
首先我们定义数据类如下:

public class Student {

    private int id;

    private String name;

    private String gender;

    private int age;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString(){
        return "["+id+","+name+","+gender+","+age+"]";
    }
}

查询语句如下:

Student student = this.jdbcTemplate.queryForObject("select * from student where id = ?", new Object[]{1},
                new RowMapper<Student>() {
            public Student mapRow(ResultSet rs, int rowNum) throws SQLException {

                Student tmp = new Student();
                tmp.setId(Integer.parseInt(rs.getString("id")));
                tmp.setName(rs.getString("name"));
                tmp.setGender(rs.getString("gender"));
                tmp.setAge(Integer.parseInt(rs.getString("age")));
                return tmp;

            }
        });

当然,当我们需要查询多个满足对象的结果是,可以使用如下方法:

 List<Student> students = this.jdbcTemplate.query("select * from student", new RowMapper<Student>() {
            public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
                Student tmp = new Student();
                tmp.setId(Integer.parseInt(rs.getString("id")));
                tmp.setName(rs.getString("name"));
                tmp.setGender(rs.getString("gender"));
                tmp.setAge(Integer.parseInt(rs.getString("age")));
                return tmp;

            }
        });
更新

插入数据:

this.jdbcTemplate.update(
                "insert into student (id,name,gender,age) values(?,?,?,?)", 
       student.getId(),student.getName(),student.getGender(),student.getAge());

更新数据

this.jdbcTemplate.update("UPDATE student  set gender=? where id = ?",student.getGender(),student.getId());

删除数据

this.jdbcTemplate.update("delete from student where id=?",student.getId());

2.2 NamedParameterJdbcTemplate

NamedParameterJdbcTemplate封装了JdbcTemplate,但是正如它名字所体现的那样,它不实用?来构造SQL语句,而是使用参数命名的方式来构造SQL语句,在内部完成SQL语句的组装。接下来我们简要介绍下该类用法。

配置

public class StudentDAOImpl  implements StudentDAO{
    
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    //数据访问方法
    ......
    //属性注入
    public void setDataSource(DataSource dataSource) {
        this. namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
    }
}

XML配置和JdbcTemplate相同,可直接参考JdbcTemplate配置。

查询数据

String sql = "select * from student where id = :studentId";
SqlParameterSource namedParameters = new MapSqlParameterSource("studentId", id);
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);

如上所示,我们使用MapSqlParameterSource为sql语句中的参数赋值,当我们需要为多个参数赋值时,我们还可以使用Map类型的类:

Map<String, String> namedParameters = Collections.singletonMap("studentId", id);

我们创建了一个Map,可以为SQL语句中的多个参数赋值。

三、JDBC访问实战

学习了Spring JDBC知识,我们接下来通过代码实战来巩固一下(假设此时你本地已安装配置好MySQL数据库)。该例子使用JdbcTemplate来访问数据库,尽量使用到前文讲述到的知识,你可以下载代码在本地运行,并通过修改来巩固所需到的知识。不过在运行代码之前你需要做好下面的准备工作:

  1. 创建数据库:score_manager。
  2. 创建数据表:student,表结构如下:
列名 类型
id int
name varchar(20)
gender char(1)
age int

代码下载地址

四、总结

本文我们学习了如何使用Spring JDBC来访问数据库,并且以常用数据库MySQL为例进行代码实战练习。Spring的JDBC抽象极大的提升了程序员对数据库开发的效率,不需要再关心数据库连接获取、准备和运行句子、检索结果集、关闭连接等繁杂的工作。但通过前面的实战练习也许你也发现构造SQL语句,为句子中的参数赋值;若获取自定义定义对象则需要从结果集获取数据并对自定义对象赋值。我们将在下篇文章学习如何解决这些问题,进一步提升工作效率。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容

  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,802评论 6 342
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,650评论 18 139
  • 主要内容 定义Spring的数据访问支持 配置数据库资源 使用Spring提供的JDBC模板 写在前面:经过上一篇...
    程序熊大阅读 8,754评论 1 31
  • 第一、2017年的梦想清单 工作 1.暑假努力实习,了解出版社的美编工作。 2.画更多的透视图,不局限于人像,争取...
    ARTQRT阅读 307评论 2 3
  • 整个知识管理体系当中,阅读占的比重非常大,其实无论是写作,做其他的输出,还是做个人品牌,我们都会发现一个问题,就是...
    牛小丫53阅读 171评论 0 2