数据库连接池
什么是数据库连接池
数据库连接池是储存数据库连接资源的容器,当用户需要数据库连接资源时直接可从容器中获取资源,数据库连接资源使用完成后程序将该资源直接返还到数据库连接池即可,其大致原理如下所示。
为什么需要数据库连接池
当我们用传统的数据库操作方式来操作数据库,系统需要重复的执行数据库连接资源申请和释放代码,这样就会导致操作数据库的效率降低,为了提高数据库操作效率,避免重复性的申请和释放数据库连接资源,提高用户访问效率,节约系统资源。
如何使用操作数据库连接池
实现
- 标准接口:DataSource javax.sql包下
方法
获取连接:getConnection()
释放连接:Connection.close()
notes:如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了,而是归还连接。
常见的数据库连接池
c3p0
c3p0 数据库使用有两种方式,一种是采用硬编码方式,这种方式我们通常用的较少,一般都是采用配置文件的方式来实现数据库连接池。
硬编码方式
根据c3p0的数据手册,告诉我们基本的使用方式。
案例(硬编码方式)
使用c3p0采用硬编码方式
public class C3P001Demo {
public static void main(String[] args) throws PropertyVetoException, SQLException {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql:///test2");
ds.setUser("root");
ds.setPassword("root");
Connection connection = ds.getConnection();
String sql = "select * from account where username = ?;";
PreparedStatement ppst = connection.prepareStatement(sql);
ppst.setString(1,"zhangsan");
ResultSet resultSet = ppst.executeQuery();
System.out.println("----------------------------");
if(resultSet.next()){
System.out.println(resultSet.getInt("id")+"------>"
+resultSet.getString("username")+"--------->"+
resultSet.getDouble("balance")+"---------->"+
resultSet.getString("password")
);
}
System.out.println("----------------------------");
resultSet.close();
ppst.close();
connection.close();
}
}
硬编码运行结果:
还有其他的一些硬编码方式,在此处就不做过多解释。
采用配置文件
采用xml配置文件。
c3p0 数据手册中所推荐的数据配置文件形式。
xml文件
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test2</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<!--初始化申请的连接数量-->
<property name="initialPoolSize">5</property>
<!--最大的连接数量-->
<property name="maxPoolSize">10</property>
<!--超时时间-->
<property name="checkoutTimeout">30</property>
</default-config>
<named-config name="otherc3p0">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test2</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
c3p0支持同一套文件实现多个多个数据库连接池,实现多个连接池的方法是在创建数据源时直接赋值即可,如:
ComboPooledDataSource ds = new ComboPooledDataSource("otherc3p0");
这样就通过otherc3p0来配置实现数据库连接池。
案例
通过xml文件配置数据库。
public class C3P002Demo {
public static void main(String[] args) throws SQLException {
ComboPooledDataSource cpds = new ComboPooledDataSource("otherc3p0");
Connection connection = cpds.getConnection();
System.out.println(connection);
String sql = "select * from account where username = ?;";
PreparedStatement ppst = connection.prepareStatement(sql);
ppst.setString(1,"zhangsan");
ResultSet resultSet = ppst.executeQuery();
System.out.println("----------------------------");
if(resultSet.next()){
System.out.println(resultSet.getInt("id")+"------>"
+resultSet.getString("username")+"--------->"+
resultSet.getDouble("balance")+"---------->"+
resultSet.getString("password")
);
}
System.out.println("----------------------------");
resultSet.close();
ppst.close();
connection.close();
}
}
运行结果
c3p0采用properties配置文件的方式与xml文件类似,以下是数据手册中实现对c3p0的操作说明。
To override the library’s built-in defaults, create a file called c3p0.properties and place it at the “root” of your classpath or classloader. For a typical standalone application, that means place the file in a directory named in your CLASSPATH environment variable. For a typical web-application, the file should be placed in WEB-INF/classes. In general, the file must be available as a classloader resource under the name /c3p0.properties, in the classloader that loaded c3p0’s jar file. Review the API docs (especilly getResource… methods) of java.lang.Class, java.lang.ClassLoader, and java.util.ResourceBundle if this is unfamiliar.The format of c3p0.properties should be a normal Java Properties file format, whose keys are c3p0 configurable properties. See Appendix A. for the specifics. An example c3p0.properties file is produced below:
通过官网文档指定的方法即可实现用properties文件来实现c3p0数据库连接池,此处就不做过多赘述。
druid
druid 是阿里巴巴公司开发的一款开源数据库,目前该数据库已经成功的应用于600多款APP,经过长期的实践证明,该数据库连接池性能稳定,效率高,是众多款java数据库连接池中性能最为优秀的数据库之一。下面将结合实例来完成druid数据库连接池相关操作。
案例
资源文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test2
username=root
password=root
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
工具类
public class JDBCUtils {
private static DataSource dataSource;
static {
try {
InputStream res = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
Properties properties = new Properties();
properties.load(res);
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException{
return dataSource.getConnection();
}
public static void close(Statement statement, ResultSet resultSet,Connection connection){
if (statement!=null){
try {
statement.close();
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
}
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
}
if(connection !=null){
try {
connection.close();
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
}
}
public static void close(Statement statement, Connection connection){
if(connection !=null){
try {
connection.close();
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
}
if(connection !=null){
try {
connection.close();
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
}
}
public static DataSource getDataSource(){
return dataSource;
}
}
测试类
public class Druid01Demo {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement =null;
ResultSet resultSet = null;
try {
connection = JDBCUtils.getConnection();
System.out.println(connection);
String sql = "select * from account where username = ? ";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"lisi");
resultSet = preparedStatement.executeQuery();
if(resultSet.next()){
System.out.println(resultSet.getInt("id")+"------>"
+resultSet.getString("username")+"--------->"+
resultSet.getDouble("balance")+"---------->"+
resultSet.getString("password"));
}
connection = JDBCUtils.getConnection();
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}finally {
JDBCUtils.close(preparedStatement,resultSet,connection);
}
}
}
测试结果:
上述案例将申请数据库连接池的代码和释放资源的代码都抽象到工具类中,这样就避免了重复书写代码,简化了代码开发。
springJDBC
springJDBC是spring框架对JDBC的简单封装,spring 框架提供了一个JDBCTemplate来简化jdbc开发。
常见jdbcTemplate操作数据库方法
DML语句实现方法
- update():。增、删、改语句
DQL语句实现方法
- 1、queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
2、queryForList():查询结果将结果集封装为list集合
3、queryForObject:查询结果,将结果封装为对象, 一般用于聚合函数的查询。
4、query():查询结果,将结果封装为JavaBean对象
query的参数:RowMapper
一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
new BeanPropertyRowMapper<类型>(类型.class)
notes:
- 1、queryForMap查询的结果集长度只能是1
2、queryForList()将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
案例
采用jdbcTemplate联系数据库的增删改查
public class JDBCTemplate01Demo {
JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
private String querySql = "select * from account";
@Test
public void test(){
queryListResultPrint(jdbcTemplate.queryForList(querySql));
}
@Test
public void test1(){
String sql = "update account set balance =1000";
queryListResultPrint(jdbcTemplate.queryForList(querySql));
System.out.println("---------DML语句执行前------------");
jdbcTemplate.update(sql);
System.out.println("---------DML语句执行后------------");
queryListResultPrint(jdbcTemplate.queryForList(querySql));
}
@Test
public void test2(){
String sql = "update account set balance = 500 where username = ?";
queryListResultPrint(jdbcTemplate.queryForList(querySql));
System.out.println("---------DML语句执行前------------");
jdbcTemplate.update(sql,"zhangsan");
System.out.println("---------DML语句执行后------------");
queryListResultPrint(jdbcTemplate.queryForList(querySql));
}
@Test
public void test3(){
String sql = "insert into account values(?,?,?,?)";
queryListResultPrint(jdbcTemplate.queryForList(querySql));
System.out.println("---------DML语句执行前------------");
jdbcTemplate.update(sql,3,"wangwu",2000,"wangwu");
System.out.println("---------DML语句执行后------------");
queryListResultPrint(jdbcTemplate.queryForList(querySql));
}
@Test
public void test4(){
String sql = "DELETE from account where username = ? ";
queryListResultPrint(jdbcTemplate.queryForList(querySql));
System.out.println("---------DML语句执行前------------");
jdbcTemplate.update(sql,"wangwu");
System.out.println("---------DML语句执行后------------");
queryListResultPrint(jdbcTemplate.queryForList(querySql));
}
@Test
public void test5(){
String querySql = "select * from account where username = ?";
Map<String, Object> zhangsan = jdbcTemplate.queryForMap(querySql, "zhangsan");
System.out.println(zhangsan);
}
@Test
public void test6(){
List<Emp> query = jdbcTemplate.query(querySql, new RowMapper<Emp>() {
@Override
public Emp mapRow(ResultSet resultSet, int i) throws SQLException {
Emp emp = new Emp();
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String password = resultSet.getString("password");
double balance = resultSet.getDouble("balance");
emp.setBalance(balance);
emp.setId(id);
emp.setUsername(username);
emp.setPassword(password);
return emp;
}
});
for (Emp emp : query) {
System.out.println(emp.getId()+"---->"+emp.getUsername()+"--->"+emp.getPassword()+"--->"
+emp.getBalance());
}
}
@Test
public void test7(){
List<Emp> query = jdbcTemplate.query(querySql, new BeanPropertyRowMapper<Emp>(Emp.class));
for (Emp emp : query) {
System.out.println(emp.getId()+"---->"+emp.getUsername()+"--->"+emp.getPassword()+"--->"
+emp.getBalance());
}
}
@Test
public void test8(){
String sql = "select count(id) from account;";
Long aLong = jdbcTemplate.queryForObject(sql, Long.class);
System.out.println(aLong);
}
public void queryListResultPrint(List<Map<String, Object>> maps){
for (Map<?, ?> map :
maps) {
Set<Object> strings = (Set<Object>) map.keySet();
for (Object val :
strings) {
System.out.println(val+"---------->"+map.get(val));
}
/*Set<String> strings = maps.keySet();
System.out.println(i+"---------->"+maps.get(i));*/
}
}
}
需要导入jar包如下图所示:
执行的结果太多,在此处就不做过多演示,有兴趣的童鞋可以自己测试一下。