- 浏览: 4184228 次
最新评论
【web】赵雅智_jdbc开发
使用数据库连接池优化程序性能
应用程序直接获取链接的缺点
缺点:用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、宕机。
【案例】传统方法连接数据库
- 配置文件db.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/java username=root password=123456
- 加载数据库驱动
- 连接数据库java代码 DBConn.java
package com.hbsi.util; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; public class DBConn { static String driver; static String url; static String username; static String password; static{ InputStream in = DBConn.class.getClassLoader().getResourceAsStream("db.properties"); Properties pro = new Properties(); try { pro.load(in); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } driver = pro.getProperty("driver"); url = pro.getProperty("url"); username = pro.getProperty("username"); password = pro.getProperty("password"); } public static Connection getConnection(){ Connection conn = null; try { Class.forName(driver); conn = DriverManager.getConnection(url,username,password); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); }catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return conn; } public static void close(ResultSet rs, PreparedStatement ps, Connection conn){ if(rs != null){ try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(ps != null){ try { ps.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
- 测试 DBConnTest.java
package com.hbsi.test; import org.junit.Test; import com.hbsi.util.DBConn; import junit.framework.TestCase; public class DBConnTest extends TestCase { @Test public void testGetConn(){ System.out.print(DBConn.getConnection()); } }
- java应用类
package com.hbsi.demo; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.hbsi.util.DBConn; public class ChuanTong { public static void main(String[] args) { Connection conn = null; PreparedStatement ps =null; ResultSet rs = null; try{ conn = DBConn.getConnection(); //..... System.out.println(conn); //..... }catch(Exception e){ e.printStackTrace(); }finally{ DBConn.close(rs, ps, conn); } } }
使用连接池:
编写数据库连接池
- 编写连接池需实现javax.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
- Connection getConnection()
- Connection getConnection(String username, String password)
- 实现DataSource接口,并实现连接池功能的步骤:
- 在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
- 实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。
- 当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。
- Collection保证将自己返回到LinkedList中是此处编程的难点。
使用动态代理技术构建连接池中的connection--自己编写
动态代理
- 明确两个概念:
- 代理对象存在的价值:主要用于拦截对真实业务对象的访问。
- 代理对象有什么方法
- Java提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,使用该方法生成代理对象时,需要三个参数:
- 生成代理对象使用哪个类装载器
- 生成哪个对象的代理对象,通过接口指定
- 生成的代理对象的方法里干什么事,由开发人员编写handler接口的实现来指定。
- 初学者必须理解,或不理解必须记住的2件事情:
- Proxy类负责创建代理对象时,如果指定了handler(处理器),那么不管用户调用代理对象的什么方法,该方法都是调用处理器的invoke方法。
- 由于invoke方法被调用需要三个参数:代理对象、方法、方法的参数,因此不管代理对象哪个方法调用处理器的invoke方法,都必须把自己所在的对象、自己(调用invoke方法的方法)、方法的参数传递进来。
建立了一个代理类,传入代理对象、方法、方法的参数
如果想访问真是对象的方法只能通过invoke访问
【案例】自编写连接池
- java类
package com.hbsi.util; import java.io.InputStream; import java.io.PrintWriter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.LinkedList; import java.util.Properties; import javax.sql.DataSource; public class MyJdbcPool implements DataSource { // 创建的连接放在linklist里 private static LinkedList<Connection> list = new LinkedList<Connection>(); private static String driver; private static String url; private static String username; private static String password; // 通过静态代码块创建连接 static { try { // 类加载器 InputStream in = MyJdbcPool.class.getClassLoader() .getResourceAsStream("db.properties"); //属性对象 Properties prop = new Properties(); prop.load(in); driver = prop.getProperty("driver"); url = prop.getProperty("url"); username = prop.getProperty("username"); password = prop.getProperty("password"); //连接数据库,加载驱动 Class.forName(driver); //创建一批连接 for (int i = 0; i < 10; i++) { Connection conn = DriverManager.getConnection(url, username, password); System.out.println("向池中加入了:" + conn); list.add(conn); } } catch (Exception e) { e.printStackTrace(); } } public Connection getConnection() throws SQLException { if (list.size() > 0) { //不用get方法,get方法会出现重复利用 final Connection conn = list.removeFirst(); System.out.println("用户从池中取走了:" + conn); System.out.println("池的大小为:" + list.size()); //动态代理,那个类,哪个对象,干什么事 return (Connection) Proxy.newProxyInstance(MyJdbcPool.class .getClassLoader(), new Class[] { Connection.class }, new InvocationHandler() { //做什么事情,放回连接池里 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (!method.getName().equalsIgnoreCase("close")) { return method.invoke(conn, args); } System.out.println(conn + "被还了"); list.add(conn); System.out.println("池的大小为:" + list.size()); return null; } }); } else { throw new RuntimeException("对不起,请稍等!"); } } public Connection getConnection(String username, String password) throws SQLException { // TODO Auto-generated method stub return null; } public PrintWriter getLogWriter() throws SQLException { // TODO Auto-generated method stub return null; } public int getLoginTimeout() throws SQLException { // TODO Auto-generated method stub return 0; } public void setLogWriter(PrintWriter out) throws SQLException { // TODO Auto-generated method stub } public void setLoginTimeout(int seconds) throws SQLException { // TODO Auto-generated method stub } public boolean isWrapperFor(Class<?> iface) throws SQLException { // TODO Auto-generated method stub return false; } public <T> T unwrap(Class<T> iface) throws SQLException { // TODO Auto-generated method stub return null; } }
- 测试java类
package com.hbsi.demo; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.hbsi.util.DBConn; import com.hbsi.util.MyJdbcPool; public class MyJdbcPoolDemo { public static void main(String[] args) { Connection conn = null; PreparedStatement ps =null; ResultSet rs = null; try{ MyJdbcPool pool = new MyJdbcPool(); conn =pool.getConnection(); //..... System.out.println(conn); //..... }catch(Exception e){ e.printStackTrace(); }finally{ DBConn.close(rs, ps, conn); } } }
开源数据库连接池
- 现在很多WEB服务器(Weblogic, WebSphere, Tomcat)都提供了DataSource的实现,即连接池的实现。通常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。
- 也有一些开源组织提供了数据源的独立实现:
- DBCP 数据库连接池
- C3P0 数据库连接池
- 实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接。程序员编程时也应尽量使用这些数据源的实现,以提升程序的数据库访问性能。
DBCP数据源
- DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加如下两个 jar 文件:
- Commons-dbcp.jar:连接池的实现
- Commons-pool.jar:连接池实现的依赖库
- Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。
【案例】dbcp连接数据库
- 考jar包
- 写配置文件
#Á¬½ÓÉèÖà driverClassName=com.mysql.jdbc.Driver url=jdbc\:mysql\://localhost\:3306/java username=root password=123456 #<!-- ³õʼ»¯Á¬½Ó --> initialSize=10 #×î´óÁ¬½ÓÊýÁ¿ maxActive=50 #<!-- ×î´ó¿ÕÏÐÁ¬½Ó --> maxIdle=20 #<!-- ×îС¿ÕÏÐÁ¬½Ó --> minIdle=5 #<!-- ³¬Ê±µÈ´ýʱ¼äÒÔºÁÃëΪµ¥Î» 6000ºÁÃë/1000µÈÓÚ60Ãë --> maxWait=60000 #JDBCÇý¶¯½¨Á¢Á¬½Óʱ¸½´øµÄÁ¬½ÓÊôÐÔÊôÐԵĸñʽ±ØÐëΪÕâÑù£º[ÊôÐÔÃû=property;] #×¢Ò⣺"user" Óë "password" Á½¸öÊôÐԻᱻÃ÷È·µØ´«µÝ£¬Òò´ËÕâÀï²»ÐèÒª°üº¬ËûÃÇ¡£ connectionProperties=useUnicode=true;characterEncoding=gbk #Ö¸¶¨ÓÉÁ¬½Ó³ØËù´´½¨µÄÁ¬½ÓµÄ×Ô¶¯Ìá½»£¨auto-commit£©×´Ì¬¡£ defaultAutoCommit=true #driver default Ö¸¶¨ÓÉÁ¬½Ó³ØËù´´½¨µÄÁ¬½ÓµÄÖ»¶Á£¨read-only£©×´Ì¬¡£ #Èç¹ûûÓÐÉèÖøÃÖµ£¬Ôò¡°setReadOnly¡±·½·¨½«²»±»µ÷Óᣣ¨Ä³Ð©Çý¶¯²¢²»Ö§³ÖÖ»¶Áģʽ£¬È磺Informix£© defaultReadOnly= #driver default Ö¸¶¨ÓÉÁ¬½Ó³ØËù´´½¨µÄÁ¬½ÓµÄÊÂÎñ¼¶±ð£¨TransactionIsolation£©¡£ #¿ÉÓÃֵΪÏÂÁÐÖ®Ò»£º£¨ÏêÇé¿É¼ûjavadoc¡££©NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
修改乱码:-
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc\:mysql\://localhost\:3306/java username=root password=123456 #<!-- 初始化连接 --> initialSize=10 #最大连接数量 maxActive=50 #<!-- 最大空闲连接 --> maxIdle=20 #<!-- 最小空闲连接 --> minIdle=5 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。 connectionProperties=useUnicode=true;characterEncoding=gbk #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的只读(read-only)状态。 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix) defaultReadOnly= #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
-
- 编写java工具类 DBManger_dbcp.java
package com.hbsi.util; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; public class DBManger_dbcp { private static DataSource ds ; static{ try{ InputStream in = DBManger_dbcp.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"); Properties prop = new Properties(); prop.load(in); ds = BasicDataSourceFactory.createDataSource(prop); }catch(Exception e){ e.printStackTrace(); } } public static Connection getConnction() throws SQLException{ return ds.getConnection(); } }
- 提供一个方法,从池里去连接DBManger_dbcpDemo.java
package com.hbsi.demo; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.hbsi.util.DBConn; import com.hbsi.util.DBManger_dbcp; public class DBManger_dbcpDemo { public static void main(String[] args) { Connection conn = null; PreparedStatement ps =null; ResultSet rs = null; try{ conn = DBManger_dbcp.getConnction(); //..... System.out.println(conn); //..... }catch(Exception e){ e.printStackTrace(); }finally{ DBConn.close(rs, ps, conn); } } }
C3P0 数据源
【案例】c3p0连接数据库
- 加jar包
- 编写工具类DBManager_c3p0.java
package com.hbsi.util; import java.sql.Connection; import java.sql.SQLException; import com.mchange.v2.c3p0.ComboPooledDataSource; public class DBManager_c3p0 { private static ComboPooledDataSource ds = null; static{ try{ //创建连接池 ds = new ComboPooledDataSource("mysql"); }catch(Exception e){ e.printStackTrace(); } } public static Connection getConnection() throws SQLException{ return ds.getConnection(); } }
- 编写连接配置文件c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/java</property> <property name="user">root</property> <property name="password">123456</property> <property name="acquireIncrement">5</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">5</property> <property name="maxPoolSize">20</property> </default-config> <named-config name="mysql"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/java</property> <property name="user">root</property> <property name="password">123456</property> <property name="acquireIncrement">5</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">5</property> <property name="maxPoolSize">20</property> </named-config> </c3p0-config>
- 相应实现DBManager_c3p0Demo.java
package com.hbsi.demo; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.hbsi.util.DBConn; import com.hbsi.util.DBManager_c3p0; public class DBManager_c3p0Demo { public static void main(String[] args) { Connection conn = null; PreparedStatement ps =null; ResultSet rs = null; try{ conn = DBManager_c3p0.getConnection(); //..... System.out.println(conn); //..... }catch(Exception e){ e.printStackTrace(); }finally{ DBConn.close(rs, ps, conn); } } }
配置Tomcat数据源
特别提醒:此种配置下,驱动jar文件需放置在tomcat的lib下JNDI技术简介
- JNDI(Java Naming and Directory Interface),Java命名和目录接口,它对应于J2SE中的javax.naming包,
- 这套API的主要作用在于:它可以把Java对象放在一个容器中(JNDI容器),并为容器中的java对象取一个名称,以后程序想获得Java对象,只需通过名称检索即可。
- 其核心API为Context,它代表JNDI容器,其lookup方法为检索容器中对应名称的对象。
【实例】利用Tomcat实现数据库连接
在META-INF下新建context.xml
context.xml
<Context> <Resourse name="jdbc/javaDB" auth="Container" type="javax.sql.DataSource" username="root" password="123456" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/java" maxActive="8" maxIdle="4"/> </Context>
做一个servlet,读取xml文件
package com.hbsi.util; import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; public class TomcatPool extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { //初始化jndi容器 Context initCxt = new InitialContext(); //获取容器,检索出web服务器中的jndi容器 Context envCxt = (Context)initCxt.lookup("java:comp/env"); //从jndi容器中检索出连接池 DataSource ds = (DataSource)envCxt.lookup("jdbc/javaDB"); //获取连接 Connection conn = ds.getConnection(); System.out.println(conn); } catch (NamingException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
把jar包考到Tomcat的lib文件夹下
结果:
相关推荐
Access_JDBC30.jar jaar包 要的请抢先
亲测, 已破解Access_JDBC30.jar 无查询次数限制, 无最大1000行限制, 已经完全破解.
Java连接达梦数据库驱动dm_jdbc: dm_jdbc\com.dameng.floader.jar dm_jdbc\com.dameng.impexp.jar dm_jdbc\Dm7Dictionary.jar dm_jdbc\Dm7JdbcDriver14.jar dm_jdbc\Dm7JdbcDriver15.jar dm_jdbc\Dm7JdbcDriver16....
Access_JDBC30.jar解决 1.破解仅支持连续查询50次和1000行的限制; 2.修复原版jar包使用execute()和executeUpdate()方法报空指针异常的BUG。
MySQL_for_JDBC,Oracle9i_for_JDBC,SQL_2000_for_JDBC,SQL_2005_for_JDBC数据库驱动架包.rar
test_web05_jdbc源码.rar
不限量,不限次数,无限使用,绝对OK,亲测无误 Access_JDBC30.jar (破解版)不限查询次数
连接Access数据库的jar包。如果使用Access_JDBC30.jar,代码没问题,数据库也已正常连接,能增删改查,但还是会报数据库连接错,可以换用此jar包,问题将解决。解压后即可使用。
hive_jdbc_2.6.2.1002
解决了access_jdbc30对查询次数及单次查询条数的限制,可使用jdbc直连的方式连接mdb文件,无需使用jdbc-odbc桥连的方式,并且无查询次数及查询条数的限制。
用Oracle JDeveloper 10g IDE基于JDBC API的Web开发的简单测试.[InsertData]文件夹完成数据插入功能;[queryMetaData]纪录集元数据;[updateTable]完成可被更新和滚动的纪录集;[bindQuery]实现PreparedStatement...
1.破解仅支持连续查询50次和1000行的限制; 2.修复原版jar包使用execute()和executeUpdate()方法报空指针异常的BUG。
String url ="jdbc:access:/d:/empty.mdb"; Class.forName("com.hxtt.sql.access.AccessDriver"); Connection con = DriverManager.getConnection(url); Statement statement = con.createStatement(); ...
Java写了一个连接Access数据库的桌面程序,百度很长时间发现jdk1.8没有rt.jar,没法通过第一种方式jdbc:odbc方式连接access数据库,可以通过第四种方式驱动直连access。 实现步骤①外部jar包(Access_JDBC30.jar)导入...
greenplum java 驱动。版本:5.1.4. greenplum官方的驱动。 greenplum是postgresql集群支持。
Server_JDBC_Driver_20_EULA_CHS
web项目超市管理系统,使用最原始的JDBC访问数据库,包括dao、entity、servlet、jsp等,其中有数据库的导入表
这个版本的不知道支持什么版本,有其他版本需要改的,可以找我,留言即可