在Java应用程序开发中,使用JDBC访问MySQL数据库是Java开发者常用的技术。在Spring框架中,Spring对JDBC又进行了封装,简化了程序访问数据库的复杂度。本课主要讨论在Spring框架中如何使用封装的JDBC访问MySQL数据库。通过本课的学习,可以解决如下问题。
● 在Spring框架下,如何让程序连接数据库?
● 如何利用DAO技术从数据源读取和写入数据?
企业级应用开发都会涉及到对数据库的访问,在Java编程环境中,访问数据库是非常繁琐的事情,需要编写启动数据库连接、准备和执行SQL语句、处理事务和异常、关闭连接等大量数据库操作代码。
使用Spring框架可以简化Java程序对数据库的访问,Spring提供了一套完整的数据库访问框架,用于简化各种数据库访问技术的使用。Spring框架支持JDBC、Hibernate、Java Perssitence等数据库访问技术,本文主要讨论JDBC数据库访问技术。
1、 配置数据源
要让Spring能够访问数据库,就要把数据库的位置,以及访问数据库的账号和密码告诉Spring。这个过程称为配置数据源。Spring提供了多种方式配置数据源,下面主要讨论基于JDBC驱动方式配置数据源。
Spring提供的JDBC驱动提供了三类数据源的配置方式,开发者可以根据程序需要选择不同的配置方式,配置方式及其配置说明如下表所示。
表1 JDBC驱动配置数据源方式

本课主要使用DriverManagerDataSource连接数据源,没有使用连接池技术。后面的课程会讨论数据库连接池技术。
数据源可以在Spring配置文件中进行配置,配置代码如下。
<!-- 配置数据源 --> <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/mooc?characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="~123456q"/> </bean>
2、创建数据访问对象(DAO)
数据访问对象(DAO)相当于程序和数据源之间的经纪人。程序要访问数据源,必须要通过DAO来访问,DAO提供了程序访问数据源必要的接口和方法,接口和方法的具体实现细节,程序并不需要了解。
DAO由数据访问对象接口、数据访问对象实现类、访问对象实体类组成。其中,数据访问对象接口定义了访问数据必要的接口声明;数据访问对象实现类实现了定义的接口,并负责从数据源读取数据,数据源可以是数据库、XML文件或者是其它存储对象;访问对象实体类定义了要访问的对象结构,假设要访问的数据对象是数据库,则该实体类定义了数据库中一个表的结构。下面以访问数据库为例,分别讨论数据访问对象接口、数据访问对象实现类和访问对象实体类。
(1)数据访问对象接口
访问数据库的操作一般是增、删、改、查。增是在指定的数据库表中插入一条记录;删是在指定的数据库表中删除一条记录;改是在指定的数据库表中修改记录;查是按指定条件查询数据库表记录。数据访问对象接口就是定义操作数据库表的增删改查接口。下面给出课程案例mooc数据库course表的DAO接口。
课程案例mooc数据库ER图如下所示。

图 1 mooc数据库ER图
mooc数据库course表结构如下。
表 2 课程表

