JDBC学习笔记(三)
获取数据库的元信息metadata,里面有数据库特性的描述信息,如是否支持事务,是否支持批处理等。
Connection conn = DriverManager.getConnection(url, userName,passwrod);
DatabaseMetaData md = conn,getMetaData();
System.out.println(md.supportTransactions());
还可以获取参数的metadata:
PreparedStatement ps = conn.prepareStatement(sql);
ParamterMetaData pm = ps.getParamterMetaData();
还可以获取返回的结果集中的metadata,用于将结果封装为需求的对象如Map,List等:
ResultSet rs = ps.executeQuery();
ResultSetMetaData meta = rs.getMetaData();
class的无参数的newInstance方法要求类有一个无参数的构造方法。
Constructor con = class.getConstructor(String.class); //取得对象的参数为String的构造方法,参数是可变长度的数组
Object obj = con.newInstance("test"); //参数是可变长度的数组
Method [] ms = object.getClass.getDeclaredMethods(); //找到类中的所有方法,包括私有方法,但不包括父类方法
Method [] ms = object.getClass.getMethods(); //找到类及父类方法中的所有方法,但不包括私有方法
Java类库中有三个类直接支持代理模式:Proxy,InvocationHandler和Method。
下面是在List加上代理,在添加元素的前后打印一些信息。
public class VectorProxy implements InvocationHandler{
private Object proxyobj;
public VectorProxy(Object obj){
proxyobj = obj;
}
public static Object factory(Object obj){
Class cls = obj.getClass();
return Proxy.newProxyInstance( cls.getClassLoader(),
cls.getInterfaces(),
new VectorProxy(obj) );
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
System.out.println("before calling " + method);
if (args != null){
for (int i=0; i<args.length; i++){
System.out.println(args[i] + "");
}
}
Object o = method.invoke(proxyobj, args);
System.out.println("after calling " + method);
return o;
}
public static void main(String[] args){
List v = null;
v = (List) factory(new Vector(10));
v.add("New");
v.add("York");
}
}
打印出的信息如下:
before calling public abstract boolean java.util.List.add(java.lang.Object) New after calling public abstract boolean java.util.List.add(java.lang.Object) before calling public abstract boolean java.util.List.add(java.lang.Object) York after calling public abstract boolean java.util.List.add(java.lang.Object)
代理模式需要一个原始类的实例,InvocationHandler中invoke方法实际调用的是原始类的实例,需要仿照着一个实例在内存中动态地生成字节码。因为方法除非是静态方法,否则都是要和实例来绑定使用的。
利用代理模式,如果希望java.sql.Connection的close方法不是去关掉真正的数据库连接而是将连接放回到连接池中,可以使用下面的代码:
public class ConnectionProxy implements InvocationHandler{
private java.sql.Connection wrappedConnection;
private java.sql.Connection realConn;
private DataSource dataSource;
public ConnectionProxy(DataSource dataSource ){
this.dataSource = dataSource;
}
public static java.sql.Connection bind(java.sql.Connection conn){
this.realConn = conn;
Class cls = conn.getClass();
wrappedConnection = Proxy.newProxyInstance( cls.getClassLoader(),
/*cls.getInterfaces()*/new class[]{java.sql.Connection.class},this); //这里需要继承自java.sql.Connection接口,否则创建出的连接在连接池添加,删除时有问题
return wrappedConnection;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
if (method.getName().equals("close")){
this.dataSource.connectionsPool.addLast(wrappedConnection);Q
}
Object o = method.invokerealConn;args);
return o;
}
}
DataSource类中产生connection时就换为ConnectionProxy即可。
private Connection createConnection(){
java.sql.Connection conn = DriverManager.getConnection(url,user,password);
ConnectionProxy proxy = new ConnectionProxy(this);
return proxy.bind(conn );
}
通过数据源DataSource中的连接池获取的Connection都是包装后的Connection,已经修改了close方法,不是简单的关闭连接,而是要再放回连接池中。
连接池一般会要求提供一个配置文件,基本的配置项包括:初始连接数,最大连接数,最大、最小空闲连接数等。下面的是一个Durid数据库连接池的配置文件:
<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_username}" />
<property name="password" value="${jdbc_password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="0" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="20" />
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="20" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="0" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
<!-- <property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="33" /> -->
<property name="validationQuery" value="${validationQuery}" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="25200000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 监控数据库 -->
<!-- <property name="filters" value="stat" /> -->
<property name="filters" value="mergeStat" />
</bean>
上面将配置信息直接写到程序中的方法并不好,可以写成配置文件druiddb.xml,去从配置文件中来读取配置。
driverClassName = com.mysql.jdbc.Driver
url =com.mysql.jdbc.Driver
uer = root
password = OSSDB123
initialSize =5
再修改上面的DruidManager类,使之从配置文件中加载参数:
Properties p = new Properties();
InputStream is = DuridManager,class.getClassLoader().loadResourceAsStream("duriddb.xml");
p.load(is);
dataSource = new DruidDataSource(p);
连接池的connection也是包装后的connection,需要改写close方法。
JDBC学习笔记(三)的更多相关文章
- JDBC 学习笔记(十一)—— JDBC 的事务支持
1. 事务 在关系型数据库中,有一个很重要的概念,叫做事务(Transaction).它具有 ACID 四个特性: A(Atomicity):原子性,一个事务是一个不可分割的工作单位,事务中包括的诸操 ...
- JDBC 学习笔记(十)—— 使用 JDBC 搭建一个简易的 ORM 框架
1. 数据映射 当我们获取到 ResultSet 之后,显然这个不是我们想要的数据结构. 数据库中的每一个表,在 Java 代码中,一定会有一个类与之对应,例如: package com.gerrar ...
- JDBC学习笔记二
JDBC学习笔记二 4.execute()方法执行SQL语句 execute几乎可以执行任何SQL语句,当execute执行过SQL语句之后会返回一个布尔类型的值,代表是否返回了ResultSet对象 ...
- JDBC学习笔记一
JDBC学习笔记一 JDBC全称 Java Database Connectivity,即数据库连接,它是一种可以执行SQL语句的Java API. ODBC全称 Open Database Conn ...
- Oracle学习笔记三 SQL命令
SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)
- [Firefly引擎][学习笔记三][已完结]所需模块封装
原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读: 笔记三主要就是各个模块的封装了,这里贴 ...
- JSP学习笔记(三):简单的Tomcat Web服务器
注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...
- java之jvm学习笔记三(Class文件检验器)
java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...
- VSTO学习笔记(三) 开发Office 2010 64位COM加载项
原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...
随机推荐
- BZOJ 1061: [Noi2008]志愿者招募【单纯形裸题】
1061: [Noi2008]志愿者招募 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 4813 Solved: 2877[Submit][Stat ...
- 除了四大传统OA软件商,国内还有这些优秀的OA协同产品
国内OA 软件市场经过多年的发展,在产品.应用.服务方面都已相对成熟,也出现了众多优秀的OA软件品牌. 据中国软件协会2017年公布的数据显示:泛微OA.致远OA.华天动力OA.蓝凌OA的销售仍稳居O ...
- 将本地项目或代码上传到别人GitHub(码云)的远程分支上
今天碰到了这样一个问题,折腾了半天,就是将自己本地代码上传到人家的远程分支上. 首先要做的就是先将人家的项目克隆到本地:git clone + 项目地址 然后进入项目目录:cd + 已克隆好的项目目录 ...
- 如何看apache的版本号
在服务器上输入httpd -v就可以看到 在服务器上运行apachectl -v命令即可 Server version: Apache/2.2.3 Server built: Feb 25 2012 ...
- 优化表单数据的JS校验
在平常的web开发中,我经常需要在客户端对表单的数据进行验证.比如,我们验证表单输入的内容不为空: ? <form action="" method="post&q ...
- Ubuntu问题:E45: 'readonly' option is set (add ! to override)错误解决
问题描述:E45: 'readonly' option is set (add ! to override) 问题分析:该错误为当前用户没有权限对文件作修改 问题解决: 输入 :w !sudo tee ...
- div流加载
var hasNext=true;//触发开关,防止多次调用事件 var nScrollHight = 0; //滚动距离总长(注意不是滚动条的长度) var nScrollTop = 0; //滚动 ...
- es6重点笔记:数值,函数和数组
本篇全是重点,捡常用的怼,数值的扩展比较少,所以和函数放一起: 一,数值 1,Number.EPSILON:用来检测浮点数的计算,如果误差小于这个,就无误 2,Math.trunc():取整,去除小数 ...
- F5负载均衡虚拟服务器配置FTP端口访问不了
F5配置ip映射到地址池ftp服务,访问报错:FTP出现"数据 Socket 错误: 连接被拒""ftp 列表错误"解决办法 1条回答 FTP的vs类型需要选择 ...
- mybatis-自定义缓存-redis二级缓存
在mybatis一级缓存二级缓存中已经介绍过了二级缓存的大致原理.下面我们用redis来实现一下二级缓存.环境是springmvc+mybatis+redis 步骤一.引入redis相关的maven依 ...