一、数据库连接池:
在一般用JDBC 进行连接数据库进行CRUD操作时,每一次都会:
通过:java.sql.Connection conn = DriverManager.getConnection(url,user,password); 重新获取一个数据库的链接再进行操作,这样用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。
所以为了减少服务器的压力,便可用连接池的方法:在启动Web应用时,数据就创建好一定数量的Connection链接
存放到一个容器中,然后当用户请求时,服务器则向容器中获取Connection链接来处理用户的请求,当用户的请求完成后,
又将该Connection 链接放回到该容器中。这样的一个容器称为连接池。
编写一个基本的连接池实现连接复用
步骤:
1、建立一个数据库连接池容器。(因为方便存取,则使用LinkedList集合)
2、初始化一定数量的连接,放入到容器中。
3、等待用户获取连接对象。(该部分要加锁)
|---记得删除容器中对应的对象,放置别人同时获取到同一个对象。
4、提供一个方法,回收用户用完的连接对象。
5、要遵循先入先出的原则。
import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.LinkedList; import java.util.Properties; /** * 一个基本的数据连接池: * 1、初始化时就建立一个容器,来存储一定数量的Connection 对象 * 2、用户通过调用MyDataSource 的getConnection 来获取Connection 对象。 * 3、再通过release 方法来回收Connection 对象,而不是直接关闭连接。 * 4、遵守先进先出的原则。 * * * @author 贺佐安 * */ public class MyDataSource { private static String url = null; private static String password = null; private static String user = null ; private static String DriverClass = null; private static LinkedList<Connection> pool = new LinkedList<Connection>() ; // 注册数据库驱动 static { try { InputStream in = MyDataSource.class.getClassLoader() .getResourceAsStream("db.properties"); Properties prop = new Properties(); prop.load(in); user = prop.getProperty("user"); url = prop.getProperty("url") ; password = prop.getProperty("password") ; DriverClass = prop.getProperty("DriverClass") ; Class.forName(DriverClass) ; } catch (Exception e) { throw new RuntimeException(e) ; } } //初始化建立数据连接池 public MyDataSource () { for(int i = 0 ; i < 10 ; i ++) { try { Connection conn = DriverManager.getConnection(url, user, password) ; pool.add(conn) ; } catch (SQLException e) { e.printStackTrace(); } } } //、从连接池获取连接 public Connection getConnection() throws SQLException { return pool.remove() ; } // 回收连接对象。 public void release(Connection conn) { System.out.println(conn+"被回收"); pool.addLast(conn) ; } public int getLength() { return pool.size() ; } }
这样当我们要使用Connection 连接数据库时,则可以直接使用连接池中Connection 的对象。测试如下:
import java.sql.Connection; import java.sql.SQLException; import org.junit.Test; public class MyDataSourceTest { /** * 获取数据库连接池中的所有连接。 */ @Test public void Test() { MyDataSource mds = new MyDataSource() ; Connection conn = null ; try { for (int i = 0 ; i < 20 ; i ++) { conn = mds.getConnection() ; System.out.println(conn+"被获取;连接池还有:"+mds.getLength()); mds.release(conn) ; } } catch (SQLException e) { e.printStackTrace(); } } }
再运行的时候,可以发现,循环10次后,又再一次获取到了第一次循环的得到的Connection对象。所以,这样可以大大的减轻数据库的压力。上面只是一个简单的数据库连接池,不完美的便是,回收需要调用数据池的release() 方法来进行回收,那么可以不可以直接调用Connection 实例的close 便完成Connection 对象的回收呢?
二、数据源:
> 编写连接池需实现javax.sql.DataSource接口。
> 实现DataSource接口,并实现连接池功能的步骤:
1、在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
2、实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。
利用动态代理和包装设计模式来标准的数据源。
1、包装设计模式实现标准数据源:
这里的用包装设计模式,便是将Connection 接口进行包装。简单总结一下包装设计模式的步骤:
a)定义一个类,实现与被包装类()相同的接口。
|----可以先自己写一个适配器,然后后面继承这个适配器,改写需要改写的方法,提高编程效率。
b)定义一个实例变量,记住被包装类的对象的引用。
c)定义构造方法,转入被包装类的对象。
e)对需要改写的方法,改写。
f)对不需要改写的方法,调用原来被包装类的对应方法。
所以先编写一个类似适配器的类,将Connection 接口的方法都进行实现:
View Code
然后再对Connection 接口进行包装,将close 方法修改掉:
import java.sql.Connection; import java.sql.SQLException; import java.util.LinkedList; /** * 对MyConnectionAdapter 进行包装处理 * @author 贺佐安 * */ public class MyConnectionWrap extends MyConnectionAdapter { private LinkedList<Connection> pool = new LinkedList<Connection>() ; public MyConnectionWrap(Connection conn ,LinkedList<Connection> pool ) { super(conn); this.pool = pool ; } //改写要实现的方法 public void close() throws SQLException { pool.addLast(conn) ; } }
编写标准数据源:
import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.LinkedList; import java.util.ResourceBundle; import javax.sql.DataSource; /** * 编写标准的数据源: * 1、实现DataSource 接口 * 2、获取在实现类的构造方法中批量获取Connection 对象,并将这些Connection 存储 * 在LinkedList 容器中。 * 3、实现getConnection() 方法,调用时返回LinkedList容器的Connection对象给用户。 * @author 贺佐安 * */ public class MyDataSource implements DataSource{ private static String url = null; private static String password = null; private static String user = null ; private static String DriverClass = null; private static LinkedList<Connection> pool = new LinkedList<Connection>() ; // 注册数据库驱动 static { try { ResourceBundle rb = ResourceBundle.getBundle("db") ; url = rb.getString("url") ; password = rb.getString("password") ; user = rb.getString("user") ; DriverClass = rb.getString("DriverClass") ; Class.forName(DriverClass) ; //初始化建立数据连接池 for(int i = 0 ; i < 10 ; i ++) { Connection conn = DriverManager.getConnection(url, user, password) ; pool.add(conn) ; } } catch (Exception e) { throw new RuntimeException(e) ; } } public MyDataSource () { } //、从连接池获取连接:通过包装模式 public synchronized Connection getConnection() throws SQLException { if (pool.size() > 0) { MyConnectionWrap mcw = new MyConnectionWrap(pool.remove(), pool) ; return mcw ; }else { throw new RuntimeException("服务器繁忙!"); } } // 回收连接对象。 public void release(Connection conn) { System.out.println(conn+"被回收"); pool.addLast(conn) ; } public int getLength() { return pool.size() ; } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { } @Override public void setLoginTimeout(int seconds) throws SQLException { } @Override public int getLoginTimeout() throws SQLException { return 0; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } @Override public Connection getConnection(String username, String password) throws SQLException { return null; } }
2、动态代理实现标准数据源:
相对于用包装设计来完成标准数据源,用动态代理则方便许多:
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.ResourceBundle; import javax.sql.DataSource; /** * 编写标准的数据源: * 1、实现DataSource 接口 * 2、获取在实现类的构造方法中批量获取Connection 对象,并将这些Connection 存储 * 在LinkedList 容器中。 * 3、实现getConnection() 方法,调用时返回LinkedList容器的Connection对象给用户。 * @author 贺佐安 * */ public class MyDataSource implements DataSource{ private static String url = null; private static String password = null; private static String user = null ; private static String DriverClass = null; private static LinkedList<Connection> pool = new LinkedList<Connection>() ; // 注册数据库驱动 static { try { ResourceBundle rb = ResourceBundle.getBundle("db") ; url = rb.getString("url") ; password = rb.getString("password") ; user = rb.getString("user") ; DriverClass = rb.getString("DriverClass") ; Class.forName(DriverClass) ; //初始化建立数据连接池 for(int i = 0 ; i < 10 ; i ++) { Connection conn = DriverManager.getConnection(url, user, password) ; pool.add(conn) ; } } catch (Exception e) { throw new RuntimeException(e) ; } } public MyDataSource () { } //、从连接池获取连接:通过动态代理 public Connection getConnection() throws SQLException { if (pool.size() > 0) { final Connection conn = pool.remove() ; Connection proxyCon = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() { //策略设计模式: @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("close".equals(method.getName())){ //谁调用, return pool.add(conn);//当调用close方法时,拦截了,把链接放回池中了 }else{ return method.invoke(conn, args); } } }); return proxyCon ; }else { throw new RuntimeException("服务器繁忙!"); } } public int getLength() { return pool.size() ; } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { } @Override public void setLoginTimeout(int seconds) throws SQLException { } @Override public int getLoginTimeout() throws SQLException { return 0; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } @Override public Connection getConnection(String username, String password) throws SQLException { return null; } }
当然觉得麻烦的则可以直接使用一些开源的数据源如:DBCP、C3P0等。DBCP的原理是用包装设计模式开发的数据源,而C3P0则是动态代理的。
1、DBCP的使用:
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; /** * 创建DBCP 工具类 * @author 贺佐安 * */ public class DbcpUtil { private static DataSource ds = null ; static { try { //读取配置文件 InputStream in = DbcpUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties") ; Properties prop = new Properties() ; prop.load(in) ; //通过BasicDataSourceFactory 的creatDataSurce 方法创建 BasicDataSource 对象。 ds = BasicDataSourceFactory.createDataSource(prop) ; } catch (Exception e) { e.printStackTrace(); } } public static DataSource getDs() { return ds ; } public static Connection getConnection () { try { return ds.getConnection() ; } catch (SQLException e) { throw new RuntimeException() ; } } }
2、C3P0 的使用:
import java.sql.Connection; import java.sql.SQLException; import com.mchange.v2.c3p0.ComboPooledDataSource; /** * C3P0 开源数据源的使用 * @author 贺佐安 * */ public class C3p0Util { private static ComboPooledDataSource cpds = null ; static { cpds = new ComboPooledDataSource() ; } public static Connection getConnection() { try { return cpds.getConnection() ; } catch (SQLException e) { throw new RuntimeException() ; } } }
使用这两个数据源时,直接调用获取到的Connection 连接的close 方法,也是将连接放到pool中去。
三、元数据(DatabaseMetaData)信息的获取
> 元数据:数据库、表、列的定义信息。
> 元数据信息的获取:为了编写JDBC框架使用。
1、数据库本身信息的获取:java.sql.DataBaseMateData java.sql.Connection.getMetaData() ;
DataBaseMateData 实现类的常用方法:
getURL():返回一个String类对象,代表数据库的URL。
getUserName():返回连接当前数据库管理系统的用户名。
getDatabaseProductName():返回数据库的产品名称。
getDatabaseProductVersion():返回数据库的版本号。
getDriverName():返回驱动驱动程序的名称。
getDriverVersion():返回驱动程序的版本号。
isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。
2、ParameterMetaData: 代表PerparedStatment 中的SQL 参数元数据信息: java.sql.ParameterMetaData java.sql.PerparedStatement.getParameterMetaData() ;
ParameterMetaData 实现类常用方法:
getParameterCount() :获得指定参数的个数
getParameterType(int param) :获得指定参数的sql类型(驱动可能不支持)
3、ResultSetMetaData : 代表结果集的源数据信息:相当于SQL 中的 :DESC java.sql.ResultSetMetaData java.sql.ResultSet.getMetaData() ;
java.sql.ResultSetMetaData 接口中常用的方法:
a) getColumnCount() : 获取查询方法有几列。
b) getColumnName(int index) : 获取列名:index从1开始。
c) getColumnType(int index) : 获取列的数据类型。返回的是TYPES 中的常量值。
四、编写自己的JDBC框架:
JDBC框架的基本组成:
1、核心类:
a、定义一个指定javax.sql.DataSource 实例的引用变量,通过构造函数获取指定的实例并给定义的变量。
b、编写SQL运行框架。
DML 语句的编写:
1、通过获取的javax.sql.DataSource 实例,获取Connection 对象。
2、通过ParamenterMeteData 获取数据库元数据。
DQL 语句的编写:
1、通过获取的DataSource 实例,获取Connection 对象。
2、通过ParamenterMeteData、ResultSetMetaData 等获取数据库元数据。
3、用抽象策略设计模式:设计一个ResultSetHandler 接口,作用:将查找出的数据封装到指定的JavaBean中。
|————这里的JavaBean,由用户来指定。
抽象策略模式,用户可以更具具体的功能来扩展成具体策略设计模式。如:查找的一条信息、查找的所有信息。
import java.sql.Connection; import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; /** * 实现JDBC 框架的核心类。 * 在该类中定义了SQL语句完成的方法; * @author 贺佐安 * */ public class MyJdbcFrame { /** * javax.sql.DataSource 实例的引用变量 */ private DataSource ds = null ; /** * 将用户指定的DataSource 指定给系统定义的DataSource 实例的引用变量 * @param ds */ public MyJdbcFrame(DataSource ds ) { this.ds = ds ; } /** * 执行UPDATE、DELETE、INSERT 语句。 * @param sql * @param obj */ public void update(String sql , Object[] obj) { Connection conn = null ; PreparedStatement stmt = null ; try { //获取Connection 对象 conn = ds.getConnection() ; stmt = conn.prepareStatement(sql) ; // 获取ParameterMetaData 元数据对象。 ParameterMetaData pmd = stmt.getParameterMetaData() ; //获取SQL语句中需要设置的参数的个数 int parameterCount = pmd.getParameterCount() ; if (parameterCount > 0) { if (obj == null || obj.length != parameterCount) { throw new MyJdbcFrameException( "parameterCount is error!") ; } //设置参数: for ( int i = 0 ; i < obj.length ; i++) { stmt.setObject(i+1, obj[i]) ; } } //执行语句: stmt.executeUpdate() ; } catch(Exception e ) { throw new MyJdbcFrameException(e.getMessage()) ; } finally { release(stmt, null, conn) ; } } public Object query(String sql , Object[] obj , ResultSetHandler rsh) { Connection conn = null ; PreparedStatement stmt = null ; ResultSet rs = null ; try { //获取Connection 对象 conn = ds.getConnection() ; stmt = conn.prepareStatement(sql) ; // 获取ParameterMetaData 元数据对象。 ParameterMetaData pmd = stmt.getParameterMetaData() ; //获取SQL语句中需要设置的参数的个数 int parameterCount = pmd.getParameterCount() ; if (obj.length != parameterCount) { throw new MyJdbcFrameException( "'" +sql +"' : parameterCount is error!") ; } //设置参数: for ( int i = 0 ; i < obj.length ; i++) { stmt.setObject(i+1, obj[i]) ; } //执行语句: rs = stmt.executeQuery(); return rsh.handler(rs); } catch(Exception e ) { throw new MyJdbcFrameException(e.getMessage()) ; } finally { release(stmt, null, conn) ; } } /** * 释放资源 * @param stmt * @param rs * @param conn */ public static void release(Statement stmt , ResultSet rs , Connection conn) { if(rs != null) { try { rs.close() ; } catch (SQLException e) { e.printStackTrace(); } rs = null ; } if (stmt != null) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt = null ; } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null ; } } }
2、接口:策略模式的接口:ResultSetHandler 。
import java.sql.ResultSet; //抽象策略模式 public interface ResultSetHandler { public Object handler(ResultSet rs) ; }
这里对ResultSetHandler 接口实现一个BeanHandler 实例 :
import java.lang.reflect.Field; import java.sql.ResultSet; import java.sql.ResultSetMetaData; /** * 该类获取ResultSet 结果集中的第一个值,封装到JavaBean中 * @author 贺佐安 * */ public class BeanHandler implements ResultSetHandler { //获取要封装的JavaBean的字节码 private Class clazz ; public BeanHandler (Class clazz) { this.clazz = clazz ; } public Object handler(ResultSet rs) { try { if (rs.next()) { //1、获取结果集的元数据。 ResultSetMetaData rsm = rs.getMetaData() ; //2、创建JavaBean的实例: Object obj = clazz.newInstance() ; //3、将数据封装到JavaBean中。 for (int i = 0 ; i < rsm.getColumnCount() ; i ++) { //获取属性名 String columnName = rsm.getColumnName(i+1) ; //获取属性值 Object value = rs.getObject(i+1) ; Field objField = obj.getClass().getDeclaredField(columnName) ; objField.setAccessible(true) ; objField.set(obj, value) ; } return obj ; } else { return null ; } } catch (Exception e) { throw new RuntimeException(e) ; } } }
3、自定义异常类:继承RuntimeException。如:
public class MyJdbcFrameException extends RuntimeException { public MyJdbcFrameException() { super() ; } public MyJdbcFrameException(String e) { super(e) ; } }
然后就可以将其打包发布,在以后写数据库操作时就可以用自己的JDBC框架了,如果要完成查询多条语句什么的,则要实现ResultSetHandler 接口。来完成更多的功能。
当然,使用DBUtils 则更简单:Apache 组织提供的一个开源JDBC 工具类库。

译者 | 布加迪审校 | 孙淑娟目前,没有用于构建和管理机器学习(ML)应用程序的标准实践。机器学习项目组织得不好,缺乏可重复性,而且从长远来看容易彻底失败。因此,我们需要一套流程来帮助自己在整个机器学习生命周期中保持质量、可持续性、稳健性和成本管理。图1. 机器学习开发生命周期流程使用质量保证方法开发机器学习应用程序的跨行业标准流程(CRISP-ML(Q))是CRISP-DM的升级版,以确保机器学习产品的质量。CRISP-ML(Q)有六个单独的阶段:1. 业务和数据理解2. 数据准备3. 模型

thinkphp是国产框架。ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,是为了简化企业级应用开发和敏捷WEB应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。

Java8-291之后,禁用了TLS1.1,使JDBC无法用SSL连接SqlServer2008怎么办,以下是解决办法修改java.security文件1.找到jre的java.security文件如果是jre,在{JAVA_HOME}/jre/lib/security中,比如????C:\ProgramFiles\Java\jre1.8.0_301\lib\security如果是Eclipse绿色免安装便携版在安装文件夹搜索java.security,比如????xxx\plugins\org

什么是 celery这次我们来介绍一下 Python 的一个第三方模块 celery,那么 celery 是什么呢? celery 是一个灵活且可靠的,处理大量消息的分布式系统,可以在多个节点之间处理某个任务; celery 是一个专注于实时处理的任务队列,支持任务调度; celery 是开源的,有很多的使用者; celery 完全基于 Python 语言编写;所以 celery 本质上就是一个任务调度框架,类似于 Apache 的 airflow,当然 airflow 也是基于 Python

AI就像一个黑匣子,能自己做出决定,但是人们并不清楚其中缘由。建立一个AI模型,输入数据,然后再输出结果,但有一个问题就是我们不能解释AI为何会得出这样的结论。需要了解AI如何得出某个结论背后的原因,而不是仅仅接受一个在没有上下文或解释的情况下输出的结果。可解释性旨在帮助人们理解:如何学习的?学到了什么?针对一个特定输入为什么会做出如此决策?决策是否可靠?在本文中,我将介绍6个用于可解释性的Python框架。SHAPSHapleyAdditiveexplanation(SHapleyAdditi

已安装Microsoft.NET版本4.5.2、4.6或4.6.1的MicrosoftWindows用户如果希望Microsoft将来通过产品更新支持该框架,则必须安装较新版本的Microsoft框架。据微软称,这三个框架都将在2022年4月26日停止支持。支持日期结束后,产品将不会收到“安全修复或技术支持”。大多数家庭设备通过Windows更新保持最新。这些设备已经安装了较新版本的框架,例如.NETFramework4.8。未自动更新的设备可能

近年来,Java语言的应用越来越广泛,而JDBCAPI是Java应用程序中与数据库交互的一种创造性方法,JDBC基于一种名为ODBC的开放数据库连接标准,使得Java应用程序能够连入任何数据库管理系统(DBMS)。其中,MySQL更是一款备受青睐的数据库管理系统。然而,连接MySQL数据库时,开发人员也会遇到一些常见问题,本文旨在介绍JDBCAPI连接M

随着Java的广泛应用,Java程序在连接数据库时经常会出现JDBC错误。JDBC(JavaDatabaseConnectivity)是Java中用于连接数据库的编程接口,因此,JDBC错误是在Java程序与数据库交互时遇到的一种错误。下面将介绍一些最常见的JDBC错误及如何解决和避免它们。ClassNotFoundException这是最常见的JDBC


Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

MantisBT
Mantis ialah alat pengesan kecacatan berasaskan web yang mudah digunakan yang direka untuk membantu dalam pengesanan kecacatan produk. Ia memerlukan PHP, MySQL dan pelayan web. Lihat perkhidmatan demo dan pengehosan kami.

Dreamweaver CS6
Alat pembangunan web visual

DVWA
Damn Vulnerable Web App (DVWA) ialah aplikasi web PHP/MySQL yang sangat terdedah. Matlamat utamanya adalah untuk menjadi bantuan bagi profesional keselamatan untuk menguji kemahiran dan alatan mereka dalam persekitaran undang-undang, untuk membantu pembangun web lebih memahami proses mengamankan aplikasi web, dan untuk membantu guru/pelajar mengajar/belajar dalam persekitaran bilik darjah Aplikasi web keselamatan. Matlamat DVWA adalah untuk mempraktikkan beberapa kelemahan web yang paling biasa melalui antara muka yang mudah dan mudah, dengan pelbagai tahap kesukaran. Sila ambil perhatian bahawa perisian ini
