1、JDBC
概念:
JDBC(Java Database Connectivity) , Java连接数据库的规范(标准)。
使用JDBC连接数据库完成CRUD操作。
核心思想:
Java中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式。
由数据库厂商提供驱动实现类(Driver数据库驱动)。
MySQL数据库驱动
mysql-connection-java-5.1.X 适用于5.X版本
mysql-connection-java-8.0.X 适用于8.X版本
2、JDBC开发步骤
开发步骤:
3、ResultSet
概念:
在执行查询SQL后,存放查询到的结果集数据。
接受结果集:
注意:
作用就是完成了查询结果的存储功能,而且只能读取一次,不能够来回的滚动读取
遍历ResultSet:
ResultSet以表结构进行临时结果的存储,通过JDBC API将其中数据进行依次获取
经验:
getXxx方法可以获取的类型有:基本数据类型、引用数据类型
4、常见错误
5、SQL注入
原因:
用户输入的数据中有SQL关键字或语法并且参与了SQL语句的编译,导致SQL语句编译后的条件含义为true,一直得到正确的结果。这种现象称为SQL注入。
如何避免:
由于编写的SQL语句是在用户输入数据,整合后再进行编译
我们要使SQL语句在用户输入数据前就已编译成完整的SQL语句,再进行填充数据。
6、PreparedStatement
概念:
PreparedStatement继承了Statement接口,执行SQL语句的方法无异
作用:
预编译SQL语句,效率高
安全,避免SQL注入
可以动态的填充数据,执行多个同构的SQL语句
应用:
预编译SQL语句,参数使用?占位
为参数下标赋值:
注意:
在JDBC中的所有参数都由?符号占位,这被称为参数标记
在执行SQL语句之前,必须为每个参数提供值
6、封装工具类
背景:
在JDBC的使用中,连接数据库、关闭连接等存在着大量的重复代码
把传统的JDBC代码进行重构,抽取出通用的JDBC工具类
重用性方案:
封装获取连接方法
封装释放资源方法
背景:
重用性方案中的参数都是硬编码,当驱动、URL等参数需要更换时,需要重新编译
通过配置文件读取配置信息,使用软编码方式,更灵活的方案
跨平台方案:
创建properties配置文件
创建Properties集合:
public static final Properties prop = new Properties();
静态代码块中,使用输入流,读取配置文件
7、ORM
概念:
Object Relational Mapping:对象映射关系
对结果集(ResultSet)遍历时,取出的都是零散的数据
在实际应用开发中,我们需要将零散的数据进行封装整理
实体类(Entity):
一行数据中,多个零散的数据进行整理
通过entity的规则对表中的数据进行对象的封装
表名=类名 列名=属性名 提供各个属性的set get方法
提供无参构造方法(视情况添加有参构造)
8、DAO
概念;
Data Access Object : 数据访问对象。
DAO实现了业务逻辑与数据库访问相分离
对同一张表的所有操作封装在XxxDaoimpl对象中。
根据增删改查提供具体的方法(insert、update、delete、select、selectAll)
9、Service
什么是业务?
代表用户完成的一个业务功能,可以由一个或多个DAO的调用组成
软件所提供的一个功能叫业务
10、事务
概念:
事务是一个原子操作。是一个最小执行单元。由一个或多个SQL语句组成
在同一个事务当中,所有的SQL语句都成功执行时,整个事务成功
在一个SQL语句执行失败,整个事务都执行失败
事物的边界:
在JDBC中,先获得Connection对象。
开始事务:conn.setAutoCommit(false);
手动提交事务:conn.commit();
手动回滚事务:conn.rollback();
在Service中,调用了多次DAO操作。每一个业务功能都要控制事务。
问题:
当程序发生异常时,事务回滚并没有成功。
原因:
Service控制事务和DAO访问数据库时的连接对象,并非同一个。
在一个业务流程中,要保证多个数据库访问操作的连接对象是同一个
连接对象的同步方案1:
将Connection对象通过Service获取并传递给各个DAO方法。
传递的问题:
如果使用传递Connection,容易造成接口污染(BadSmell)
定义接口是为了更容易更换实现,而将Connection定义在接口中,会污染当前接口
连接对象同步方案2:
可以将整个线程中(单线程)中,存储一个共享值
线程拥有一个类似Map的属性,键值对结构<ThreadLocal对象,值>。
11、ThreadLocal
12、事物的封装
现有问题:
事务的开启、提交、回滚的代码都现在了Service中。
Service的主要职责是模拟现实业务功能。要将事务的控制封装在工具类中
工具类封装事务控制方法:
开启事务:
begin();
提交事务:
commit();
回滚事务;
rollback();
13、三层架构
现有问题:在之前学习过程中,通过DAO与Service对象实现数据访问与业务逻辑的分离
面向实现类编程: 层与层之间的耦合度高、不易修改、扩展、更换实现。
程序设计时,要考虑易修改、易扩展
为Service层和DAO层设计接口,便于未来更换实现类
14、DaoUtils
现有问题:
在DAO层中,对数据库表的增、删、改、查操作存在代码冗余
可对其进行抽取封装DaoUtils工具类实现复用。
增删改方法:
相同:获取连接,预编译SQL、占位符赋值、执行并返回结果。
不同:sql语句不同、参数列表不同
将DAO中增删改的数据库访问操作进行封装
查询方法:
相同:获取连接、预编译SQL、占位符赋值、执行并返回结果
不同:sql语句不同、参数列表不同、返回的结果不同(单个对象或集合、对象类型)
封装问题:
方法返回值类型
方法的参数列表
如何封装对象
方法中如何返回单个对象或多个对象
工具类无法同时完成执行查询、封装对象、返回结果的操作。
15、数据库连接池
现有问题:
数据库连接是一种关键的、有限的、昂贵的资源
频繁的创建、关闭会影响程序的性能
连接池:
数据库连接池负责分配、管理和释放数据库连接
在程序初始化时,预先创建指定数量的数据库连接对象存储在池中
避免频繁的创建、关闭
16、DbUtils
概念:
Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库
使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能
作用:
小巧、简单、实用。
对于数据表的查询操作,可以把结果转换为List 、Array 、 Set等集合
对于数据表的DML操作,只需要写SQL语句
17、 综合
UTIL
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.commons.dbutils.DbUtils;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class DBUtil {
//声明局部线程类:保存自己的连接
//类map集合 key是线程id value 是connection对象
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
//声明连接池对象:提升获取连接的效率
private static DruidDataSource dataSource;
static {
InputStream inputStream = DbUtils.class.getResourceAsStream("/db.properties");
Properties properties = new Properties();
try {
properties.load(inputStream);
//创建连接池对象
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
//到连接池中获取连接
//第一步:先到局部线程类中获取自己原有的连接
//第二步:判断是否获取到,如果获取到,则使用获取到的,如果没有获取到自己原来的连接,那么到连接池获取
Connection connection = threadLocal.get();
if (connection == null) {
//没有获取到自己线程使用的connection对象
try {
//从连接池获取
connection = dataSource.getConnection();
//存入局部线程
threadLocal.set(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
return connection;
}
//返回连接池对象
public static DataSource getDataSource() {
return dataSource;
}
}