为什么要使用连接池:我们使用Java开发时,就需要访问数据库,而Java不能直接访问数据库,中间得通过JDBC来建立程序和数据库的连接,执行一个事务就需要创建一个连接,而程序和数据库建立连接的过程是最耗时间的,当程序变得庞大,如果频繁的让程序和数据库建立连接,则耗时非常大,所以,程序员们就有了连接池的概念
连接池:存放着与数据库连接的通道,也就是JDBC中的Connection,事先定义好n 个连接,在程序启动的时候就初始化这些连接,后期直接从连接池中拿就行了,最后放回到连接池中,中间就省略了大量的重复连接和释放的操作。
Druid:德鲁D连接池是由Alibaba团队开发,其中引入了“缓加载“概念。
缓加载:在创建连接池对象的时候,不会对事先定义好的连接通道个数与数据库建立连接,而是在中连接池中拿第一个连接通道的时候,连接池就检查内部是否有用的连接通道,如果有就给出,如果没有就执行事先定义好的n个连接通道与数据库建立连接。
Druid.1.2.8.jar
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.8version>
dependency>
两种方式任选其一。
创建一个properties文件,主要用来给Druid连接池一个约束
driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/javaweb?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
username = root
password = 123456
initialSize = 5 //初始化连接通道个数
maxActive = 5 //最大的可用连接通道个数
maxWait = 3000 //当所有的连接通道都被占用后,需要等待的最大时间,单位为毫秒
将配置文件读入到内存中等待被拿取连接通道
public class DruidUtils {
private static DataSource dataSource = null;
private static Properties properties = null;
static{
properties = new Properties();
try {
//将配置文件加载进入内存,采用反射技术
properties.load(DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//通过工厂设计模式得到一个连接池对象,得到的是一个连接池对象,而不是连接对象哦
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException("连接池配置文件加载失败");
}
}
//将连接池对象开放给外部使用
public static DataSource getDataSource(){
return dataSource;
}
//从连接池对象中获取Connection
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
1、 需要先得到一个连接池对象,然后从连接池对象中得到连接
2、得到连接后的操作和JDBC操作数据库是一样的
private static DataSource dataSource = DruidUtils.getDataSource(); //得到连接池对象
public static void main(String[] args){
System.out.println(dataSource);
}
private static String addUser(User user){
String sql = "INSERT INTO user VALUES(?,?,?,?,?)";//SQL语句
int result = 0; //执行后的结果
try {
//从连接池对象中得到连接通道
Connection connection = dataSource.getConnection();
//下面的操作都和JDBC中的一样,执行SQL语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,user.getId());
preparedStatement.setString(2,user.getUserName());
preparedStatement.setString(3,user.getPassword());
preparedStatement.setString(4,user.getSex());
preparedStatement.setString(5,user.getPhone());
result = preparedStatement.executeUpdate();
//操作完成后一定要将连接再次放到连接池中,不然连接池就一直处于被占用的状态,不能给其他的事物使用。
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
return result > 0 ? "添加用户成功" : "添加用户失败";
}
private static List<User> getUserList() {
List<User> userList = new ArrayList<>();
ResultSet result = null;
String sql = "SELECT * FROM user";
try {
//从连接池中得到连接通道
Connection connection = dataSource.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(sql);
result = preparedStatement.executeQuery();
User user = null;
while (result.next()) {
user = new User(result.getString("id"),result.getString("username"),
result.getString("password"), result.getString("sex"), result.getString("phone"));
userList.add(user);
}
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
return userList;
}
public class DruidPoolTest {
private static DataSource dataSource = null;
public static void main(String[] args) {
dataSource = DruidUtils.getDataSource(); //得到连接池对象
System.out.println("-----------向数据库中添加一个用户-----------------");
User user = new User("6","王水煮","999999","女","13888887878");
System.out.println(addUser(user));
System.out.println("--------------查询所有-------------");
List<User> userList = getUserList();
for(User user : userList){
System.out.println(user.toString());
}
}
}
目前数据库内一共有五条用户信息
执行完Main方法中的操作后
一共有六条数据,数据添加成功。由于Druid连接池采用的“缓加载”技术,在程序执行到第一次得到连接通道的时候,由于连接池内没有连接,就需要初始化N条连接通道,所以会一开始比较慢。
我事先在properties文件中定义的连接通道条数是五条,最大活动条数也是五条。
而现在我要获取六条:
public static void main(String[] args) {
dataSource = DruidUtils.getDataSource(); //得到连接池对象
try {
Connection connection1 = dataSource.getConnection();//第一个连接
Connection connection2 = dataSource.getConnection();//第二个连接
Connection connection3 = dataSource.getConnection();//第三个连接
Connection connection4 = dataSource.getConnection();//第四个连接
Connection connection5 = dataSource.getConnection();//第五个连接
Connection connection6 = dataSource.getConnection();//第六个连接
} catch (SQLException e) {
e.printStackTrace();
}
}
原因一:连接池中没有可用的连接通道了,定义了五条通道,最大可用的也是五条通道,所有就没有可用的了。
原因二 :我执行完一个事务后没有将连接释放,导致其他事务无法得到连接通道。
解决办法
解决办法一:扩大连接池中最大可用的连接条数
initialSize = 5 //初始化五条连接通道
maxActive = 10 //最大可用的连接通道为 10条
解决办法二 : 事务执行完后,将连接还给连接池。
个人建议还是使用解决办法二,因为在大型的项目中,不建议去动不动就加大连接通道的条数
Druid连接池也是现在比较流行的一个连接池技术,但是它只能解决连接通道在连接和释放的性能优化。其他操作数据库的方式还是和JDBC一样,所以目前市场上也出现了MyBatis等框架技术。