J2EE进阶之JDBC数据库连接池 十九
来源:互联网 发布:php连不上mysql数据库 编辑:程序博客网 时间:2024/06/05 16:31
JDBC之数据库连接池
使用数据库连接池优化程序性能
不用连接池缺点:
使用连接池的话:
编写一个简单的连接池
连接池实现原理:
1 public class SimpleConnectionPool { 2 //池:存链接 3 private static List<Connection> pool = new ArrayList<Connection>(); 4 static{ 5 try { 6 //初始化10个链接 7 for(int i=0;i<10;i++){ 8 Connection conn = JdbcUtil.getConnection(); 9 pool.add(conn); 10 } 11 } catch (Exception e) { 12 throw new ExceptionInInitializerError("连接池初始化失败"); 13 } 14 } 15 //从池中取出一个链接 16 public synchronized static Connection getConnection(){ 17 if(pool.size()>0){ 18 Connection conn = pool.remove(0); 19 return conn; 20 }else{ 21 //继续创建一个链接供用户使用 22 //再向池中放一定数量的链接 23 //让用户等:超时。 24 //通知用户:服务器忙 25 throw new RuntimeException("对不起!服务器真忙,请稍后再试"); 26 } 27 } 28 //用完连接后还回池中 29 public static void release(Connection conn){ 30 pool.add(conn); 31 } 32 }
测试
1 @Test 2 public void save(){ 3 Connection conn = null; 4 Statement stmt = null; 5 try{ 6 conn = SimpleConnectionPool.getConnection();//从池中取的数据 7 stmt = conn.createStatement(); 8 //... 9 }catch(Exception e){ 10 e.printStackTrace(); 11 }finally{ 12 if(stmt!=null){ 13 try { 14 stmt.close(); 15 } catch (SQLException e) { 16 e.printStackTrace(); 17 } 18 } 19 if(conn!=null){ 20 SimpleConnectionPool.release(conn);//还回池中 21 } 22 } 23 }
编写连接池需实现javax.sql.DataSource接口
DataSource编写
利用动态代理实现
MyDataSource1
1 public class MyDataSource1 implements DataSource { 2 private static List<Connection> pool = new ArrayList<Connection>(); 3 static{ 4 try { 5 //初始化10个链接 6 for(int i=0;i<10;i++){ 7 Connection conn = JdbcUtil.getConnection(); 8 pool.add(conn); 9 } 10 } catch (Exception e) { 11 throw new ExceptionInInitializerError("连接池初始化失败"); 12 } 13 } 14 //要从池中获取链接,利用动态代理机制。若调用获取连接对象,并使用其方法,是close方法的话,就使用代理规定的方法。 15 public Connection getConnection() throws SQLException { 16 if(pool.size()>0){ 17 final Connection conn = pool.remove(0);//驱动的 18 //返回驱动的实例的代理对象 19 20 /* 21 * 产生代理对象的实例 22 * public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 23 * 24 * ClassLoader loader:既然代理类也是类,必定要类加载器加载。固定写法:和被代理对象一样 25 * Class<?>[] interfaces:代理对象要实现的接口。固定写发:和被代理对象一样。目的就是拥有相同的行为 26 * InvocationHandler h:策略设计模式。是一个接口,你必须传入一个实现了该接口的对象(具体代理方案)。 27 */ 28 Connection proxy = (Connection)Proxy.newProxyInstance(conn.getClass().getClassLoader(), 29 conn.getClass().getInterfaces(), 30 new InvocationHandler() { 31 32 /** 33 * //调用代理对象的任何方法,该方法都会被执行 34 * @param proxy 代理对象本身的引用,一般用不着 35 * @param method 当前执行的方法 36 * @param args当前方法用到的参数 37 * @return 当前方法的返回值 38 * @throws Throwable 39 */ 40 public Object invoke(Object proxy, Method method, Object[] args) 41 throws Throwable { 42 //判断是不是close方法,如果是,把链接放回池中 43 if("close".equals(method.getName())){ 44 return pool.add(conn); 45 } 46 return method.invoke(conn, args); 47 } 48 }); 49 return proxy; 50 }else{ 51 //继续创建一个链接供用户使用 52 //再向池中放一定数量的链接 53 //让用户等:超时。 54 //通知用户:服务器忙 55 throw new RuntimeException("对不起!服务器真忙,请稍后再试"); 56 } 57 } 58
开源数据源(数据库连接池) DBCP和C3P0
DBCP
搭建开发环境:
a、拷贝jar包:commons-dbcp.jar commons-pool.jar
b、在classpath中添加DBCP的配置文件:
c、编写工具类:
配置文件;
1 #连接设置 2 driverClassName=com.mysql.jdbc.Driver 3 url=jdbc:mysql://localhost:3306/wsj 4 username=root 5 password=root 6 7 #<!-- 初始化连接 --> 8 initialSize=10 9 10 #最大连接数量 11 maxActive=50 12 13 #<!-- 最大空闲连接 --> 14 maxIdle=20 15 16 #<!-- 最小空闲连接 --> 17 minIdle=5 18 19 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> 20 maxWait=60000 21 22 23 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 24 #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。 25 connectionProperties=useUnicode=true;characterEncoding=utf8 26 27 #指定由连接池所创建的连接的自动提交(auto-commit)状态。 28 defaultAutoCommit=true 29 30 #driver default 指定由连接池所创建的连接的只读(read-only)状态。 31 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix) 32 defaultReadOnly= 33 34 #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 35 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE 36 defaultTransactionIsolation=READ_COMMITTED
工具类
1 public class DBCPUtil { 2 private static DataSource dataSource; 3 static{ 4 try { 5 Properties props = new Properties(); 6 ClassLoader cl = DBCPUtil.class.getClassLoader(); 7 InputStream in = cl.getResourceAsStream("dbcpconfig.properties"); 8 props.load(in); 9 dataSource = BasicDataSourceFactory.createDataSource(props); 10 } catch (Exception e) { 11 throw new ExceptionInInitializerError(e); 12 } 13 } 14 public static DataSource getDataSource(){ 15 return dataSource; 16 } 17 public static Connection getConnection(){ 18 try { 19 return dataSource.getConnection(); 20 } catch (SQLException e) { 21 throw new RuntimeException(e); 22 } 23 } 24 }
测试
public class DBCPUtilTest { @Test public void test1() throws SQLException{ Connection conn = DBCPUtil.getConnection(); System.out.println(conn.getClass().getName()); conn.close(); }}
C3P0
a、拷贝jar包:c3p0-0.9.1.2.jar c3p0-oracle-thin-extras-0.9.1.2.jar(oracle瘦客户端需要)
b、在classpath中添加配置文件:
c、编写工具类:
配置文件
工具类
public class C3P0Util { private static ComboPooledDataSource dataSource = new ComboPooledDataSource(); public static DataSource getDataSource(){ return dataSource; } public static Connection getConnection(){ try { return dataSource.getConnection(); } catch (SQLException e) { throw new RuntimeException(e); } }}
测试
public class C3P0UtilTest {
@Test
public void test1() throws SQLException{
Connection conn = C3P0Util.getConnection();
System.out.println(conn.getClass().getName());
conn.close();
}
}
利用JNDI获取数据源:更加接近真实
1、拷贝数据库的驱动到Tomcat\lib目录中。 (既mysql-connector-java.jar包)
2、在web应用的META-INF目录下,建立一个context.xml的配置文件
<?xml version="1.0" encoding="UTF-8"?><Context> <Resource name="jdbc/wsj" auth="Container" type="javax.sql.DataSource" maxActive="50" maxIdle="30" maxWait="10000" username="root" password="sorry" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/wsj"/></Context>
3.重启Tomcat
测试:
Context initContext = new InitialContext(); Context envContext = (Context)initContext.lookup("java:/comp/env");//Tomcat的放的资源的路径 DataSource ds = (DataSource)envContext.lookup("jdbc/wsj");//name Connection conn = ds.getConnection(); out.write(conn.toString());
JDBC简单框架
数据源信息的获取
1 //数据库元信息的获取 2 public class MetaDataDemo { 3 //数据库本身的元信息 4 @Test 5 public void test1() throws Exception{ 6 Connection conn = DBCPUtil.getConnection(); 7 DatabaseMetaData dbmd = conn.getMetaData(); 8 System.out.println(dbmd.getDatabaseProductName()); 9 System.out.println(dbmd.getDatabaseProductVersion()); 10 conn.close(); 11 } 12 //SQL语句占位符的元信息:计算?的个数 13 @Test 14 public void test2()throws Exception{ 15 Connection conn = DBCPUtil.getConnection(); 16 PreparedStatement stmt = conn.prepareStatement("?????"); 17 ParameterMetaData pmd = stmt.getParameterMetaData(); 18 int paramNum = pmd.getParameterCount();//得到占位符的数量 19 System.out.println(paramNum); 20 conn.close(); 21 } 22 //查询结果集的元数据 23 @Test 24 public void test3()throws Exception{ 25 Connection conn = DBCPUtil.getConnection(); 26 PreparedStatement stmt = conn.prepareStatement("select * from account"); 27 ResultSet rs = stmt.executeQuery(); 28 ResultSetMetaData rsmd = rs.getMetaData(); 29 //有几列? 每列的列名是啥?类型又是啥? 30 int columnCount = rsmd.getColumnCount(); 31 for(int i=0;i<columnCount;i++){ 32 String columnName = rsmd.getColumnName(i+1);//列名。第一列的索引是1 33 int columnType = rsmd.getColumnType(i+1);//列类型。用的是整数常量表示的。 34 System.out.println(columnName+":"+columnType); 35 } 36 conn.close(); 37 } 38 }
工具类编写
封装数据;
BeanHandler
1 /** 2 * 适合结果集只有一条的情况。 3 * 使用前提:数据库的字段名和目标类的字段名保持一致。约定。 4 * 目标对象到底啥:谁用谁知道 5 */ 6 public class BeanHandler implements ResultSetHandler { 7 8 private Class clazz;//目标类型 9 public BeanHandler(Class clazz){ 10 this.clazz = clazz; 11 } 12 13 public Object handle(ResultSet rs) { 14 15 try { 16 Object bean = clazz.newInstance(); 17 //封装数据 18 if(rs.next()){ 19 ResultSetMetaData rsmd = rs.getMetaData(); 20 int columnCount = rsmd.getColumnCount();//列数 21 for(int i=0;i<columnCount;i++){ 22 String fieldName = rsmd.getColumnName(i+1);//列名。和javabean的字段名一样 23 Object fieldValue = rs.getObject(i+1); 24 //给javabean的字段赋值 25 Field field = clazz.getDeclaredField(fieldName);// private int id; 26 field.setAccessible(true);//强暴他 27 field.set(bean, fieldValue);// private int id=1; 28 } 29 } 30 return bean; 31 } catch (Exception e) { 32 throw new RuntimeException(e); 33 } 34 } 35 36 }
ResultSetHandler
public interface ResultSetHandler { /** * 把结果集中的数据封装到对象中 * @param rs * @return */ Object handle(ResultSet rs);}
BeanListHandler 多条
1 public class BeanListHandler implements ResultSetHandler { 2 private Class clazz;//目标类型 3 public BeanListHandler(Class clazz){ 4 this.clazz = clazz; 5 } 6 public Object handle(ResultSet rs) { 7 try { 8 List list = new ArrayList(); 9 //封装数据 10 while(rs.next()){ 11 Object bean = clazz.newInstance(); 12 ResultSetMetaData rsmd = rs.getMetaData(); 13 int columnCount = rsmd.getColumnCount();//列数 14 for(int i=0;i<columnCount;i++){ 15 String fieldName = rsmd.getColumnName(i+1);//列名。和javabean的字段名一样 16 Object fieldValue = rs.getObject(i+1); 17 //给javabean的字段赋值 18 Field field = clazz.getDeclaredField(fieldName);// private int id; 19 field.setAccessible(true);//强暴他 20 field.set(bean, fieldValue);// private int id=1; 21 } 22 list.add(bean); 23 } 24 return list; 25 } catch (Exception e) { 26 throw new RuntimeException(e); 27 } 28 } 29 30 }
增删改查DBAssist
1 public class DBAssist { 2 3 private DataSource dataSource; 4 public DBAssist(DataSource dataSource){ 5 this.dataSource = dataSource; 6 } 7 /** 8 * 查询 9 * @param sql 只能是查询语句 10 * @param params 如果没有参数,传null 11 * @return 封装后的信息 12 */ 13 public Object query(String sql,Object[] params,ResultSetHandler rsh) { 14 Connection conn = null; 15 PreparedStatement stmt = null; 16 ResultSet rs = null; 17 try{ 18 conn = dataSource.getConnection(); 19 stmt = conn.prepareStatement(sql); 20 //参数的一些处理 21 //得到sql中的参数元信息 22 ParameterMetaData pmd = stmt.getParameterMetaData(); 23 int paramCount = pmd.getParameterCount(); 24 if(paramCount>0){ 25 //有参数 26 if(params==null) 27 throw new RuntimeException("有占位符,不能不传递参数"); 28 if(paramCount!=params.length) 29 throw new RuntimeException("参数个数与占位符个数不匹配"); 30 //个数匹配 31 for(int i=0;i<paramCount;i++){ 32 stmt.setObject(i+1, params[i]); 33 } 34 } 35 rs = stmt.executeQuery(); 36 //查出来的数据在rs中。 用户执行的sql语句确定吗?不确定 37 //封装到JavaBean中或List中。封装到什么对象中确定吗?不确定 38 39 //确定:把结果集中的东西封装到JavaBean中。怎么封装?谁用谁知道。把路子铺好(接口),由使用着来走。策略设计模式 40 41 return rsh.handle(rs); 42 }catch(Exception e){ 43 throw new RuntimeException(e); 44 }finally{ 45 release(rs, stmt, conn); 46 } 47 } 48 /** 49 * 完成曾删改操作 50 * @param sql sql语句,参数要使用占位符 51 * @param params 顺序要和占位符的顺序对应.Java基础加强之可变参数 52 */ 53 public void update(String sql,Object[] params) { 54 Connection conn = null; 55 PreparedStatement stmt = null; 56 ResultSet rs = null; 57 try{ 58 conn = dataSource.getConnection(); 59 stmt = conn.prepareStatement(sql); 60 //参数的一些处理 61 //得到sql中的参数元信息 62 ParameterMetaData pmd = stmt.getParameterMetaData(); 63 int paramCount = pmd.getParameterCount(); 64 if(paramCount>0){ 65 //有参数 66 if(params==null) 67 throw new RuntimeException("有占位符,不能不传递参数"); 68 if(paramCount!=params.length) 69 throw new RuntimeException("参数个数与占位符个数不匹配"); 70 //个数匹配 71 for(int i=0;i<paramCount;i++){ 72 stmt.setObject(i+1, params[i]); 73 } 74 } 75 stmt.executeUpdate(); 76 }catch(Exception e){ 77 throw new RuntimeException(e); 78 }finally{ 79 release(rs, stmt, conn); 80 } 81 } 82 private void release(ResultSet rs,Statement stmt,Connection conn){ 83 if(rs!=null){ 84 try { 85 rs.close(); 86 } catch (SQLException e) { 87 e.printStackTrace(); 88 } 89 rs = null; 90 } 91 if(stmt!=null){ 92 try { 93 stmt.close(); 94 } catch (SQLException e) { 95 e.printStackTrace(); 96 } 97 stmt = null; 98 } 99 if(conn!=null){100 try {101 conn.close();102 } catch (SQLException e) {103 e.printStackTrace();104 }105 conn = null;106 }107 }108 }
bean类
1 public class Account implements Serializable { 2 private int id; 3 private String name; 4 private float money; 5 public int getId() { 6 return id; 7 } 8 public void setId(int id) { 9 this.id = id; 10 } 11 public String getName() { 12 return name; 13 } 14 public void setName(String name) { 15 this.name = name; 16 } 17 public float getMoney() { 18 return money; 19 } 20 public void setMoney(float money) { 21 this.money = money; 22 } 23 @Override 24 public String toString() { 25 return "Account [id=" + id + ", name=" + name + ", money=" + money 26 + "]"; 27 } 28 29 }
测试:
DBAssistTest
1 public class DBAssistTest { 2 private DBAssist da = new DBAssist(DBCPUtil.getDataSource()); 3 @Test 4 public void testAdd(){ 5 da.update("insert into account (id,name,money) values (?,?,?)", 6 new Object[]{4,"ddd",10000}); 7 } 8 @Test 9 public void testUpdate(){ 10 da.update("update account set money=? where id=?", 11 new Object[]{1000,4}); 12 } 13 @Test 14 public void testDel(){ 15 da.update("delete from account where id=?", 16 new Object[]{4}); 17 } 18 @Test 19 public void testFindOne(){ 20 Account a = (Account)da.query("select * from account", null, new BeanHandler(Account.class)); 21 System.out.println(a); 22 } 23 @Test 24 public void testFindAll(){ 25 List<Account> list = (List<Account>)da.query("select * from account", null, new BeanListHandler(Account.class)); 26 for(Account a:list) 27 System.out.println(a); 28 } 29 }
阅读全文
0 0
- J2EE进阶之JDBC数据库连接池 十九
- J2EE进阶之JDBC简介 十六
- jdbc之数据库连接池
- J2EE进阶之JDBC工具类DbUtils使用 二十
- JDBC开发之数据库连接池
- JDBC开发之数据库连接池
- JavaWeb:JDBC之数据库连接池
- J2EE之JBOSS配置数据库连接池
- 【J2EE规范】数据库连接——JDBC
- jdbc 学习总结三之数据库连接池
- JavaWeb之JDBC(数据库连接)
- jdbc之简单数据库连接
- JDBC数据库连接之配置文件
- J2EE之JDBC
- J2EE之JDBC
- J2EE中的数据库连接池
- javaee学习之路(十九)JDBC连接池
- J2EE进阶之JDBC简单应用之客户管理系统 十七
- Eclipse自动补全功能轻松设置
- MyBatis 详细介绍
- 考究Hadoop中split的计算方法
- 【PAT】Set Similarity&&Student List for Course
- 解决`向github提交代码是老要输入用户名密码`的问题
- J2EE进阶之JDBC数据库连接池 十九
- Python3之ftp下载简单代码
- mysql数据库case函数
- 真Unity3d_没看完这个先不要用2dtoolkit做UI
- Java版本HTTPSQS 纯java实现、 一个jar包、支持嵌入式启动、完全兼容HTTPSQS、TPS 1w+
- Css中,transform属性的matrix值简介
- 20170824 Java——I/O,字节流与字符流,BufferedOutputStream,InputStream等(附相关练习代码)
- TcpClient和UdpClient
- mysql提示符命令prompt