course表DAO接口代码如下。
package com.milihua.springprogram.dao;
import java.util.List;
import javax.sql.DataSource;
import com.milihua.springprogram.entity.Course;
public interface CourseDao {
/**
* 初始化数据源
*/
public void setDataSource(DataSource ds);
/**
* 插入一条课程记录
*/
public void insertCourse(Course inCourse);
/**
* 获取课程记录,获取的课程由编号指定
*/
public Course getCourse(String number);
/**
* 获取全部课程记录
*/
public List<Course> listCourse();
/**
* 删除课程记录,删除的课程由编号指定
*/
public void delete(String number);
/**
* 更新课程记录
*
*/
public void update(Course inCourse);
}(2)数据访问对象实现类
数据访问对象实现类实现DAO接口,并负责从mooc数据库中读取数据。在Spring中,可以采用JDBC、Hibernate、MyBits、JPA等技术在DAO层实现对数据库的访问。本课采用JDBC技术,JdbcTemplate类是Spring对JDBC的封装,让JDBC更加容易使用,JdbcTemplate 类可以执行 标准的SQL 语句和过程调用。数据访问对象实现类代码如下。
package com.milihua.springprogram.jdbc;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import com.milihua.springprogram.dao.CourseDao;
import com.milihua.springprogram.entity.Course;
public class CourseJDBCTemplate implements CourseDao{
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
@Override
public void setDataSource(DataSource ds) {
// TODO Auto-generated method stub
this.dataSource = ds;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
@Override
public void insertCourse(Course inCourse) {
// TODO Auto-generated method stub
String SQL = "insert into course (number,price,brief,category,teacher_number,name) values (?,?,?,?,?,?)";
jdbcTemplateObject.update(SQL,inCourse.getNumber(),inCourse.getPrice(),inCourse.getBrief(),inCourse.getCategory(),inCourse.getTeacher_number(),inCourse.getName());
System.out.println("插入课程记录 = " + inCourse.getName());
return;
}
@Override
public Course getCourse(String number) {
// TODO Auto-generated method stub
String SQL = "select * from course where number = ?";
Course course = jdbcTemplateObject.queryForObject(SQL,
new Object[]{number}, new CourseMapper());
return course;
}
@Override
public List<Course> listCourse() {
// TODO Auto-generated method stub
String SQL = "select * from course";
List <Course> students = jdbcTemplateObject.query(SQL,new CourseMapper());
return students;
}
@Override
public void delete(String number) {
// TODO Auto-generated method stub
String SQL = "delete from course where number = ?";
jdbcTemplateObject.update(SQL, number);
System.out.println("删除课程记录 课程编号 = " + number );
return;
}
@Override
public void update(Course inCourse) {
// TODO Auto-generated method stub
String SQL = "update course set name = ? where number = ?";
jdbcTemplateObject.update(SQL, inCourse.getName(), inCourse.getNumber());
System.out.println("更新课程名称 = " + inCourse.getName() );
return;
}
}CourseJDBCTemplate类实现了CourseDao接口,并实现了接口的所有方法。CourseJDBCTemplate类内置了DataSource和JdbcTemplate类。DataSource为数据源类,存储了数据源的连接地址、登录数据源的账号密码等数据。JdbcTemplate类是Spring对JDBC的封装,JdbcTemplate 类可以执行 标准的SQL 语句和过程调用,创建JdbcTemplate类时传入的参数为DataSource。
package com.milihua.springprogram.jdbc;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import com.milihua.springprogram.dao.CourseDao;
import com.milihua.springprogram.entity.Course;
public class CourseJDBCTemplate implements CourseDao{
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
@Override
public void setDataSource(DataSource ds) {
// TODO Auto-generated method stub
this.dataSource = ds;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
@Override
public void insertCourse(Course inCourse) {
// TODO Auto-generated method stub
String SQL = "insert into "
+ "course (number,price,brief,category,teacher_number,name)"
+ " values (?,?,?,?,?,?)";
jdbcTemplateObject.update(SQL,inCourse.getNumber(),
inCourse.getPrice(),
inCourse.getBrief(),
inCourse.getCategory(),
inCourse.getTeacher_number(),
inCourse.getName());
System.out.println("插入课程记录 = " + inCourse.getName());
return;
}
@Override
public Course getCourse(String number) {
// TODO Auto-generated method stub
String SQL = "select * from course where number = ?";
Course course = jdbcTemplateObject.queryForObject(SQL,
new Object[]{number}, new CourseMapper());
return course;
}
@Override
public List<Course> listCourse() {
// TODO Auto-generated method stub
String SQL = "select * from course";
List <Course> students = jdbcTemplateObject.query(SQL,new CourseMapper());
return students;
}
@Override
public void delete(String number) {
// TODO Auto-generated method stub
String SQL = "delete from course where number = ?";
jdbcTemplateObject.update(SQL, number);
System.out.println("删除课程记录 课程编号 = " + number );
return;
}
@Override
public void update(Course inCourse) {
// TODO Auto-generated method stub
String SQL = "update course set name = ? where number = ?";
jdbcTemplateObject.update(SQL, inCourse.getName(), inCourse.getNumber());
System.out.println("更新课程名称 = " + inCourse.getName() );
return;
}
}代码中用到了JdbcTemplate类的queryForObject方法,该方法从数据库中查询符合条件的记录。queryForObject方法的第三个参数是RowMapper泛型类型,通过继承RowMapper泛型,可以将查询返回的ResultSet数据集映射到访问对象实体类。
package com.milihua.springprogram.jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
import com.milihua.springprogram.entity.Course;
public class CourseMapper implements RowMapper<Course>{
@Override
public Course mapRow(ResultSet rs, int arg1) throws SQLException {
// TODO Auto-generated method stub
Course course = new Course();
course.setNumber(rs.getString("number"));
course.setName(rs.getString("name"));
course.setBrief(rs.getString("brief"));
course.setPrice(rs.getFloat("price"));
course.setTeacher_number(rs.getString("teacher_number"));
course.setCategory(rs.getString("category"));
return course;
}
}(3)访问对象实体类
访问对象实体类定义了要访问的对象结构,假设要访问的数据对象是数据库,则该实体类定义了数据库中一个表的结构。mooc数据库course表的实体类代码如下。
package com.milihua.springprogram.entity;
public class Course {
/*
* 课程编号
*/
private String number;
/*
* 课程价格
*/
private float price;
/*
* 课程简介
*/
private String brief;
/*
* 课程类别
*/
private String category;
/*
* 老师编号
*/
private String teacher_number;
/*
* 课程名称
*/
private String name;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getBrief() {
return brief;
}
public void setBrief(String brief) {
this.brief = brief;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getTeacher_number() {
return teacher_number;
}
public void setTeacher_number(String teacher_number) {
this.teacher_number = teacher_number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}3、运行JDBC的测试程序
前面主要讨论了配置数据源和创建数据访问对象(DAO)相关内容,解决了程序如何访问数据库以及数据库表的读写问题。下面给出一个程序实例,利用前面配置的数据源和已创建的DAO对象,实现对mooc数据库course表的课程插入和查询操作。
mooc数据库非常简单,可以根据课程给出的ER图和course二维表,手动创建mooc数据库和course表。mooc数据库创建完成后,需要修改Spring配置文件中配置的数据源,主要是修改数据库的连接地址、登录账户和密码。
运行程序前需要确定项目已经引入了Spring框架关于JDBC功能的jar包。下面列出的是spring 5.0版本相关JDBC的jar包。
● mysql-connector-java-5.1.7-bin
● spring-jdbc-5.0.8.RELEASE
测试程序代码如下。
package test;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.milihua.springprogram.entity.Course;
import com.milihua.springprogram.jdbc.CourseJDBCTemplate;
public class DataBaseTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context = new ClassPathXmlApplicationContext("config/database.xml");
CourseJDBCTemplate courseJDBCTemplate =
(CourseJDBCTemplate)context.getBean("courseJDBCTemplate");
System.out.println("------插入课程记录--------" );
Course course = new Course();
course.setNumber("0001");
course.setName("Java基础教程");
course.setBrief("本课程尝试用一个编程案例与同学们探讨程序的开发流程,"
+ "然后讲述Java的基础语法,"
+ "掌握变量的意义及用法,在掌握变量的基础上,"
+ "梳理Java的数据类型及基本的输入与输出。");
course.setCategory("编程");
course.setPrice((float)39.5);
course.setTeacher_number("teacher_001");
courseJDBCTemplate.insertCourse(course);
course.setNumber("0002");
course.setName("Python教程");
course.setBrief("课程阐述Python的核心内容,包括基本的概念和语句"
+ "、Python对象、映射和集合类型、文件的输入和输出、"
+ "函数和函数式编程等内容");
course.setCategory("编程");
course.setPrice((float)29);
course.setTeacher_number("teacher_001");
courseJDBCTemplate.insertCourse(course);
System.out.println("------查询课程记录--------" );
List<Course> courses = courseJDBCTemplate.listCourse();
for (Course record : courses) {
System.out.print("课程编号 : " + record.getNumber() );
System.out.print("课程名称 : " + record.getName() );
System.out.println("课程简介: " + record.getBrief());
}
}
}程序运行结果如下图示所示。

课程小结
(1)要让Spring能够访问数据库,就要把数据库的位置,以及访问数据库的账号和密码告诉Spring,这个过程称为配置数据源。数据源可以在Spring配置文件中进行配置,也可以写成Bean的方式,由DAO对象读取。
(2)数据访问对象(DAO)相当于程序和数据源之间的经纪人。程序要访问数据源,必须要通过DAO来访问,DAO提供了程序访问数据源必要的接口和方法,接口和方法的具体实现细节,程序并不需要了解。DAO将底层数据操作细节和上层应用进行了有效隔离,在程序开发过程中,DAO和上层应用都可以独立编写代码,然后再进行集成就可以了,利用DAO层也可以轻松实现不同数据库的访问。