- 持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用,持久化的实现过程大多通过各种关系型数据库来完成
- JPA(Java Persistence API):Java 的持久化 API,为对象关系映射提供了一种基于 POJO 的持久化模型
- JPA 的实现:Hibernate、Toplink、OpenJPA、Eclipselink 等
- Spirng Data JPA 是 Spring 提供的一套简化 JPA 开发的框架,可以理解为对 JPA 规范的再次封装抽象
- JDBC 即 Java 数据库连接(Java DataBase Connectivity),一组可以执行 SQL 语句的 Java API(Java 数据库的统一访问接口)
JDBC 完成 CRUD 操作
在 java.sql 包下
步骤
- 加载数据库驱动,使用 DriverManager 获取连接对象
- 使用 Connection 创建 PreparedStatement 语句对象
- 设置 SQL 语句中的参数值,执行 SQL 语句
- 操作结果集
- 回收数据库资源,包括关闭 ResultSet、Statement 和 Connection 等资源
Class.forName("com.mysql.jdbc.Driver"); // 从 Java6(JDBC 4.0)开始,无需加载数据库驱动
Connection conn = DriverManager.getConnection(String url, String user, String password); // 建立到指定数据库 URL 的连接
// url = "jdbc:mysql://localhost:3306/mydb"
// 如果连接的数据库服务器在本机上,并且端口是3306,则可以简写:url = "jdbc:mysql:///mydb"
使用 PreparedStatement 比使用 Statement 的好处:
- 无须“拼接”SQL 语句,编程更简单
- 预编译 SQL 语句,性能更好(MySQL 不支持 PreparedStatement 的性能优化)
- 可以防止 SQL 注入,安全性更好
- Configuration Properties for Connector/J 常见参数:user、password、useSSL、serverTimezone、autoReconnect、rewriteBatchedStatements
常用 API
Connection 接口
Connection 接口:代表数据库连接对象(一个物理连接会话)
创建语句对象
Statement createStatement()
:创建一个 Statement 对象PreparedStatement prepareStatement(String sql)
:创建一个 PreparedStatement 对象PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
:创建一个 PreparedStatement 对象,并设置该对象是否能获取自动生成的主键(int 常量:Statement.RETURN_GENERATED_KEYS)控制事务
void setAutoCommit(boolean autoCommit)
:false 为关闭自动提交,开启事务(MySQL 默认打开自动提交)void commit()
:提交事务,并释放所持有的数据库锁void rollback()
:回滚事务,并释放所持有的数据库锁(在 catch 块中回滚事务)
Statement 接口
Statement 接口:用于执行静态 SQL 语句(将 SQL 语句发送到数据库)
int 常量:RETURN_GENERATED_KEYS、NO_GENERATED_KEYS
执行语句
int executeUpdate(String sql)
:执行 DML 语句时返回受影响的行数;执行 DDL 语句时返回 0int executeUpdate(String sql, int autoGeneratedKeys)
:执行给定的 DML 语句,并设置此 Statement 生成的自动生成键是否能用于获取ResultSet executeQuery(String sql)
:执行 DQL 语句,并返回査询结果对应的 ResultSet 对象批量更新
void addBatch(String sql)
:将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中int[] executeBatch()
:执行一批命令void clearBatch()
:清空此 Statement 对象的当前 SQL 命令列表获取自动生成主键
ResultSet getGeneratedKeys()
:获取由于执行此 Statement 对象而创建的所有自动生成的主键
PreparedStatement 接口
PreparedStatement 接口,Statement 的子接口,用于执行带占位符(?)参数的 SQL 语句
给参数设值即添加到批处理
viod setXxx(int parameterIndex, Xxx value)
:根据索引(从 1 开始)将 SQL 语句中指定位置的参数设置为 value 值,如果不清楚预编译 SQL 语句中各参数的类型,可以使用 setObject() 方法来传入参数void setBlob(int parameterIndex, InputStream inputStream)
:将指定参数设置为输入流对象void addBatch()
:将一组参数添加到此 PreparedStatement 对象的批处理命令中(调用前需先为参数设置)执行语句
int executeUpdate()
:执行 DML 语句或 DDL 语句(无须接收 SQL 字符串)ResultSet executeQuery()
:执行 DQL 语句(无须接收 SQL 字符串)
ResultSet 接口:结果集对象
boolean next()
:将光标从当前行移动到下一行(光标的初始位置是第一行之前)Xxx getXxx(int columnIndex)
:获取当前行中的指定列索引(从 1 开始)的数据Xxx getXxx(String columnName)
:获取当前行中的指定列名的数据
- Xxx 表示 Java 中与当前列的数据类型对应的数据类型,也可以用 getObject() 获取任意类型的值,或 getString() 方法获取除 Blob 之外的任意类型列的值
接口 Blob
InputStream getBinaryStream()
:以流的形式获取此 Blob 实例指定的 BLOB 值
常用 JPA 注解
- javax.persistence
- 实体
- @Entity:标明该类是一个实体类
- @MappedSuperclass
- @Table(name):定义映射的表
- 主键
- @Id:标明主键
- @GeneratedValue(strategy, generator):主键生成策略,如
@GeneratedValue(strategy = GenerationType.IDENTITY)
,依赖于数据库递增的策略 - @SequenceGenerator (name, sequenceName)
- 映射
- @Column (name, nullable, length, insertable, updatable):定义属性和表的映射关系
- @Enumerated
- @JoinTable(name)、@JoinColumn(name)
- @Convert(converter):指定使用的转换器(自定义转换器实现 AttributeConverter
)
- 关系
- @OneToOne、@OneToMany、@ManyToOne、@ManyToMany
- @OrderBy
Hibernate 常用注解
- org.hibernate.annotations
- @CreationTimestamp、@UpdateTimestamp
- @Type(type、parameters)
DAO 设计
DAO(Data Access Object):一个数据访问接口,夹在业务逻辑与数据库资源中间
分包规范:domain:存放实体类 / 模型对象, Xxxdao:存放 DAO 接口,IXxxDAO,对实体类对象的 CRUD 的封装dao.impl:存放 DAO 实现类,XxxDAOImplutil:存放工具类,JdbcUtils,包括:在初始化时加载配置文件创建 DataSource 对象、获取连接对象、释放资源test:存放 DAO 测试类,XxxDAOTest
事务处理
- 隐式提交事务:正常退出或者运行 DDL、DCL 语句
隐式自动回滚:Connection 遇到一个未处理的 SQLException 异常,系统非正常退出(但如果程序捕获了该异常,则需要在异常处理块中显式地回滚事务)
操作事务的模板:
try {
connection对象.setAutoCommit(false); // 取消事务自动提交
DML 操作1
DML 操作2
...
Connection对象.commit(); // 提交事务
} catch(Exception e) {
// 处理异常
Connection对象.rollback(); // 回滚事务
} finally {
释放资源
}
批处理操作
MySQL 不支持批量处理,但在新的JDBC驱动中,可以通过在 URL 连接中设置参数来优化:rewriteBatchedStatements=true
步骤:
- 将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中,或者设置 SQL 语句中指定位置的参数值后添加到此 PreparedStatement 对象的当前命令列表中
- 执行批处理
- 清除缓存
大数据类型处理
将 Blob 类型数据插入数据库需要调用 PreparedStatement 对象将指定参数设置为输入流对象的方法
从 ResultSet 里取出 Blob 数据
- 调用 ResultSet 的 getBlob(int columnlndex) 方法,获取一个 Blob 对象
- 调用 Blob 对象的 getBinaryStream() 方法来获取该 Blob 数据的输入流,或调用 Blob 对象的 getBytes()方法直接取出该 Blob 对象封装的二进制数据
获取保存数据时自动生成的主键
调用 Statement 接口中的ResultSet getGeneratedKeys()
方法,获取由于执行此 Statement 对象而创建的所有自动生成的主键
使用连接池管理连接
- 当应用程序启动时,系统主动建立足够的数据库连接,并将这些连接组成一个连接池
每次应用程序请求数据库连接时,无须重新打开连接,而是从连接池中取出已有的连接使用,使用完后不再关闭数据库连接,而是直接将连接归还给连接池
Connection Pool
javax.sql.DataSource 接口,表示 JDBC 的数据库连接池
常用 DataSource 的实现:DBCP、C3P0、Druid、Hikari
// 使用连接池获取 Connection 对象
Connection conn = DataSource对象.getConnection();
// 释放数据库连接
conn.close();
获取 DataSource 对象
DBCP 连接池
- 需要的 jar 包:commons-dbcp.jar、commons-pool.jar
- Tomcat 内置的数据库连接池也是 DBCP
// 通过连接池工厂创建连接池对象
// 配置文件中的 key 名要对应 BasicDataSourceFactory 类中字符串常量
DataSource ds = BasicDataSourceFactory.createDataSource(Properties properties);
Druid 连接池
- 需要的 jar 包:druid.jar、commons-logging.jar
- Druid 的分页支持:PagerUtils
- 配置属性列表
- Druid Spring Boot Starter
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcdemo?useSSL=false&rewriteBatchedStatements=true&serverTimezone=Asia/Shanghai
username=root
password=admin
# 最大连接数
maxActive=10
// 通过连接池工厂创建连接池对象
// 配置文件中的 key 名要对应 DruidDataSourceFactory 类中字符串常量
DataSource ds = DruidDataSourceFactory.createDataSource(Properties properties);
重构的思想
把相同的结构提取出去,把不同内容的使用参数表示
JDBC 操作模板:JdbcTemplate
把处理结果集的具体行为交给每一个 DAO 的实现类
结果集处理器接口:IResultSetHandler
结果集处理器实现类:
- BeanHanlder:把结果集中的第一条记录封装成一个 JavaBean 对象
- BeanListHandler:把结果集中的每一条记录都封装成一个 JavaBean 对象,再把多个 JavaBean 对象存储到 List 集合中
- 此时要保证:表中的列名和 JavaBean 中的属性名相同,表中的列类型和 JavaBean 中属性的类型对应
通过内省机制获取属性名(列名)、属性值
使用注解或 XML 文件处理表名和类名、属性名和列名不同的情况(映射)