前言
- 回顾曾经约定俗成的开发规则,DAO模式 —— Oracle 官网介绍的开发标准(浏览即可)
- 什么是JDBC
- JDBC的缺陷
- ORM的诞生
- Spring集成ORM做的努力
1. JDBC
1.1 什么是JDBC
以下内容整理至百度
JDBC (Java Database Connectivity)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口。
JDBC API主要位于JDK中的java.sql
包中(之后扩展的内容位于javax.sql
包中)
具体的规范有:
Driver
会将自身加载到DriverManager中去。DriverManager
负责加载各种不同驱动程序(Driver)并根据不同的请求,向调用者返回相应的数据库连接(Connection)Connection
数据库的一个连接环境,在这个环境下可以实现数据库的交互Statement
用以执行SQL查询和更新(针对静态SQL语句和单次执行)PreparedStatement
用以执行包含动态参数的SQL查询和更新(在服务器端编译,允许重复执行以提高效率)SQLException
代表在数据库连接的建立和关闭和SQL语句的执行过程中发生了例外情况(即错误)
注意,现在主流使用的是JDBC2.0标准,也就是javax.sql.DataSource
取代了用DriverManager
获取数据库连接
1.2 数据库驱动
- Maven管理的MySQL驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
- 区分硬件的驱动
独立显卡为什么要装驱动? 因为显卡厂商要告诉操作系统:“我很强,请识别出我的优势,CPU可以把渲染的工作交给我,需要我的时候请使用这些API”。操作系统就能很好得识别并控制独立显卡这个大家伙。硬件的驱动是比操作系统再高一层的软件,夹在应用程序和操作系统之间。 - 数据库驱动是什么
在Java的生态里,习惯把mysql-connector-java
称为驱动,或是因为它的核心类符合JDBC
的Driver
规范,Driver
翻译过来就是驱动。但是区别于硬件的驱动,这里的数据库驱动实质上就是应用软件。使用navicat
或者其他工具操作MySQL
,重要的是什么?—— 连接。输入了用户名密码后,navicat
帮你连接了数据库。如果是在Java程序中,properties或者yml文件提供了url 密码等信息,mysql-connector-java
做了什么?—— 连接。所以,可以认为数据库驱动是数据库的连接管理器。 - mysql-connector-java 和 JDBC 的关系
mysql-connector-java
是MySQL厂商遵循JDBC
标准的数据库连接管理器,供程序员在程序中使用
所以,当驱动注册好了后,程序员只用面向JDBC
的接口编程即可。
1.3 Spring 集成数据库连接池
Spring
的数据访问框架在数据库资源的管理上全部采用JDBC2.0
标准的javax.sql.DataSource
用于数据库连接。由于数据库连接的新增和销毁是很占用资源且耗时的,所以把连接进行池化是很必要,具体思路如下:
- 遵循JDBC的
DataSource
接口创建实现类A
,用该实现类获取connection
connection.close()
后,数据库连接不是释放而是返回到连接池中- 以后都使用
A
获取数据库连接
以上思路的第三点,交给Spring IOC
容器提供该服务是最好不过了,所以让应用集成连接池,最简单的是可以用Spring
配置一个bean,在使用的时候注入即可。(这个bean的id = ‘dataSource’ 用于覆盖Spring的默认实现)
<!-- 1.加载jdbc.properties文件的位置 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 2.配置druid连接池 ,id是固定值,class是druid连接池类的全路径 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 配置连接数据库的基本信息 -->
<property name="driverClassName" value="${db.driverClassName}"></property>
<property name="url" value="${db.url}"></property>
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
</bean>
Spring Boot 默认配置的是 HikariCP 连接池
1.4 使用JDBC与数据库交互
有了JDBC和数据库驱动,就能用java程序实现和数据库交互了。网上摘了一段代码下来:插入数据
private void insert(Person p) {
Connection conn = null;
Statement stmt = null;
// 连接数据库url
String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
// 数据库用户名
String user = "root";
// 数据库密码
String password = "root";
try {
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.创建数据连接对象
conn = DriverManager.getConnection(url, user, password);
// 3.创建Statement对象
stmt = conn.createStatement();
// 对sql拼接
String sql = "insert into t_person(name,age)values('" + p.getName()
+ "','" + p.getAge() + "')";
// 执行增加操作
stmt.executeUpdate(sql);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {// 关闭数据库
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
2. ORM的诞生
JDBC
的出现提供了访问数据库的便利,但是在面向对象的编程习惯里面,还是跟面向对象的表达存在着隔阂。ORM
的出现就是尽可能的消除这些隔阂,值得一提的是,ORM
是一个思想,并不是Java
所特有的。看以下代码体会以下ORM
怎么把sql
语句封装成对象的操作。
public Double calcAmount(String customerid, double amount)
{
Customer customer = CustomerManager.getCustomer(custmerid);
// 根据客户等级获得打折规则
Promotion promotion = PromotionManager.getPromotion(customer.getLevel());
// 累积客户总消费额,并保存累计结果
customer.setSumAmount(customer.getSumAmount().add(amount);
CustomerManager.save(customer);
return amount.multiply(protomtion.getRatio());
}
3. Spring集成ORM框架
3.1 JdbcTemplate
要说Spring
集成ORM框架,首先得提到Spring封装jdbc形成的JdbcTemplate
(记住这种命名方式,Spring在后期提供的RabbitMqTemplate
、RedisTemplate
、RestTemplate
也有这个意味)。
- Spring 封装模板代码
注意到原生的JDBC实现:
catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {// 关闭数据库
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
既然每次写访问数据库的代码都要带上这大段,那么何不使用模板方法设计模式进行封装。
- Spring 细化 SQLException 的语义
JDBC
标准中SQLException
存在比较宽泛的语义,不同数据库厂商会在方法中抛出的SQLException或是代表不同的意思,程序排错的时候看得就一脸懵逼,什么错都是SQLException
。并且SQLException
是一个checked Exception
,Java对checked Exception
的约束是:当前抛出异常,上层选择要捕获或者继续抛出。Spring
作为一个劳模,看源码,把模糊的SQLException
转化成各种见名知意的unchecked Exception
也就是所谓的RuntimeException
的子类,抛出后上层可以不捕获。Eg:
InvalidDataAccessApiUsageException
无效数据访问API使用异常DataRetrievalFailureException
数据获取异常DeadlockLoserDataAccessException
死锁DataIntegrityViolationException
一致性检验异常
- 综合上诉两个特点,
JdbcTemplate
支持以下写法(忽略依赖注入的代码)
String sql="insert into user (name,deptid) values (?,?)";
List<Object[]> batchArgs=new ArrayList<Object[]>();
batchArgs.add(new Object[]{"caoyc",6});
batchArgs.add(new Object[]{"zhh",8});
batchArgs.add(new Object[]{"cjx",8});
jdbcTemplate.batchUpdate(sql, batchArgs);
3.2 Hibernate 和 MyBatis
Spring 集成Hibernate
和 MyBatis
都同JdbcTemplate的思想大同小异
- 统一资源的管理方式
- Spring 异常管理的转译
- 事务管理及控制(这块内容比较大,后期还会更新)