JDBC笔记一
连接池原理
数据库连接池:1.提前创建好多个连接对象,放到缓存中(集合),客户端用时直接从缓存中获取连接 ,用完连接后一定要还回来。
目的:提高数据库访问效率。
模拟代码:
package com.itheima.pool; import java.sql.Connection;
import java.util.ArrayList;
import java.util.List; import com.itheima.util.JdbcUtil; //模拟连接池的实现原理:帮助理解
public class SimpleConnectionPool {
private static List<Connection> pool = new ArrayList<Connection>();
static{
for(int i=0;i<10;i++){
//com.mysql.jdbc.Connection数据库的那个Connection实现类型
Connection conn = JdbcUtil.getConnection();
pool.add(conn);
}
}
//从池中获取的连接
public synchronized static Connection getConnection(){
if(pool.size()>0){
Connection conn = pool.remove(0);
return conn;
}else{
throw new RuntimeException("服务器真忙");
}
}
//归还连接
public static void release(Connection conn){
pool.add(conn);
}
public static List<Connection> getPool(){
return pool;
}
}
List的Remove方法在删除元素的时候总会保持下标连续。例如,删掉第一个元素的时候,后面的元素会依次往前覆盖。
package com.itheima.util; import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties; public class JdbcUtil { private static String driverClass;
private static String url;
private static String user;
private static String password; static{
try {
ClassLoader cl = JdbcUtil.class.getClassLoader();
InputStream in = cl.getResourceAsStream("dbcfg.properties");
Properties props = new Properties();
props.load(in);
driverClass = props.getProperty("driverClass");
url = props.getProperty("url");
user = props.getProperty("user");
password = props.getProperty("password");
in.close();
} catch (IOException e) {
throw new ExceptionInInitializerError("获取数据库配置文件信息失败");
}
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError("加载驱动失败");
}
} public static Connection getConnection(){
try {
Connection conn = DriverManager.getConnection(url,user,password);
return conn;
} catch (Exception e) {
throw new RuntimeException("链接数据库的url或用户名密码错误,请检查您的配置文件");
}
}
public static void release(ResultSet rs,Statement stmt,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;
}
}
}
import java.sql.Connection; public class Client { public static void main(String[] args) { System.out.println("开始时池中的连接有:");
for(Connection conn:SimpleConnectionPool.getPool()){
System.out.println(conn);
}
System.out.println("---------------");
Connection conn1 = SimpleConnectionPool.getConnection();
System.out.println("取走的连接是:"+conn1);
System.out.println("---------------");
System.out.println("池中的连接有:");
for(Connection conn:SimpleConnectionPool.getPool()){
System.out.println(conn);
}
System.out.println("---------------");
Connection conn2 = SimpleConnectionPool.getConnection();
System.out.println("取走的连接是:"+conn2);
System.out.println("---------------");
System.out.println("池中的连接有:");
for(Connection conn:SimpleConnectionPool.getPool()){
System.out.println(conn);
} System.out.println("开始归还---------------");
SimpleConnectionPool.release(conn1);
System.out.println("池中的连接有:");
for(Connection conn:SimpleConnectionPool.getPool()){
System.out.println(conn);
}
System.out.println("开始归还---------------");
SimpleConnectionPool.release(conn2);
System.out.println("池中的连接有:");
for(Connection conn:SimpleConnectionPool.getPool()){
System.out.println(conn);
}
} }
dbfg.properties:
#driver config for mysql
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day16
user=root
password=sorry
编写标准的数据源
1.Sun定义了一个标准:javax.sql.DataSource接口(数据源)
//一班标准的数据源:一般都带有连接池
public class MyDataSource1 implements DataSource {
private static List<Connection> pool = Collections.synchronizedList(new ArrayList<Connection>());
static{
for(int i=0;i<10;i++){
//com.mysql.jdbc.Connection数据库的那个Connection实现类型
Connection conn = JdbcUtil.getConnection();
pool.add(conn);
}
} public Connection getConnection() throws SQLException {
if(pool.size()>0){
Connection conn = pool.remove(0);//com.mysql.jdbc.Connection
MyConnection1 myconn = new MyConnection1(conn, pool);
return myconn;
}else{
throw new RuntimeException("服务器真忙");
}
}
专题编程难点
背景:义在池中获取连接后不需要使用了不能用close()方法进行处理,导致pool中连接对象就close了,数量就会减小
1.更改已知的某个或者某些方法(不能修改原有的代码,应该拓展)解决方案如下:
1.继承:此处不行
2.利用包装设计模式(装饰设计模式)
3.利用动态代理
2.装饰设计模式:I/O
口诀:a.编写一个类实现与被包装类(com.mysql.jdbc.Connection)相同的接口
b.定义一个变量,引用被包装类的实例
c.定义构造方法,传入被包装类实例的引用
d.对于要改变的方法,编写自己的代码即可
e.对于不需要改变的方法,调用原有的对应方法
配上图解(防蒙):
Jdbcutil:
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties; public class JdbcUtil { private static String driverClass;
private static String url;
private static String user;
private static String password; static{
try {
ClassLoader cl = JdbcUtil.class.getClassLoader();
InputStream in = cl.getResourceAsStream("dbcfg.properties");
Properties props = new Properties();
props.load(in);
driverClass = props.getProperty("driverClass");
url = props.getProperty("url");
user = props.getProperty("user");
password = props.getProperty("password");
in.close();
} catch (IOException e) {
throw new ExceptionInInitializerError("获取数据库配置文件信息失败");
}
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError("加载驱动失败");
}
} public static Connection getConnection(){
try {
Connection conn = DriverManager.getConnection(url,user,password);
return conn;
} catch (Exception e) {
throw new RuntimeException("链接数据库的url或用户名密码错误,请检查您的配置文件");
}
}
public static void release(ResultSet rs,Statement stmt,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;
}
}
}
MyConnection:
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.List;
import java.util.Map;
import java.util.Properties; //a、编写一个类实现与被包装类(com.mysql.jdbc.Connection)相同的接口
//b、定义一个变量,引用被包装类的实例
//c、定义构造方法,传入被包装类实例的引用
//d、对于要改变的方法,编写自己的代码即可
//e、对于不需要改变的方法,调用原有对象的对应方法
public class MyConnection1 implements Connection{//a、编写一个类实现与被包装类(com.mysql.jdbc.Connection)相同的接口 private List<Connection> pool; private Connection oldConnection;//b、定义一个变量,引用被包装类的实例
public MyConnection1(Connection oldConnection,List<Connection> pool){//c、定义构造方法,传入被包装类实例的引用
this.oldConnection = oldConnection;
this.pool = pool;//注入
} //d、对于要改变的方法,编写自己的代码即可
public void close() throws SQLException {
pool.add(oldConnection);
}
//e、对于不需要改变的方法,调用原有对象的对应方法
public <T> T unwrap(Class<T> iface) throws SQLException {
return oldConnection.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return oldConnection.isWrapperFor(iface);
}
@Override
public Statement createStatement() throws SQLException {
return oldConnection.createStatement();
}
//后面省略不写
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public String nativeSQL(String sql) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
// TODO Auto-generated method stub }
@Override
public boolean getAutoCommit() throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void commit() throws SQLException {
// TODO Auto-generated method stub }
@Override
public void rollback() throws SQLException {
// TODO Auto-generated method stub } @Override
public boolean isClosed() throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
// TODO Auto-generated method stub }
@Override
public boolean isReadOnly() throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void setCatalog(String catalog) throws SQLException {
// TODO Auto-generated method stub }
@Override
public String getCatalog() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
// TODO Auto-generated method stub }
@Override
public int getTransactionIsolation() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public SQLWarning getWarnings() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void clearWarnings() throws SQLException {
// TODO Auto-generated method stub }
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
// TODO Auto-generated method stub }
@Override
public void setHoldability(int holdability) throws SQLException {
// TODO Auto-generated method stub }
@Override
public int getHoldability() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Savepoint setSavepoint() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
// TODO Auto-generated method stub }
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
// TODO Auto-generated method stub }
@Override
public Statement createStatement(int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Clob createClob() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Blob createBlob() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public NClob createNClob() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public SQLXML createSQLXML() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isValid(int timeout) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void setClientInfo(String name, String value)
throws SQLClientInfoException {
// TODO Auto-generated method stub }
@Override
public void setClientInfo(Properties properties)
throws SQLClientInfoException {
// TODO Auto-generated method stub }
@Override
public String getClientInfo(String name) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Properties getClientInfo() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Array createArrayOf(String typeName, Object[] elements)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Struct createStruct(String typeName, Object[] attributes)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
}
client:
package com.itheima.ds; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement; public class Client { public static void main(String[] args) {
MyDataSource2 ds = new MyDataSource2();
Connection conn = null;
Statement stmt = null;
try{
conn = ds.getConnection();//MyConnection1从池中获取一个连接
stmt = conn.createStatement();//调用的是MyConnection1中的createStatement(),调用驱动最原始的对应方法
//.....
}catch(Exception e){
e.printStackTrace();
}finally{
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();//关闭连接(com.mysql.jdbc.Connection)
//不要关闭,还回池中(更改已知类的某个方法的默认行为)
} catch (SQLException e) {
e.printStackTrace();
}
}
}
} }
MyDataSource:
package com.itheima.ds; import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import javax.sql.DataSource; import com.itheima.util.JdbcUtil;
//一把标准的数据源:一般都带有连接池
public class MyDataSource1 implements DataSource {
private static List<Connection> pool = Collections.synchronizedList(new ArrayList<Connection>());
static{
for(int i=0;i<10;i++){
//com.mysql.jdbc.Connection数据库的那个Connection实现类型
Connection conn = JdbcUtil.getConnection();
pool.add(conn);
}
} public Connection getConnection() throws SQLException {
if(pool.size()>0){
Connection conn = pool.remove(0);//com.mysql.jdbc.Connection
MyConnection1 myconn = new MyConnection1(conn, pool);
return myconn;
}else{
throw new RuntimeException("服务器真忙");
}
} @Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
} @Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub } @Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub } @Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
} @Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
} @Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
} @Override
public Connection getConnection(String username, String password)
throws SQLException {
// TODO Auto-generated method stub
return null;
} }
默认适配器
背景:义在池中获取
1.适配器类:
//适配器,还是一个包装类
//a、编写一个类实现与被包装类(com.mysql.jdbc.Connection)相同的接口
//b、定义一个变量,引用被包装类的实例
//c、定义构造方法,传入被包装类实例的引用
//d、对于不需要改变的方法,调用原有对象的对应方法
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Map;
import java.util.Properties; //适配器,还是一个包装类
//a、编写一个类实现与被包装类(com.mysql.jdbc.Connection)相同的接口
//b、定义一个变量,引用被包装类的实例
//c、定义构造方法,传入被包装类实例的引用
//d、对于不需要改变的方法,调用原有对象的对应方法
public class ConnectionAdapter implements Connection{
private Connection oldConnection;
public ConnectionAdapter(Connection oldConnection){
this.oldConnection = oldConnection;
}
public <T> T unwrap(Class<T> iface) throws SQLException {
return oldConnection.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return oldConnection.isWrapperFor(iface);
}
//省略
@Override
public Statement createStatement() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public String nativeSQL(String sql) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
// TODO Auto-generated method stub }
@Override
public boolean getAutoCommit() throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void commit() throws SQLException {
// TODO Auto-generated method stub }
@Override
public void rollback() throws SQLException {
// TODO Auto-generated method stub }
@Override
public void close() throws SQLException {
// TODO Auto-generated method stub }
@Override
public boolean isClosed() throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
// TODO Auto-generated method stub }
@Override
public boolean isReadOnly() throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void setCatalog(String catalog) throws SQLException {
// TODO Auto-generated method stub }
@Override
public String getCatalog() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
// TODO Auto-generated method stub }
@Override
public int getTransactionIsolation() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public SQLWarning getWarnings() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void clearWarnings() throws SQLException {
// TODO Auto-generated method stub }
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
// TODO Auto-generated method stub }
@Override
public void setHoldability(int holdability) throws SQLException {
// TODO Auto-generated method stub }
@Override
public int getHoldability() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Savepoint setSavepoint() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
// TODO Auto-generated method stub }
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
// TODO Auto-generated method stub }
@Override
public Statement createStatement(int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Clob createClob() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Blob createBlob() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public NClob createNClob() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public SQLXML createSQLXML() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isValid(int timeout) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void setClientInfo(String name, String value)
throws SQLClientInfoException {
// TODO Auto-generated method stub }
@Override
public void setClientInfo(Properties properties)
throws SQLClientInfoException {
// TODO Auto-generated method stub }
@Override
public String getClientInfo(String name) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Properties getClientInfo() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Array createArrayOf(String typeName, Object[] elements)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Struct createStruct(String typeName, Object[] attributes)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
}
2.继承包装类:
//a、编写一个类继承已经实现了被包装类(com.mysql.jdbc.Connection)相同的接口的类
//b、定义一个变量,引用被包装类的实例
//c、定义构造方法,传入被包装类实例的引用
//d、对于要改变的方法,覆盖即可
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List; //a、编写一个类继承已经实现了被包装类(com.mysql.jdbc.Connection)相同的接口的类
//b、定义一个变量,引用被包装类的实例
//c、定义构造方法,传入被包装类实例的引用
//d、对于要改变的方法,覆盖即可
public class MyConnection2 extends ConnectionAdapter{
private Connection oldConnection;
private List<Connection> pool;
public MyConnection2(Connection oldConnection,List<Connection> pool){
super(oldConnection);
this.oldConnection = oldConnection;
this.pool = pool;
}
public void close() throws SQLException {
pool.add(oldConnection);
} }
动态代理:
示例代码
1.接口:
package com.itheima.proxy1; public interface Human {
void sing(float money);
void dance(float money);
void eat();
}
2. 实现接口类:
public class SpringBrother implements Human { public void sing(float money) {
System.out.println("拿到钱:"+money+"开唱");
} public void dance(float money) {
System.out.println("拿到钱:"+money+"开跳");
} public void eat() {
System.out.println("狼吞虎咽的吃");
} }
实现接口类
3.代理类:
package com.itheima.proxy1;
//静态代理:代理类写好了
public class ProxyMan implements Human{
private Human oldHuman;
public ProxyMan(Human oldHuman){
this.oldHuman = oldHuman;
}
public void sing(float money) {
if(money<10000)
throw new RuntimeException("不干");
oldHuman.sing(money/2);
} public void dance(float money) {
if(money<20000)
throw new RuntimeException("不干");
oldHuman.dance(money/2);
}
public void eat() {
oldHuman.eat();
} }
代理类(静态代理)
4.动态代理及测试:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//如果被代理对象没有实现任何接口,Proxy代理不能用。基于接口的动态代理
public class Boss { public static void main(String[] args) {
final Human h = new SpringBrother();//被代理对象
// Human proxyMan = new ProxyMan(h);//静态代理
//动态代理
/*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
返回值:代理对象的引用
参数:
loader:代理对象用的类加载器。固定写法:和被代理对象一致
interfaces:代理对象实现的接口。固定写法:代理对象实现什么接口它就实现什么接口(保持代理对象和被代理对象有相同的行为)
h:如何代理,怎么代理,代理什么?策略设计模式(InvocationHandler是一个接口)
*/
Human proxyMan = (Human)Proxy.newProxyInstance(h.getClass().getClassLoader(),
h.getClass().getInterfaces(), new InvocationHandler() {
//如何代理啊:具体策略
//调用代理对象的任何方法,都会经过该方法
/*
* 返回值:当前方法的返回值
* proxy:代理对象的引用
* method:当前调用的代理的哪个方法
* args:当前方法需要的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("sing".equals(method.getName())){
float money = (Float)args[0];
if(money>10000){
return method.invoke(h, money/2);
}
}else if("dance".equals(method.getName())){
float money = (Float)args[0];
if(money>20000){
return method.invoke(h, money/2);
}
}else{
return method.invoke(h, args);
}
return null;
}
});
proxyMan.sing(100000);
proxyMan.dance(200000);
proxyMan.eat();
} }
2.基于动态代理更改驱动close()方法:
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.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import javax.sql.DataSource; import com.itheima.util.JdbcUtil;
//一把标准的数据源:一般都带有连接池。使用动态代理来做
public class MyDataSource2 implements DataSource {
private static List<Connection> pool = Collections.synchronizedList(new ArrayList<Connection>());
static{
for(int i=0;i<10;i++){
//com.mysql.jdbc.Connection数据库的那个Connection实现类型
Connection conn = JdbcUtil.getConnection();
pool.add(conn);
}
} public Connection getConnection() throws SQLException {
if(pool.size()>0){
final Connection conn = pool.remove(0);//com.mysql.jdbc.Connection
return (Connection)Proxy.newProxyInstance(conn.getClass().getClassLoader(),
conn.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("close".equals(method.getName())){
return pool.add(conn);
}else{
return method.invoke(conn, args);
}
}
});
}else{
throw new RuntimeException("服务器真忙");
}
} @Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
} @Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub } @Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub } @Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
} @Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
} @Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
} @Override
public Connection getConnection(String username, String password)
throws SQLException {
// TODO Auto-generated method stub
return null;
} }
示例代码
3.CGLIB生成代理 对象:
(代理类是被代理的子类)
被代理类要求:
a.必须是public
b.必须不是final
1.导入架包:cglib-nodep-2.1_3.jar
2:被代理类:
//没有实现任何接口。domain包中的普通的JavaBean,有时并没有实现任何接口,需要他的代理类怎么办?
//借助第三方的开发:CGLIB
public class SpringBrother{ public void sing(float money) {
System.out.println("拿到钱:"+money+"开唱");
} public void dance(float money) {
System.out.println("拿到钱:"+money+"开跳");
} public void eat() {
System.out.println("狼吞虎咽的吃");
} }
3.代理:
import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
//如果被代理对象没有实现任何接口,Proxy代理不能用。基于接口的动态代理
//CGLIB:基于子类的动态代理
public class Boss { public static void main(String[] args) {
final SpringBrother h = new SpringBrother();//被代理对象
/*
* Enhancer.create(type, callback)
* type:代理类的父类型
* callback:如何代理
*/
SpringBrother proxyMan = (SpringBrother)Enhancer.create(SpringBrother.class, new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("sing".equals(method.getName())){
float money = (Float)args[0];
if(money>10000){
return method.invoke(h, money/2);
}
}else if("dance".equals(method.getName())){
float money = (Float)args[0];
if(money>20000){
return method.invoke(h, money/2);
}
}else{
return method.invoke(h, args);
}
return null;
} });
proxyMan.sing(100000);
proxyMan.dance(200000);
proxyMan.eat();
} }
AOP面向切向思想:
之前写了一篇关于IOC的博客——《Spring容器IOC解析及简单实现》,今天再来聊聊AOP。大家都知道Spring的两大特性是IOC和AOP。
IOC负责将对象动态的注入到容器,从而达到一种需要谁就注入谁,什么时候需要就什么时候注入的效果,可谓是招之则来,挥之则去。想想都觉得爽,如果现实生活中也有这本事那就爽歪歪了,至于有多爽,各位自己脑补吧;而AOP呢,它实现的就是容器的另一大好处了,就是可以让容器中的对象都享有容器中的公共服务。那么容器是怎么做到的呢?它怎么就能让在它里面的对象自动拥有它提供的公共性服务呢?答案就是我们今天要讨论的内容——动态代理。
动态代理其实并不是什么新鲜的东西,学过设计模式的人都应该知道代理模式,代理模式是一种静态代理,而动态代理就是利用反射和动态编译将代理模式变成动态的。原理跟动态注入一样,代理模式在编译的时候就已经确定代理类将要代理谁,而动态代理在运行的时候才知道自己要代理谁。
Spring的动态代理有两种:一是JDK的动态代理;另一个是cglib动态代理(通过修改字节码来实现代理)。今天咱们主要讨论JDK动态代理的方式。JDK的代理方式主要就是通过反射跟动态编译来实现的,下面咱们就通过代码来看看它具体是怎么实现的。
假设我们要对下面这个用户管理进行代理:
//用户管理接口
package com.tgb.proxy; public interface UserMgr {
void addUser();
void delUser();
} //用户管理的实现
package com.tgb.proxy; public class UserMgrImpl implements UserMgr { @Override
public void addUser() {
System.out.println("添加用户.....");
} @Override
public void delUser() {
System.out.println("删除用户.....");
} }
按照代理模式的实现方式,肯定是用一个代理类,让它也实现UserMgr接口,然后在其内部声明一个UserMgrImpl,然后分别调用addUser和delUser方法,并在调用前后加上我们需要的其他操作。但是这样很显然都是写死的,我们怎么做到动态呢?别急,接着看。 我们知道,要实现代理,那么我们的代理类跟被代理类都要实现同一接口,但是动态代理的话我们根本不知道我们将要代理谁,也就不知道我们要实现哪个接口,那么要怎么办呢?我们只有知道要代理谁以后,才能给出相应的代理类,那么我们何不等知道要代理谁以后再去生成一个代理类呢?想到这里,我们好像找到了解决的办法,就是动态生成代理类!
这时候我们亲爱的反射又有了用武之地,我们可以写一个方法来接收被代理类,这样我们就可以通过反射知道它的一切信息——包括它的类型、它的方法等等(如果你不知道怎么得到,请先去看看我写的反射的博客《反射一》《反射二》)。
JDK动态代理的两个核心分别是InvocationHandler和Proxy,下面我们就用简单的代码来模拟一下它们是怎么实现的:
InvocationHandler接口:
package com.tgb.proxy; import java.lang.reflect.Method; public interface InvocationHandler {
public void invoke(Object o, Method m);
}
实现动态代理的关键部分,通过Proxy动态生成我们具体的代理类:
package com.tgb.proxy; import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask; public class Proxy {
/**
*
* @param infce 被代理类的接口
* @param h 代理类
* @return
* @throws Exception
*/
public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {
String methodStr = "";
String rt = "\r\n"; //利用反射得到infce的所有方法,并重新组装
Method[] methods = infce.getMethods();
for(Method m : methods) {
methodStr += " @Override" + rt +
" public "+m.getReturnType()+" " + m.getName() + "() {" + rt +
" try {" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
" h.invoke(this, md);" + rt +
" }catch(Exception e) {e.printStackTrace();}" + rt +
" }" + rt ;
} //生成Java源文件
String srcCode =
"package com.tgb.proxy;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class $Proxy1 implements " + infce.getName() + "{" + rt +
" public $Proxy1(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
" com.tgb.proxy.InvocationHandler h;" + rt +
methodStr + rt +
"}";
String fileName =
"d:/src/com/tgb/proxy/$Proxy1.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(srcCode);
fw.flush();
fw.close(); //将Java文件编译成class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(fileName);
CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close(); //加载到内存,并实例化
URL[] urls = new URL[] {new URL("file:/" + "d:/src/")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.tgb.proxy.$Proxy1"); Constructor ctr = c.getConstructor(InvocationHandler.class);
Object m = ctr.newInstance(h); return m;
} }
这个类的主要功能就是,根据被代理对象的信息,动态组装一个代理类,生成$Proxy1.java文件,然后将其编译成$Proxy1.class。这样我们就可以在运行的时候,根据我们具体的被代理对象生成我们想要的代理类了。这样一来,我们就不需要提前知道我们要代理谁。也就是说,你想代理谁,想要什么样的代理,我们就给你生成一个什么样的代理类。
然后,在客户端我们就可以随意的进行代理了。
package com.tgb.proxy; public class Client {
public static void main(String[] args) throws Exception {
UserMgr mgr = new UserMgrImpl(); //为用户管理添加事务处理
InvocationHandler h = new TransactionHandler(mgr);
UserMgr u = (UserMgr)Proxy.newProxyInstance(UserMgr.class,h); //为用户管理添加显示方法执行时间的功能
TimeHandler h2 = new TimeHandler(u);
u = (UserMgr)Proxy.newProxyInstance(UserMgr.class,h2); u.addUser();
System.out.println("\r\n==========华丽的分割线==========\r\n");
u.delUser();
}
}
运行结果:
开始时间:2014年-07月-15日 15时:48分:54秒
开启事务.....
添加用户.....
提交事务.....
结束时间:2014年-07月-15日 15时:48分:57秒
耗时:3秒 ==========华丽的分割线========== 开始时间:2014年-07月-15日 15时:48分:57秒
开启事务.....
删除用户.....
提交事务.....
结束时间:2014年-07月-15日 15时:49分:00秒
耗时:3秒
这里我写了两个代理的功能,一个是事务处理,一个是显示方法执行时间的代理,当然都是非常简单的写法,只是为了说明这个原理。当然,我们可以想Spring那样将这些AOP写到配置文件,因为之前那篇已经写了怎么通过配置文件注入了,这里就不重复贴了。 到这里,你可能会有一个疑问:你上面说,只要放到容器里的对象,都会有容器的公共服务,我怎么没看出来呢?好,那我们就继续看一下我们的代理功能:
事务处理:
package com.tgb.proxy; import java.lang.reflect.Method; public class TransactionHandler implements InvocationHandler { private Object target; public TransactionHandler(Object target) {
super();
this.target = target;
} @Override
public void invoke(Object o, Method m) {
System.out.println("开启事务.....");
try {
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("提交事务.....");
} }
从代码中不难看出,我们代理的功能里没有涉及到任何被代理对象的具体信息,这样有什么好处呢?这样的好处就是将代理要做的事情跟被代理的对象完全分开,这样一来我们就可以在代理和被代理之间随意的进行组合了。也就是说同一个功能我们只需要一个。同样的功能只有一个,那么这个功能不就是公共的功能吗?不管容器中有多少给对象,都可以享受容器提供的服务了。这就是容器的好处。
不知道我讲的够不够清楚,欢迎大家积极交流、讨论。
转载
开源数据源的使用(实际开发中用):
一:DBCP
a、简介:DBCP DataBase Connection Pool
b、Apache组织搞的开源的数据源(DataSource)实现
c、使用:
1、拷贝jar包:数据库的驱动jar;commons-dbcp-1.4.jar;commons-pool-1.5.6.jar
2、在构建路径的顶层,建立一个配置文件,内容如下:dbcpconfig.properties:
3、编写工具类:
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day17
username=root
password=sorry #<!-- 初始化连接 -->
initialSize=10 #最大连接数量
maxActive=50 #<!-- 最大空闲连接 -->
maxIdle=20 #<!-- 最小空闲连接 -->
minIdle=5 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8 #指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true #driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly= #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=REPEATABLE_READ
dbcpconfig.properties
package com.Util; import java.sql.Connection;
import java.sql.SQLException; import org.junit.Test; public class Client { public Client() {
// TODO Auto-generated constructor stub
}
@Test
public void test1(){
Connection conn=DbcpUtil.getConnection();
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
Client
二:C3p0
a.简介:非常优秀的开源的数据
b,使用方法:
1、拷贝jar包:c3p0-0.9.1.2.jar;c3p0-0.9.1.2-jdk1.3.jar(JDK版本低);c3p0-oracle-thin-extras-0.9.1.2.jar(为oracle服务)
2、编写配置文件:参考发行包中的文档
3、编写工具类:
4.3利用Tomcat管理数据源
1、JavaWeb服务器一般都提供数据源的实现,一般只需要做一些简单的配置即可。
2、配置Tomcat的数据源
Tomcat一旦配置了数据源,在启动时利用JNDI技术(JavaEE技术之一),把数据源放在JNDI容器中。
JNDI:Java Naming and Directory Interface(Java命名和目录接口)
简单理解:JNDI是一个Map<String,Object>结构的容器,类似window系统的注册表。
key:String |
value:Object |
HEY_SOFTWARE/Microsoft/Ports |
|
HEY_MATHINCES/Microsoft/Ports |
|
java:/comp/env/jdbc/day17 |
DataSource对象 |
3、配置步骤:
a、拷贝数据库驱动jar到Tomcat\lib目录中
b、在应用的META-INF目录下配置一个名称为context.xml的配置文件
c、从JNDI容器中取出创建好的数据源
使用JNDI的API来取:(javax.naming.*)
数据库元信息的获取(编写JDBC框架)
1、什么数据库元信息
指数据库、表等的定义信息
2、元信息:
l 数据库的元信息:DatabaseMetaData dmd = conn.getMetaData();//数据库的元信息。全部都是getter方法
l 参数元信息:执行的SQL语句中的占位符元信息
l 结果集元信息:
编写属于自己的JDBC框架
1、目的:简化代码,提高开发效率
策略设计模式
JDBC笔记一的更多相关文章
- 【JDBC 笔记】
JDBC 笔记 作者:晨钟暮鼓c个人微信公众号:程序猿的月光宝盒 对应pdf版:https://download.csdn.net/download/qq_22430159/10754554 没有积分 ...
- JDBC笔记总结[申明:来源于网络]
JDBC笔记总结[申明:来源于网络] 地址:http://blog.csdn.net/Summer_YuXia/article/details/53676386?ref=myread
- JDBC笔记
简介 JDBC是Java规定的访问数据库的API,目前主流的数据库都支持JDBC.使用JDBC访问不同的数据库时需要安装不同的驱动. JDBC定义了数据库的链接,SQL语句的执行以及查询结果集的遍历等 ...
- spring jdbc 笔记3
spring JDBC 加入对commons-dbcp spring-jdbc spring-tx的依赖 1.数据源的配置 获取数据源在spring中的Bean管理默认已经是单例模式 关闭数据源d ...
- jdbc笔记(二) 使用PreparedStatement对单表的CRUD操作
首先声明,本文只给出代码,并不是做教程用,如有不便之处,还请各位见谅. PreparedStatement相较于Statement,概括来说,共有三个优势: 1. 代码的可读性和易维护性:Prepar ...
- jdbc笔记(一) 使用Statement对单表的CRUD操作
jdbc连接mysql并执行简单的CRUD的步骤: 1.注册驱动(需要抛出/捕获异常) Class.forName("com.mysql.jdbc.Driver"); 2.建立连接 ...
- jdbc笔记2
private static String driver; private static String url; private static String username; private sta ...
- JDBC 笔记3 通过PreparedStatement 对数据库进行增删改查 (转载)
之前MVC时一直用它,学了框架后就没怎么用了.这里转载一位同学的博客,以后可能也会用到的. 转自:https://www.cnblogs.com/zilong882008/archive/2011/1 ...
- JDBC的简单笔记
JDBC笔记: JDBC:java database connectivity SUN公司提供的一套操作数据库的标准规范. JDBC与数据库驱动的关系:接口与实现的关系. JDBC规范(掌握四个核心对 ...
随机推荐
- 吴裕雄 python 机器学习——多项式贝叶斯分类器MultinomialNB模型
import numpy as np import matplotlib.pyplot as plt from sklearn import datasets,naive_bayes from skl ...
- 微服务介绍和springCloud组件
微服务架构模式是:将整个web服务 组织成一系列小的web 服务,这些小的web服务可以进行独立的编译和部署,并通过各自暴露的API接口 进行相互通信,他们相互协作,作为一个整体,为客户提供服务功 ...
- pip install 安装指定版本的包
pip install 安装指定版本的包 要用 pip 安装指定版本的 Python 包,只需通过 == 操作符 指定 pip install robotframework==2.8.7 将安装r ...
- LINUX 怎么实现root和普通用户的切换及怎么更改root密码
在linux系统中执行什么命令后可以使$变为#? 先说下$和#在linux系统终端(命令行)中通常代表的什么:$打头的表示这不是在root用户(管理员用户)下执行的命令#打头的和前者相反,即r ...
- Ubuntu16.04+Ros+Usb_Cam ORB SLAM2
转载自:https://www.jianshu.com/p/dbf39b9e4617亲测可用 1.其中编译ORB_SLAM2的 ./build.sh 和 ./build_ros.sh之前需要修改文 ...
- acm数论之旅--数论四大定理
ACM数论之旅5---数论四大定理(你怕不怕(☆゚∀゚)老实告诉我) (本篇无证明,想要证明的去找度娘)o(*≧▽≦)ツ ----------数论四大定理--------- 数论四大定理: 1.威 ...
- 2、json教程
JSON(JavaScript)对象表示法是一种轻量级的基于文本的开放标准, 被设计用于可读的数据交换, 约定使用JSON的程序包括 C C++ Java Python Perl 总结 JSO ...
- Catalyst 6500/6000 Switches ARP or CAM Table
译:https://www.cisco.com/c/en/us/support/docs/switches/catalyst-6500-series-switches/71079-arp-cam-ta ...
- 数据分析--excel
excel 的使用 1.excel基础 1.数据类型 数字类型 字符类型 注意: 1.普通文本:默认作对齐,左上方没有小绿点,数字默认又对齐 2.数字存储为文本类型,美容默认为左对齐,左上方有小绿点 ...
- 【PAT甲级】1079 Total Sales of Supply Chain (25 分)
题意: 输入一个正整数N(<=1e5),表示共有N个结点,接着输入两个浮点数分别表示商品的进货价和每经过一层会增加的价格百分比.接着输入N行每行包括一个非负整数X,如果X为0则表明该结点为叶子结 ...