批量处理
- JDBC语句提高处理速度
- 当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率
- JDBC的批量处理语句包括下面两个方法(Statement):
- addBatch(String):添加需要批量处理的SQL语句或是参数;
- executeBatch():执行批量处理语句;
- clearBatch():清空缓存的数据
- 通常我们会遇到两种批量执行SQL语句的情况:
- 多条SQL语句的批量处理;
- 一个SQL语句的批量传参;
数据库事务
- 事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。
- 事务处理(事务操作):保证事务要么全部执行,要么全不执行
- 事务的**ACID(acid)**属性
- 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
- 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
- 隔离性(Isolation)事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
- JDBC 事务建立
- 当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚
- 为了让多个 SQL 语句作为一个事务执行:
- 调用 Connection 对象的 setAutoCommit(false); 以取消自动提交事务
- 在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
- 在出现异常时,调用 rollback(); 方法回滚事务
- 若此时 Connection 没有被关闭, 则需要恢复其自动提交状态
- 提交后的数据状态
- 数据的改变已经被保存到数据库中。
- 改变前的数据已经丢失。
- 所有用户可以看到结果。
- 锁被释放, 其他用户可以操作涉及到的数据。
连接池
- 在使用开发基于数据库的web程序时,传统的模式基本是按以下步骤:
- 在主程序(如servlet、beans)中建立数据库连接
- 进行sql操作
- 断开数据库连接
- 传统模式存在的问题:
- 普通的JDBC数据库连接使用 DriverManager 来获取,每次都要建立连接,关闭连接,建立连接没限制
- 效率不高,容易资源泄露,服务器容易崩
- 基本思想
- 数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
- 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
- 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
- 数据库连接池技术的优点
- 资源重用
- 更快的系统反应速度
- 新的资源分配手段
- 统一的连接管理,避免数据库连接泄露
- 连接
- 把配置文件传入连接池,即可
- close和以前一样使用,不过底层只是把此还给了连接池,并非真正关闭
- javax.sql.DataSource数据库连接池
- JDBC 的数据库连接池使用 javax.sql.DataSource 来表示,DataSource 只是一个接口,该接口通常由服务器(Weblogic, WebSphere, Tomcat)提供实现,也有一些开源组织提供实现:
- DBCP 数据库连接池
- C3P0 数据库连接池
- Druid 阿里巴巴公司提供开源数据库连接池
- DataSource 通常被称为数据源,它包含连接池和连接池管理两个部分,习惯上也经常把 DataSource 称为连接池
- DataSource用来取代DriverManager来获取Connection,获取速度快,同时可以大幅度提高数据库访问速度。
jdbcutils工具类
- 封装了从连接只获取释放连接的操作,是来连接池的直接使用者
//jdbcutils工具类,主要用来获取连接,释放连接
public class JDBCUtils {
//连接池,只需要一个即可,在静态语句块中初始化。
private static DataSource dataSource;
static {
try {
//1、读取druip.properties文件
Properties pro = new Properties();
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//2、连接连接池
dataSource = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() {
Connection connection = null;
try {
connection = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
//释放连接
public static void releaseConnection(Connection connection) {
if(connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
DBUtils工具类
- 区别jdbcUtils!!!
- 用来和数据库交互,查询数据,执行sql语句,将查询结果包装成javabean,将增删改结果返回,是数据库的直接操作类
- QueryRunner类,提供数据库操作的一系列重载的update()和query()操作:
- T query(String sql, ResultSetHandler rsh)
- Executes the given SELECT SQL without any replacement parameters.
- 使用给定的sql和转换器对象执行sql查询操作
- int update(Connection conn, String sql)
- Execute an SQL INSERT, UPDATE, or DELETE query without replacement parameters.
- 使用给定的连接和sql执行增删改操作
- ResultSetHandler,此接口用于处理数据库查询操作得到的结果集。不同的结果集的情形,由其不同的子类来实现
- BeanHandler:把结果集转为一个 Bean
- BeanListHandler:把结果集转为一个 Bean 的集合
- MapHandler:把结果集转为一个 Map
- MapListHandler:把结果集转为一个 Map 的 List
- ScalarHandler:把结果集转为一个类型的数据返回, 该类型通常指 String 或其它 8 种基本数据类型.
Dao封装
- 把数据库中的记录转成javabean或提供使用javabean和数据库查询的方式,是DBUtils的直接使用者
- 一般dao层结构
- baseDao使用泛型封装基本操作并设置为abstrast避免用户直接使用
- 接口dao,声明具体的javabean对应的操作方法
- 实现dao,实现接口dao所声明的方法,并继承baseDao,来使用baseDao中所提供的方法
- BaseDao中一般方法
- public BaseDao(),构造方法,把子代继承的类传给
//dao基础封装,设置成abstract避免直接使用
public abstract class BaseDao<T> {
//DBUtils工具类核心类,使用它来执行查询操作
private QueryRunner queryRunner = new QueryRunner();
//定义一个变量来接收泛型的类型
private Class<T> type;
// 获取T的Class对象,获取泛型的类型,泛型是在被子类继承时才确定
public BaseDao() {
//获取子类的类型
Class clazz = this.getClass();
//获取父类的类型
//getGenericSuperclass()用来获取当前类的父类的类型
//ParameterizedType表示的是带泛型的类型
ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
//获取具体的泛型类型 getActualTypeArguments获取具体的泛型的类型
//这个方法会返回一个Type的数组
Type[] types = parameterizedType.getActualTypeArguments();
//获取具体的泛型的类型·
this.type = (Class<T>) types[0];
}
/**
* 通用的增删改操作
*
* @param sql
* @param params
* @return
*/
public int update(String sql, Object... params) {
// 获取连接,基于jdbcutils工具类
Connection connection = JDBCUtils.getConnection();
int count = 0;
try {
count = queryRunner.update(connection, sql, params);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.releaseConnection(connection);
}
return count;
}
/**
* 获取一个对象
*
* @param sql
* @param params
* @return
*/
public T getBean(String sql, Object... params) {
// 获取连接
Connection connection = JDBCUtils.getConnection();
T t = null;
try {
t = queryRunner.query(connection, sql, new BeanHandler<T>(type),
params);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.releaseConnection(connection);
}
return t;
}
/**
* 获取所有对象
* @param sql
* @param params
* @return
*/
public List<T> getBeanList(String sql, Object... params) {
// 获取连接
Connection connection = JDBCUtils.getConnection();
List<T> list = null;
try {
list = queryRunner.query(connection, sql, new BeanListHandler<T>(
type), params);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.releaseConnection(connection);
}
return list;
}
}