import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class DBConnection { private static final String DBDRIVER = "com.mysql.jdbc.Driver" ; //驱动类类名 private static final String DBURL = "jdbc:mysql://localhost:3306/db_affairmanage";//链接URL private static final String DBUSER = "root" ; //数据库用户名 private static final String DBPASSWORD = "XXXXXX"; //数据库密码 public static Connection getConnection(){ Connection conn = null; //声明一个链接对象 try { Class.forName(DBDRIVER); //注册驱动 conn = DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD); //得到链接对象 } catch (ClassNotFoundException e) { //捕获驱动类没法找到异常 e.printStackTrace(); } catch (SQLException e) { //捕获SQL异常 e.printStackTrace(); } return conn; } public static void close(Connection conn) {//关闭链接对象 if(conn != null) { //若是conn链接对象不为空 try { conn.close(); //关闭conn链接对象对象 } catch (SQLException e) { e.printStackTrace(); } } } public static void close(PreparedStatement pstmt) {//关闭预处理对象 if(pstmt != null) { //若是pstmt预处理对象不为空 try { pstmt.close(); //关闭pstmt预处理对象 } catch (SQLException e) { e.printStackTrace(); } } } public static void close(ResultSet rs) {//关闭结果集对象 if(rs != null) { //若是rs结果集对象不为null try { rs.close(); //关闭rs结果集对象 } catch (SQLException e) { e.printStackTrace(); } } } }
public interface CriticismDAO { public void addCriticism(Criticism criticism); //添加回复 }
public class CriticismDAOImpl implements CriticismDAO{ public void addCriticism(Criticism criticism) { Connection conn = DBConnection.getConnection(); //得到链接对象 String addSQL = "insert into tb_criticism(criticismContent,criticismTime,messageID) values(?,?,?,?)"; PreparedStatement pstmt = null; //声明预处理对象 try { pstmt = conn.prepareStatement(addSQL); //得到预处理对象并赋值 pstmt.setString(1, criticism.getCriticismContent()); //设置第一个参数 pstmt.setInt(2, criticism.getEmployeeID());//设置第二个参数 pstmt.setInt(3, criticism.getMessageID()); pstmt.executeUpdate(); //执行更新 } catch (SQLException e) { e.printStackTrace(); } finally{ DBConnection.close(pstmt); //关闭预处理对象 DBConnection.close(conn); //关闭链接对象 } }
(1)当Jdbc程序向数据库得到一个Connection对象时,默认状况下这个Connection对象会自动向数据库提交在它上面发送的SQL语句。若想关闭这种默认提交方式,让多条SQL在一个事务中执行,可以使用下列语句:java
(2)JDBC控制事务语句mysql
Connection.setAutoCommit(false); sql
Connection.rollback(); 数据库
Connection.commit(); apache
(1)为何使用链接池编程
链接,是咱们的编程语言与数据库交互的一种方式。咱们常常会听到这么一句话“数据库链接很昂贵“,简单的获取一个链接,系统却要在背后作不少消耗资源的事情,大多时候,建立链接的时间比执行sql语句的时间还要长,用户每次请求都须要向数据库得到连接,而数据库建立链接一般须要消耗相对较大的资源,建立时间也较长。假设网站一天10万访问量,数据库服务器就须要建立10万次链接,极大的浪费数据库的资源,而且极易形成数据库服务器内存溢出、拓机;数据库链接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤其突出。对数据库链接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库链接池负责分配,管理和释放数据库链接,它容许应用程序重复使用一个现有的数据库链接,而不是从新创建一个设计模式
(2)链接池核心思想安全
链接池技术的核心思想是:链接复用,经过创建一个数据库链接池以及一套链接使用、分配、管理策略,使得该链接池中的链接能够获得高效、安全的复用,避免了数据库链接频繁创建、关闭的开销。另外,因为对JDBC中的原始链接进行了封装,从而方便了数据库应用对于链接的使用(特别是对于事务处理),提升了获取数据库链接效率,也正是由于这个封装层的存在,隔离了应用的自己的处理逻辑和具体数据库访问逻辑,使应用自己的复用成为可能。链接池主要由三部分组成:链接池的创建、链接池中链接的使用管理、链接池的关闭服务器
(3)链接池的管理编程语言
链接池管理策略是链接池机制的核心。当链接池创建后,如何对链接池中的链接进行管理,解决好链接池内链接的分配和释放,对系统的性能有很大的影响。链接的合理分配、释放可提升链接的复用,下降了系统创建新链接的开销,同时也加速了用户的访问速度。下面介绍链接池中链接的分配、释放策略。
链接池的分配、释放策略对于有效复用链接很是重要,咱们采用的方法是一个颇有名的设计模式:Reference Counting(引用记数)。该模式在复用资源方面应用的很是普遍,把该方法运用到对于链接的分配释放上,为每个数据库链接,保留一个引用记数,用来记录该链接的使用者的个数。具体的实现方法是:
当客户请求数据库链接时,首先查看链接池中是否有空闲链接(指当前没有分配出去的链接)。若是存在空闲链接,则把链接分配给客户并做相应处理(即标记该链接为正在使用,引用计数加1)。若是没有空闲链接,则查看当前所开的链接数是否是已经达到maxConn(最大链接数),若是没达到就从新建立一个链接给请求的客户;若是达到就按设定的maxWaitTime(最大等待时间)进行等待,若是等待maxWaitTime后仍没有空闲链接,就抛出无空闲链接的异常给用户。
当客户释放数据库链接时,先判断该链接的引用次数是否超过了规定值,若是超过就删除该链接,并判断当前链接池内总的链接数是否小于minConn(最小链接数),若小于就将链接池充满;若是没超过就将该链接标记为开放状态,可供再次复用。能够看出正是这套策略保证了数据库链接的有效复用,避免频繁地创建、释放链接所带来的系统资源开销。
(4)链接池的关闭
当应用程序退出时,应关闭链接池,此时应把在链接池创建时向数据库申请的链接对象统一归还给数据库(即关闭全部数据库链接),这与链接池的创建正好是一个相反过程
(5)链接池配置
链接池是建立和管理一个链接的缓冲池的技术,这些链接准备好被任何须要它们的线程使用,经常使用链接池有dbcp,c3p0,Proxool,这里只介绍一下dbcp
DBCP链接池
DBCP 是 Apache 软件基金组织下的开源链接池实现,要使用DBCP数据源,须要应用程序应在系统中增长以下两个 jar 文件: Commons-dbcp.jar:链接池的实现 Commons-pool.jar:链接池实现的依赖库 Tomcat 的链接池正是采用该链接池来实现的。该数据库链接池既能够与应用服务器整合使用,也可由应用程序独立使用
步骤1: 在类目录下加入dbcp的配置文件:dbcp.properties
#数据库驱动 driverClassName=com.mysql.jdbc.Driver #数据库链接地址 url=jdbc:mysql://localhost/test #用户名 username=root #密码 password=123456 #链接池的最大数据库链接数。设为0表示无限制 maxActive=30 #最大空闲数,数据库链接的最大空闲时间。超过空闲时间,数据库连 #接将被标记为不可用,而后被释放。设为0表示无限制 maxIdle=10 #最大创建链接等待时间。若是超过此时间将接到异常。设为-1表示无限制 maxWait=1000 #超过removeAbandonedTimeout时间后,是否进行没用链接(废弃)的回收(默认为false,调整为true) removeAbandoned=true #超过期间限制,回收没有用(废弃)的链接(默认为 300秒) removeAbandonedTimeout=180
步骤2: 在获取数据库链接的工具类(如jdbcUtils)的静态代码块中建立池:
import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; /** * 在java中,编写数据库链接池需实现java.sql.DataSource接口,每一种数据库链接池都是DataSource接口的实现 * DBCP链接池就是java.sql.DataSource接口的一个具体实现 */ public classJdbcUtils_DBCP { private static DataSource ds = null; //在静态代码块中建立数据库链接池 static{ try{ //加载dbcp.properties配置文件 InputStream in =JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcp.properties"); Properties prop = new Properties(); prop.load(in); //建立数据源 ds =BasicDataSourceFactory.createDataSource(prop); }catch (Exception e) { throw newExceptionInInitializerError(e); } } //从数据源中获取数据库链接 public static Connection getConnection()throws SQLException{ //从数据源中获取数据库链接 return ds.getConnection(); } //释放链接 public static void release(Connection conn){ if(conn!=null){ try{ //将Connection链接对象还给数据库链接池 conn.close(); }catch (Exception e) { e.printStackTrace(); } } } }
步骤3:在应用中获取链接
Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ //获取数据库链接 conn =JdbcUtils_DBCP.getConnection(); …… }catch (Exception e) { e.printStackTrace(); }finally{ //释放资源 JdbcUtils_DBCP.release(conn); }