Spring 数据库连接池(JDBC)详解
数据库连接池
对一个简单的数据库应用,由于对数据库的访问不是很频繁,这时可以简单地在需要访问数据库时,就新创建一个连接,就完后就关闭它,这样做也不会带来什么性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同而,频繁的建立、关闭连接,会极大地减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。
通过建立一个数据库连接池以及一套连接使用管理策略,可以达到连接复用的效果,使得一个数据库连接可以得到安全、高效的复用,避免了数据库连接频繁建立、关闭的开销。
数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法。如:外部使用者可通过getConnection方法获取连接,使用完毕后再通过releaseConnection方法将连接返回,注意此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。
数据库连接池技术带来的好处:
1、资源重用
由于数据库连接得到重用,避免了频繁创建、释放链接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进行/线程数量)
2、更快地系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接池置于池中备用。此时连接的初始化工作均已完成,对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间
3、统一的连接管理,避免数据库连接泄露
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。
目前数据库连接池产品是非常多的,主要有:
1、dbcp
dbcp,即DataBaseConnectionPoolApache出品,Spring开发组推荐使用的数据库连接池,开发较为活跃,是一个使用极为广泛的数据库连接池产品。不过从网上
2、c3p0
Hibernate开发组推荐使用的数据库连接池,它实现了数据源和JNDI的绑定
3、Proxool
Proxool的口碑较好,没什么负面评价(比如dbcp就是因为Hibernate认为它BUG太多Hibernate才不推荐使用的),也是Hibernate开发组推荐使用的数据库连接池,不过使用者不算多,开发不够活跃。这个连接池提供了连接池监控的功能,方便易用,便于发现连接池泄露的情况
基于Spring的JDBC基本框架搭建
先讲一下使用Spring实现JDBC,数据库连接池就用Spring开发组推荐的DBCP,DBCP需要三个jar包,先下载一下:
1、commons-dbcp-1.4.jar,官方网站上有,点我下载
2、commons.pool-1.6.jar,官方网站上有,点我下载
3、commons.collections4-4.0.jar,官方网站上有
下载了这三个jar包之后请导入自己的工程中(注意MySql的包别忘记导入了),虽然dbcp和pool都出了dbcp2和pool2的版本,Apache官网上都可以下载,但是这里提供的还是dbcp1和pool1的版本下载地址,一个原因是dbcp2和pool2都只可以在JDK1.7及JDK1.7以上的版本运行,而dbcp1和pool1则可以在JDK1.6的版本运行,考虑到MyEclipse10默认自带的JRE就是1.6版本的,所以这里下载、使用dbcp1和pool1。想要dbcp2和pool2的可以自己去Apache官网下载,不过要注意,dbcp2必须和pool2一组,dbcp1必须和pool1一组,不可以混着用。
JDBC,我之前写过一篇文章,数据库建立和实体类都是用的原文章里面的,这里只是把原生的JDBC搬到SpringJDBC下而已,看下最基础的写法,再添加功能,学生管理类为:
publicclassStudentManager { privateJdbcTemplatejdbcTemplate; privatestaticStudentManagerinstance=newStudentManager(); publicstaticStudentManagergetInstance() { returninstance; } publicJdbcTemplategetJdbcTemplate() { returnjdbcTemplate; } publicvoidsetJdbcTemplate(JdbcTemplatejdbcTemplate) { this.jdbcTemplate=jdbcTemplate; } }
Spring的XML配置文件命名为jdbc.xml,jdbc.xml的写法为:
主函数为:
publicstaticvoidmain(String[]args) { ApplicationContextac= newClassPathXmlApplicationContext("jdbc.xml"); System.out.println(StudentManager.getInstance()); System.out.println(StudentManager.getInstance().getJdbcTemplate()); }
运行没什么问题,得到StudentManager的引用地址和StudentManager中属性jdbcTemplate的引用地址,说明整个连接、注入都没问题。
JDBCTemple是Spring里面最基本的JDBC模板,利用JDBC和简单的索引参数查询提供对数据库的简单访问。除了JDBCTemplate,Spring还提供了NamedParameterJdbcTemplate和SimpleJdbcTemplate两个类,前者能够在执行查询时把值绑定到SQL里的命名参数而不是使用索引,后者利用Java5的特性比如自动装箱、泛型和可变参数列表来简化JDBC模板的使用。具体使用哪个看个人喜好,这里使用JdbcTemplate,所以把JdbcTemplate添加到学生管理类中。
另外:
1、dbcp提供很多参数给用户配置,每个参数的意思都以注释的形式写在.xml里面了,更加具体要知道每个参数的意思可以上网查询一下
2、注意dbcp的属性url,url指的是数据库连接地址,遇到特殊字符需要转义,所以这里的"&"变成了"&",不然会报错
基于Spring的JDBC增删改查
上面一部分搭建了一个SpringJDBC的基础框架,下面看一下Java代码如何实现CRUD,这个过程中jdbc.xml都不需要变化。
1、添加一个学生信息,代码为:
//添加学生信息 publicbooleanaddStudent(Studentstudent) { try { jdbcTemplate.update("insertintostudentvalues(null,?,?,?)", newObject[]{student.getStudentName(),student.getStudentAge(),student.getStudentPhone()}, newint[]{Types.VARCHAR,Types.INTEGER,Types.VARCHAR}); returntrue; } catch(Exceptione) { returnfalse; } }
2、根据Id删除指定学生信息,代码为:
//根据Id删除单个学生信息 publicbooleandeleteStudent(intid) { try { jdbcTemplate.update("deletefromstudentwherestudentId=?",newObject[]{id},newint[]{Types.INTEGER}); returntrue; } catch(Exceptione) { returnfalse; } }
3、根据Id更新学生信息,代码为:
//根据Id更新指定学生信息 publicbooleanupdateStudent(intId,Studentstudent) { try { jdbcTemplate.update("updatestudentsetstudentName=?,studentAge=?,studentPhone=?wherestudentId=?", newObject[]{student.getStudentName(),student.getStudentAge(),student.getStudentPhone(),Id}, newint[]{Types.VARCHAR,Types.INTEGER,Types.VARCHAR,Types.INTEGER}); returntrue; } catch(Exceptione) { returnfalse; } }
4、根据Id查询学生信息,代码为:
//根据学生Id查询单个学生信息 publicStudentgetStudent(intid) { try { return(Student)jdbcTemplate.queryForObject("select*fromstudentwherestudentId=?", newObject[]{id},newint[]{Types.INTEGER},newRowMapper(){ publicStudentmapRow(ResultSetrs,intarg1)throwsSQLException { Studentstudent=newStudent(rs.getInt(1),rs.getString(2),rs.getInt(3),rs.getString(4)); returnstudent; } }); } //根据Id查询学生信息抛异常,不管什么原因,认为查询不到该学生信息,返回null catch(DataAccessExceptione) { returnnull; } }
5、查询所有学生信息,代码为:
//查询所有学生信息 publicListgetStudents() { List