0x00 参考

本笔记直接参考或引自如下链接文章:

https://www.w3cschool.cn/wkspring/

http://c.biancheng.net/spring/

0x01 JDBC框架概述

在使用普通的JDBC数据库时,就会很麻烦的写不必要的代码来处理异常,打开和关闭数据库连接等。但Spring JDBC框架负责所有的低层细节,从开始打开连接,准备和执行SQL语句,处理异常,处理事务,到最后关闭连接。

所以当从数据库中获取数据时,你所做的是定义连接参数,指定要执行的SQL语句,每次迭代完成所需的工作。

Spring JDBC提供几种方法和数据库中相应的不同的类与接口。我将给出使用JdbcTemplate类框架的经典和最受欢迎的方法。这是管理所有数据库通信和异常处理的中央框架类。

0x02 JdbcTemplate类

Spring框架提供的JDBC支持主要由四个包组成,分别是core(核心包)、object(对象包)、dataSource(数据源包)和support(支持包),org.springframework.jdbc.core.JdbcTemplate类就包含在核心包中。作为Spring JDBC的核心,JdbcTemplate类中包含了所有数据库操作的基本方法。

JdbcTemplate类执行SQL查询、更新语句和存储过程调用,执行迭代结果集和提取返回参数值。它也捕获JDBC异常并转换它们到org.springframework.dao包中定义的通用类、更多的信息、异常层次结构。

JdbcTemplate类继承自抽象类JdbcAccessor,同时实现了JdbcOperations接口。其直接父类JdbcAccessor为子类提供了一些访问数据库时使用的公共属性:

  • DataSource:其主要功能是获取数据库连接,具体实现时还可以引入对数据库连接的缓冲池和分布式事务的支持,它可以作为访问数据库资源的标准接口;
  • SQLExceptionTranslator:org.springframework.jdbc.support.SQLExceptionTranslator接口负责对SQLException进行转译工作。通过必要的设置或者获取SQLExceptionTranslator中的方法,可以使 JdbcTemplate在需要处理SQLException时,委托SQLExceptionTranslator的实现类完成相关的转译工作;

使用JdbcTemplate类时常见的做法是在你的Spring配置文件中配置数据源,然后共享数据源bean依赖注入到DAO类中,并在数据源的设值函数中创建了JdbcTemplate。

0x03 JDBC配置

配置模板如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http:/www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.dataSource.DriverManagerDataSource">
<!--数据库驱动-->
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<!--连接数据库的url-->
<property name= "url" value="jdbc:mysql://localhost/spring" />
<!--连接数据库的用户名-->
<property name="username" value="root" />
<!--连接数据库的密码-->
<property name="password" value="root" />
</bean>
<!--配置JDBC模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.jdbcTemplate">
<!--默认必须使用数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置注入类-->
<bean id="xxx" class="xxx">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
...
</beans>

在上述代码中,定义了三个Bean,分别是dataSource、jdbcTemplate和需要注入类的Bean。其中dataSource对应的是DriverManagerDataSource类,用于对数据源进行配置;jdbcTemplate对应JdbcTemplate类,该类中定义了JdbcTemplate的相关配置。

在定义jdbcTemplate时,需要将dataSource注入jdbcTemplate中。而在其他的类中要使用jdbcTemplate,也需要将jdbcTemplate注入使用类中(通常注入dao类中)。

在dataSource中定义了四个连接数据库的属性:

属性名 含义
driverClassName 所使用的驱动名称,对应驱动 JAR 包中的 Driver 类
url 数据源所在地址
username 访问数据库的用户名
password 访问数据库的密码

0x04 JDBC框架使用

数据访问对象(DAO)

DAO(Data Access Object)数据访问对象是一个面向对象的数据库接口。DAO类都是进行数据操作的类,是对于数据库中的数据做增删改查等操作的代码。

在Spring中,数据访问对象(DAO)支持很容易用统一的方法使用数据访问技术,如JDBC、Hibernate、JPA或者JDO。

执行SQL语句

我们看看如何使用SQL和jdbcTemplate对象在数据库表中执行CRUD(创建、读取、更新和删除)操作。

查询一个整数类型:

1
2
String SQL = "select count(*) from Student";
int rowCount = jdbcTemplateObject.queryForInt( SQL );

查询一个 long 类型:

1
2
String SQL = "select count(*) from Student";
long rowCount = jdbcTemplateObject.queryForLong( SQL );

一个使用绑定变量的简单查询:

1
2
String SQL = "select age from Student where id = ?";
int age = jdbcTemplateObject.queryForInt(SQL, new Object[]{10});

查询字符串:

1
2
String SQL = "select name from Student where id = ?";
String name = jdbcTemplateObject.queryForObject(SQL, new Object[]{10}, String.class);

查询并返回一个对象:

1
2
3
4
5
6
7
8
9
10
11
12
String SQL = "select * from Student where id = ?";
Student student = jdbcTemplateObject.queryForObject(SQL,
new Object[]{10}, new StudentMapper());
public class StudentMapper implements RowMapper<Student> {
public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
Student student = new Student();
student.setID(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setAge(rs.getInt("age"));
return student;
}
}

查询并返回多个对象:

1
2
3
4
5
6
7
8
9
10
11
12
String SQL = "select * from Student";
List<Student> students = jdbcTemplateObject.query(SQL,
new StudentMapper());
public class StudentMapper implements RowMapper<Student> {
public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
Student student = new Student();
student.setID(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setAge(rs.getInt("age"));
return student;
}
}

在表中插入一行:

