目录
一、关于JDBC
1、JDBC简介
JDBC(Java DataBase Connectivity)可以让我们用相同的方式访问不同的数据库,它定义了一套标准的接口,即访问数据库的通用API。它是sun公司开发的一套数据库访问编程接口,由java语言编写完成。不同的数据库厂商根据自己数据库的特性去实现JDBC提供的这套接口。
JDBC具有很好的跨平台特性,使用JDBC编写的数据库应用程序可以在任何支持java的平台上运行,所以不必在不同的平台上去编写不同的应用程序。
2、JDBC接口
首先,JDBC接口分为四类
1:DriverManager:驱动管理接口
2:Connection,DatabaseMetaData:链接接口
3:Statement,PreparedStatement,CallableStatement:语句对象接口(用于执行SQL语句)
4:ResultSet,ResultSetMetaData:结果集合接口(执行select语句的结果)
DriverManager:管理一组JDBC驱动程序的基本服务,我们通过DriverManager来获取Connection。
Connection:通过驱动器DriverManager获取,用来获取Statement
Statement:用于执行SQL语句
ResultSet:在执行查询语句时的返回集接口
3、JDBC原理及工作流程
1、加载JDBC驱动程序
在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),这通过java.lang.Class类的静态方法forName(String className)实现。成功加载之后,会将Driver类的实例注册到DriverManager类中。
2、提供JDBC连接的URL
连接URL定义了连接数据库时的协议、子协议、数据源标识,
其书写格式:协议:子协议:数据源标识
String url="jdbc:mysql://localhost:3306/springtemplate
协议:在JDBC中总是以jdbc开始
子协议:是桥连接的驱动程序或是数据库管理系统名称
数据源标识:标记找到数据库来源的地址与连接端口
3、创建数据库的连接
(1)要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象,该对象就代表一个数据库的连接。
(2)使用DriverManager的getConnectin(String url , String username , String password )方法传入指定的欲连接的数据库的路径、数据库的用户名和密码来获得。
4、创建一个Statement
要执行SQL语句,必须获得java.sql.Statement实例,Statement实例分为以下3种类型:
(1)执行静态SQL语句。通常通过Statement实例实现
(2)执行动态SQL语句。通常通过PreparedStatement实例实现
(3)执行数据库存储过程。通常通过CallableStatement实例实现
5、执行SQL语句
Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate和execute
(1)ResultSet executeQuery(String sqlString):执行查询数据库的SQL语句,返回一个结果集(ResultSet)对象。
(2)int executeUpdate(String sqlString):用于执行INSERT、UPDATE或DELETE语句以及SQL DDL语句,如:CREATE TABLE和DROP TABLE等
(3)execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合的语句。
6、处理结果
此处分为两种情况:
(1)执行更新返回的是本次操作影响到的记录数
(2)执行查询返回的结果是一个ResultSet对象
ResultSet包含符合SQL查询语句中条件的所有行,并且它通过一套get方法提供了对这些行中数据的访问。
7、关闭JDBC对象
操作完成以后要把所有使用的JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声明顺序相反:
(1)关闭记录集
(2)关闭声明
(3)关闭连接对象
完整的JDBC操作数据库代码示例:
public class JDBCDemo {
public static void main(String[] args) {
String url="jdbc:mysql://localhost:3306/springtemplate?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "root";
String sql = "select * from Student";
try {
// 1、加载JDBC驱动程序
Class.forName("com.mysql.jdbc.Driver");
// 2、提供JDBC连接的URL 3、创建数据库的连接(数据库连接、账号、密码)
Connection connection = DriverManager.getConnection(url, username, password);
// 4、创建一个Statement(执行SQL平台)
Statement statement = connection.createStatement();
// 5、执行SQL语句
ResultSet rs = statement.executeQuery(sql);
// 6、处理执行结果
while(rs.next()){
System.out.println(rs.getString("name"));
}
// 7、关闭连接
rs.close();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
二、Spring JDBC框架
1、JDBCTemplate介绍
JDBC已经能够满足大部分用户最基本的需求,但是在使用JDBC时,必须自己来管理数据库资源如:获取PreparedStatement,设置SQL语句参数,关闭连接等步骤。
JDBCTemplate就是Spring对JDBC的封装,目的是使JDBC更加易于使用。
JDBCTemplate是Spring的一部分。,JDBCTemplate处理了资源的建立和释放。他帮助我们避免一些常见的错误,比如忘了总要关闭连接。
在数据库已经连接和JdbcTemplate对象已经注入的情况下,使用JdbcTemplate编程我们只需两步:
1、提供SQL语句和占位符的值
2、得到封装好的查询结果集
JdbcTemplate主要提供以下五类方法:
- execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
- update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;
- batchUpdate方法用于执行批处理相关语句;
- query方法及queryForXXX方法:用于执行查询相关语句;
- call方法:用于执行存储过程、函数相关语句。
2、使用JDBCTemplate操作数据库
(1)建立实体类Student.java
public class Student {
private Integer age;
private String name;
private Integer id;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
(2)使用XML文件加载数据库配置和注入JDBCTemplate对象
<?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/springtemplate"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- Definition for studentJDBCTemplate bean -->
<bean id="JDBCTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
(3)操作数据库
public class JDBCTemplateDemo {
public static void main(String[] args) {
// 解析配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
// 获取模板对象
JdbcTemplate template = (JdbcTemplate) context.getBean("JDBCTemplate");
/**
* 执行 INSERT,UPDATE,DELETE
*/
String sqlUpdate = "update student set name = ? where id = ?";
template.update(sqlUpdate,"Bob",3);
/**
* 测试批量更新操作
* 最后一个参数是 Object[] 的 List 类型:因为修改一条记录需要一个 Object 数组,
* 修改多条记录就需要一个 List 来存放多个数组。
*/
String batchSql = "insert into student(id, name, age) values(?,?,?)";
List<Object[]> batchArgs = new ArrayList<>();
batchArgs.add(new Object[]{4, "Lucy", 22});
batchArgs.add(new Object[]{5, "bb", 25});
batchArgs.add(new Object[]{6, "com", 30});
template.batchUpdate(batchSql,batchArgs);
/**
* 从数据库中获取一条记录,实际得到对应的一个对象
* 注意:不是调用 queryForObject(String sql, Class<Employee> requiredType, Object... args) 方法!
* 而需要调用 queryForObject(String sql, RowMapper<Employee> rowMapper, Object... args)
* 1、其中的 RowMapper 指定如何去映射结果集的行,常用的实现类为 BeanPropertyRowMapper
* 2、使用 SQL中的列的别名完成列名和类的属性名的映射,例如 name age
* 3、不支持级联属性。 JdbcTemplate 只能作为一个 JDBC 的小工具, 而不是 ORM 框架
*/
String querySql = "select * from student where id = ?";
// 指定如何去映射结果集的行
RowMapper<Student> rowMapper = new BeanPropertyRowMapper<>(Student.class);
List<Student> query = template.query(querySql, rowMapper,5);
query.stream().forEach(x-> System.out.println(x.getName()));
/**
* 获取单个列的值或做统计查询
* 使用 queryForObject(String sql, Class<Long> requiredType)
*/
String countSql = "select count(*) from student";
Long aLong = template.queryForObject(countSql, Long.class);
}
}
总结:JdbcTemplate是Spring框架自带的对JDBC操作的封装,目的是提供统一的模板方法使对数据库的操作更加方便、友好,效率也不错。但是功能还是不够强大(比如不支持级联属性),在实际应用中还需要和hibernate、mybaties等框架混合使用。
三、存储过程
存储过程(Stored Procedure)是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象。
存储过程是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。
存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。
存储过程的优点
1. 运行速度:对于很简单的sql,存储过程没有什么优势。对于复杂的业务逻辑,因为在存储过程创建的时候,数据库已经对其进行了一次解析和优化。存储过程一旦执行,在内存中就会保留一份这个存储过程,这样下次再执行同样的存储过程时,可以从内存中直接调用,所以执行速度会比普通sql快。
2. 减少网络传输:存储过程直接就在数据库服务器上跑,所有的数据访问都在数据库服务器内部进行,不需要传输数据到其它服务器,所以会减少一定的网络传输。但是在存储过程中没有多次数据交互,那么实际上网络传输量和直接sql是一样的。而且我们的应用服务器通常与数据库是在同一内网,大数据的访问的瓶颈会是硬盘的速度,而不是网速。
3. 可维护性:的存储过程有些时候比程序更容易维护,这是因为可以实时更新DB端的存储过程。有些bug,直接改存储过程里的业务逻辑,就搞定了。
4. 增强安全性:提高代码安全,防止 SQL注入。这一点sql语句也可以做到。
5. 可扩展性:应用程序和数据库操作分开,独立进行,而不是相互在一起。方便以后的扩展和DBA维护优化。
存储过程的缺点
1. SQL本身是一种结构化查询语言,但不是面向对象的的,本质上还是过程化的语言,面对复杂的业务逻辑,过程化的处理会很吃力。同时SQL擅长的是数据查询而非业务逻辑的处理,如果如果把业务逻辑全放在存储过程里面,违背了这一原则。
2. 如果需要对输入存储过程的参数进行更改,或者要更改由其返回的数据,则您仍需要更新程序集中的代码以添加参数、更新调用,等等,这时候估计会比较繁琐了。
3. 开发调试复杂,由于IDE的问题,存储过程的开发调试要比一般程序困难。
4. 没办法应用缓存。虽然有全局临时表之类的方法可以做缓存,但同样加重了数据库的负担。如果缓存并发严重,经常要加锁,那效率实在堪忧。
5. 不支持群集,数据库服务器无法水平扩展,或者数据库的切割(水平或垂直切割)。数据库切割之后,存储过程并不清楚数据存储在哪个数据库中。
使用建议
1. 适当的使用存储过程,能够提高我们SQL查询的性能,
2. 存储过程不应该大规模使用,滥用。
3. 随着众多ORM 的出现,存储过程很多优势已经不明显。
4. SQL最大的缺点还是SQL语言本身的局限性——SQL本身是一种结构化查询语言,我们不应该用存储过程处理复杂的业务逻辑——让SQL回归它“结构化查询语言”的功用。复杂的业务逻辑,还是交给代码去处理吧。