JDBC入门
#1. JDBC概述
- JDBC(Java Database Cnonnectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库
 

#2. 获取数据库连接
1. 方式一:
1  | Driver driver = new com.mysql.cj.jdbc.Driver();  | 
2. 方式二:
- 对方式一的迭代:在程序中不出现第三方的api,使程序具有更好的可移植性
 
1  | //1. 获取Driver实现类对象  | 
3. 方式三:
- 使用DriverMannager替换Driver
 
1  | Class clazz = Class.forName("com.mysql.jdbc.Driver");  | 
4. 方式四:
- 可以只加载驱动,不用显示的注册驱动了
 
1  | String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true";  | 
5. 方式五(final):
- 将数据库连接需要的4个基本信息声明在配置文件中,通过读取配置文件的方式,获取连接
 
1  | //1.读取配置文件中的4个基本信息  | 
优点:
1.实现了数据与代码的分离。实现了解耦
2.如果需要修改配置文件信息,可以避免程序重新打包
#3. 使用PreparedStatement实现CRUD操作
使用Statement的弊端:需要拼写sql语句,并且存在SQL注入的问题
如何避免出现sql注入:只要用PreparedStatement(从Statement扩展而来)代替Statement
除了解决Statement的拼串、sql问题之外,PreparedStatement还可以操作Blob的数据
还可以实现更高效的批量插入
1. 增
1  | Connection conn = null;  | 
2. 改
- 这里将固定的方法封装了
 
1  | Connection conn = null;  | 
3. 查
通用的针对Order表的查询操作
针对表的字段名与类的属性名不相同的情况:
1.必须声明sql时,使用类的属性名来命名字段的别名
使用ResultSetMetaData时,需要使用getColumnLabel()来替换getColumnName(),获取列的别名
1  | 
  | 
- 通用
 
1  | 
  | 
- 多行查询通用操作
 
1  | 
  | 
#4. 操作BLOB类型字段
1. 插入
1  | Connection conn = null;  | 
2. 查询
1  | Connection conn = null;  | 
- 如果在指定了相关的Blob类型以后,还报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数:max_allowed_packet=16M。
 
#5. 批量插入
- 使用PreparedStatement实现批量插入
 - 方式一:
 
1  | 
  | 
方式二:addBatch(), executeBatch(), clearBatch()
mysql服务器是默认关闭批处理的,需要通过一个参数让mysql开启批处理的支持
mysql8.0 以下?rewriteBatchedStatements=true 写在配置文件的url后面
mysql8.0 以上&&rewriteBatchedStatements=true
1  | Connection conn = null;  | 
- 方式三:设置不允许自动提交
 
1  | Connection conn = null;  | 
#6. 数据库事务
- 事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态
 - 事务处理:保证所有事务都作为一个工作单元来执行,要么所有的事务都被提交(commit),要么数据库放弃所作的所有的操作,整个事务回滚(rollback)到初始状态
 - 数据一旦提交,就不可回滚
 
1  | //考虑数据库事务后的转账操作  | 
事务的ACID属性
原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另一个一致性状态
隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务的内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何的影响
数据库的并发问题
- 脏读:对两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段。之后,若T2回滚,T1读取的内容就是临时且无效的
 - 不可重复读:对于两个事务T1T2,T1读取了一个字段,然后T2更新了该字段。之后,T1再次读取同一个字段,值就不同了
 - 幻读:对于两个事务T1T2,T1从一个表中读取了一个字段,然后T2在该表中插入了一些新的行。之后,如果T1再次读取同一个表,就会多出几行
 
四种隔离级别
- READ UNCOMMITTED(读未提交数据):允许事务读取未被其他事务提交的变更,脏读、不可重复读和幻读的问题都会出现
 - READ COMMITTED(读已提交数据):只允许事务读取已经被其他事务提交的变更。可以避免脏读。
 - REPEATABLE READ(可重复读):确保事务可以多次从一个字段中读取相同的值。在事务的持续期间,禁止其他事务对这个字段进行更新。幻读的问题仍然存在
 - SERIALIZABLE(串行化):确保事务可以从一个表中读取相同的行。在事务的持续期间,禁止其他事务对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能非常低下
 - 一般从第二和第三个级别中选择
 - Oracle支持第二种和第四种事务隔离级别:默认是第二种
 - MySQL支持四种事务隔离级别。默认是第三种
 
1  | //获取当前连接的隔离级别  | 
#7. DAO及相关实现类
- 查看idea中jdbc2工程下的DAO及DAO2包
 
#8. 数据库连接池
基本思想
- 为数据库连接建立一个缓冲池。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从缓冲池中取出一个,使用完毕之后再放回去。
 - 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个
 
多种开源的数据库连接池技术
- DBCP:tomcat服务器自带的。速度快,但不稳定
 - C3P0:速度较慢,但比较稳定
 - Druid:阿里提供的数据库连接池,兼顾了以上的优点
 
C3P0的两种实现方法
- 方式一:
 
1  | //获取c3p0数据库连接池  | 
- 方式二:
 
1  | <c3p0-config>  | 
1  | ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");  | 
DBCP数据库连接池的两种实现方法
- 方式一:
 
1  | //创建了DBCP的数据库连接池  | 
- 方式二:
 
1  | Properties pros = new Properties();  | 
DRUID数据库连接池的两种实现方法
- 方法一:略
 - 方法二:使用配置文件
 
1  | Properties pros = new Properties();  | 
#9. Apache-DBUtils实现CRUD操作
- commons-dbutils 是Apache组织提供的一个开源JDBC工具类库,封装了针对于数据库的增删改查操作
 
增删改
1  | Connection conn = null;  | 
查询
- BeanHander:是ResultSetHandler接口的实现类,用于封装表中的一条记录
 
1  | //返回一条记录  | 
- BeanListHandler:是ResultSetHandler接口的实现类,用于封装表中的多条记录构成的集合
 
1  | //返回多条记录  | 
MapHandler:是ResultSetHandler接口的实现类,对应表中的一条记录
将字段以及相应字段的值作为map中的key和value
ScalarHandler:用于查询特殊值