1
2
String SQL = "insert into Student (name, age) values (?, ?)";
jdbcTemplateObject.update( SQL, new Object[]{"Zara", 11} );

更新表中的一行:

1
2
String SQL = "update Student set name = ? where id = ?";
jdbcTemplateObject.update( SQL, new Object[]{"Zara", 10} );

从表中删除一行:

1
2
String SQL = "delete Student where id = ?";
jdbcTemplateObject.update( SQL, new Object[]{20} );

执行DDL语句

DDL是数据定义语言的缩写,简单来说,就是对数据库内部的对象进行创建、删除、修改的操作语言。它和DML语言的最大区别是DML只是对表内部数据的操作,而不涉及到表的定义、结构的修改,更不会涉及到其他对象。DDL语句更多的是被数据库管理员(DBA)所使用,一般的开发人员很少使用。

你可以使用jdbcTemplate中的execute(..)方法来执行任何SQL语句或DDL语句。下面是一个使用CREATE语句创建一个表的示例:

1
2
3
4
5
6
String SQL = "CREATE TABLE Student( " +
"ID INT NOT NULL AUTO_INCREMENT, " +
"NAME VARCHAR(20) NOT NULL, " +
"AGE INT NOT NULL, " +
"PRIMARY KEY (ID));"
jdbcTemplateObject.execute( SQL );

Demo

StudentDAO.java,数据访问对象接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.mi1k7ea;

import javax.sql.DataSource;
import java.util.List;

public interface StudentDAO {
/**
* This is the method to be used to initialize
* database resources ie. connection.
*/
public void setDataSource(DataSource ds);
/**
* This is the method to be used to create
* a record in the Student table.
*/
public void create(String name, Integer age);
/**
* This is the method to be used to list down
* a record from the Student table corresponding
* to a passed student id.
*/
public Student getStudent(Integer id);
/**
* This is the method to be used to list down
* all the records from the Student table.
*/
public List<Student> listStudents();
/**
* This is the method to be used to delete
* a record from the Student table corresponding
* to a passed student id.
*/
public void delete(Integer id);
/**
* This is the method to be used to update
* a record into the Student table.
*/
public void update(Integer id, Integer age);
}

Student.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.mi1k7ea;

public class Student {
private Integer age;
private String name;
private Integer id;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
}

StudentMapper.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.mi1k7ea;

import org.springframework.jdbc.core.RowMapper;

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

public class StudentMapper implements RowMapper<Student> {
public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
Student student = new Student();
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setAge(rs.getInt("age"));
return student;
}
}

StudentJDBCTemplate.java,定义的DAO接口StudentDAO的实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.mi1k7ea;

import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.util.List;

public class StudentJDBCTemplate implements StudentDAO {
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public void create(String name, Integer age) {
String SQL = "insert into Student (name, age) values (?, ?)";
jdbcTemplateObject.update( SQL, name, age);
System.out.println("Created Record Name = " + name + " Age = " + age);
return;
}
public Student getStudent(Integer id) {
String SQL = "select * from Student where id = ?";
Student student = jdbcTemplateObject.queryForObject(SQL,
new Object[]{id}, new StudentMapper());
return student;
}
public List<Student> listStudents() {
String SQL = "select * from Student";
List <Student> students = jdbcTemplateObject.query(SQL,
new StudentMapper());
return students;
}
public void delete(Integer id){
String SQL = "delete from Student where id = ?";
jdbcTemplateObject.update(SQL, id);
System.out.println("Deleted Record with ID = " + id );
return;
}
public void update(Integer id, Integer age){
String SQL = "update Student set age = ? where id = ?";
jdbcTemplateObject.update(SQL, age, id);
System.out.println("Updated Record with ID = " + id );
return;
}
}

MainApp.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.mi1k7ea;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
StudentJDBCTemplate studentJDBCTemplate = (StudentJDBCTemplate)context.getBean("studentJDBCTemplate");
System.out.println("------Records Creation--------" );
studentJDBCTemplate.create("Zara", 11);
studentJDBCTemplate.create("Nuha", 2);
studentJDBCTemplate.create("Ayan", 15);
System.out.println("------Listing Multiple Records--------" );
List<Student> students = studentJDBCTemplate.listStudents();
for (Student record : students) {
System.out.print("ID : " + record.getId() );
System.out.print(", Name : " + record.getName() );
System.out.println(", Age : " + record.getAge());
}
System.out.println("----Updating Record with ID = 2 -----" );
studentJDBCTemplate.update(2, 20);
System.out.println("----Listing Record with ID = 2 -----" );
Student student = studentJDBCTemplate.getStudent(2);
System.out.print("ID : " + student.getId() );
System.out.print(", Name : " + student.getName() );
System.out.println(", Age : " + student.getAge());
}
}

Beans.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd ">

<!-- Initialization for data source -->
<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/test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>

<!-- Definition for studentJDBCTemplate bean -->
<bean id="studentJDBCTemplate" class="com.mi1k7ea.StudentJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>

</beans>

注意,在jdbc协议设置URL时,添加了参数serverTimezone值为UTC进行服务端Timezone的设置,否则会报如下错误:

1
Exception in thread "main" org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.

在执行之前,需要在数据库中执行以下SQL语句创建test数据库以及新建:

1
2
3
4
5
6
7
8
CREATE DATABASE test;
USE test;
CREATE TABLE Student(
ID INT NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL,
AGE INT NOT NULL,
PRIMARY KEY (ID)
);

创建成功后,运行MainApp成功使用JDBC框架实现数据库的连接使用:

查看数据库,数据被成功插入: