一、数据库连接池
1.1、连接池介绍
数据库连接池的概念:负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个连接来操作数据库.
1.2、常见的数据库连接池
- C3P0:比较古老的数据库连接池
官网地址: https://www.mchange.com/projects/c3p0/
C3P0提供了多种创建数据库连接的方式,根据官网任选其一即可
- Druid:alibaba的基于Java的高效的数据库连接池
官网地址: https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98
1.3、数据连接池使用
//创建连接池对象
ComboPooledDataSource pool = new ComboPooledDataSource();
//注册驱动
pool.setDriverClass("com.mysql.jdbc.Driver");
pool.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc");
pool.setUser("root");
pool.setPassword("root");
详细用法见JDBC Part04:综合练习
二、DBUtils工具类
2.1、 DBUtils介绍
DBUtils是apache的一个组件,算是一个轻量级的JDBC框架,官网地址
https://commons.apache.org/proper/commons-dbutils/
DbUtils是一个非常小的类库,不需要花很长的时间去看他的API类或者是接口,只需要知道QueryRunner和ReulthSthand两个/接口类即可
2.2 DBUtils使用
- 通过BeanHandler查询一个ResultSet返回一个JavaBean对象(查询单个对象)。
QueryRunner run = new QueryRunner(dataSource);
ResultSetHandler<Person> h = new BeanHandler<Person>(Person.class);
Person p = run.query("SELECT * FROM Person WHERE name=?", h, "John Doe");
- 通过BeanListHandler查询所有的ResultSet返回一组JavaBean列表
QueryRunner run = new QueryRunner(dataSource);
ResultSetHandler<List<Person>> h = new BeanListHandler<Person>(Person.class);
List<Person> persons = run.query("SELECT * FROM Person", h);
详细用法见JDBC Part04:综合练习
三、数据库多线程安全问题
3.1、问题说明
当前端多个用户发送多个请求的时候,每一个请求都会建立一个数据库连接,而一个用户请求可能执行多条SQL语句,多次操作数据库,在执行多条SQL语句时怎么保证一个用户请求在一个事务管理内,如果不能保证在一个事务管理中就会出现线程安全问题,造成前后数据的不一致。保证线程安全的主要任务就是保证一个用户请求中执行的多条SQL语句在一个数据库连接中即可.还有一种情况实在使用数据库连接池时候,由于数据库连接池的链接是可以共用的,在一个用户请求过来的时候由于有异常产生而需要事物回滚操作,但是在事务还没有来得及回滚的时候其他的请求使用了这个连接池里的连接,进行了提交,这个时候在回滚就会没有效果,造成的数据出错。
3.2、解决方法 ThreadLocal
public class JdbcUtil {
private static ThreadLocal<Connection> pool = new ThreadLocal<>();
/**
* 获取当前请求线程上的Connection
* @return
*/
public static Connection getConnection() {
Connection conn = pool.get();
if(conn==null) {
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("", "", "");
pool.set(conn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
return conn;
}
/**
* 关闭当前请求线程上的Connection
*/
public static void close(){
Connection conn = pool.get();
conn.close();//关闭连接
pool.remove();//移除连接
}
}