DbUtils 和 DBCP一般需要一起使用。
在ORALCE环境下运行。
首先创建一张表,创建表语句。
create table tb_user(USERNAME varchar2(64) ,PASSWORD varchar2(64));
首先来看一段程序运行后的异常:
Exception in thread "main"java.lang.AbstractMethodError
atorg.apache.commons.dbcp.DelegatingPreparedStatement.getParameterMetaData(DelegatingPreparedStatement.java:221)
atorg.apache.commons.dbcp.DelegatingPreparedStatement.getParameterMetaData(DelegatingPreparedStatement.java:221)
atorg.apache.commons.dbutils.AbstractQueryRunner.fillStatement(AbstractQueryRunner.java:225)
atorg.apache.commons.dbutils.QueryRunner.update(QueryRunner.java:487)
atorg.apache.commons.dbutils.QueryRunner.update(QueryRunner.java:377)
attest.ffm83.commons.dbutils.QueryRunnerError.test_insert(QueryRunnerError.java:72)
attest.ffm83.commons.dbutils.QueryRunnerError.main(QueryRunnerError.java:62)
在网上查了下,这种类似的异常很多,但是解决办法千奇百怪,这种代码是下面类似的代码产生的。
Commons DbUtils中QueryRunner总是出错的源代码:
package test.ffm83.commons.dbutils;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
/**
* 通过commons dbUtils进行数据库的简单访问和实用,同时暴露一些异常
* dbUtils1.6,Oracle驱动:class12
* @author范芳铭
*/
public
classQueryRunnerError {
private
static BasicDataSource dataSource =
null;
privateQueryRunner
runner= null;
publicQueryRunnerError() {
init();
runner = new QueryRunner(dataSource);
}
public
static void init() {
if (dataSource !=
null) {
try {
dataSource.close();
}catch(Exception e) {
e.printStackTrace();
}
dataSource =
null;
}
try {
Propertiesp = newProperties();
p.setProperty("driverClassName","oracle.jdbc.driver.OracleDriver");
p.setProperty("url",
"jdbc:oracle:thin:@192.168.1.1:1521:fanfangming");
p.setProperty("password","ffm");
p.setProperty("username","ffm");
p.setProperty("maxActive","2");
p.setProperty("maxIdle","1");
p.setProperty("maxWait","100");
dataSource =(BasicDataSource) BasicDataSourceFactory
.createDataSource(p);
}catch(Exception e) {
e.printStackTrace();
}
}
public
static synchronized ConnectiongetConnection()
throwsSQLException {
if (dataSource ==
null) {
init();
}
Connectionconn = null;
if (dataSource !=
null) {
conn= dataSource.getConnection();
}
return conn;
}
public
static void main(String[] args)
throws SQLException {
test_insert();
}
public
static void test_insert()
throws SQLException {
System.out.println("-------------test_insert()-------------");
//创建连接
Connection conn = getConnection();
//创建SQL执行工具
QueryRunner qRunner =
new QueryRunner();
//执行SQL插入
int n =
qRunner.update(conn,
"insert into tb_user(username,password) values(‘范芳铭‘,‘ffm‘)");
System.out.println("成功插入" + n +
"条数据!");
//关闭数据库连接
DbUtils.closeQuietly(conn);
}
public
class tb_user{
private String
username ;
private String
password;
public tb_user(String username,String password){
this.username = username;
this.password = password;
}
public String getUsername() {
return
username;
}
public
void setUsername(Stringusername) {
this.username = username;
}
public String getPassword() {
return
password;
}
public
void setPassword(Stringpassword) {
this.password = password;
}
}
}
这段代码就是一个相对比较常见的代码。但是这种代码,至少在oracle的环境下,无法正常使用。
问题发现了,要怎么解决?
首先是信心,很多大人物特别喜欢说信心比黄金还重要,所以我们先要有信心;如果dbutils不能连接Oracle数据库,那么我们没有必要在这里继续倒腾;
然后是学习,在网上看了一大圈,用百度找到一些资料,看看总没有坏处。
仔细看这个异常,最后一节抛出来的是 getParameterMetaData()方法,那么姑且认为和 参数的元数据有关系;
因为这个实例简单,因此可以聚焦问题。只需要关注 conn连接,QueryRunner初始化和执行update三个地方有关。
如果不用QueryRunner,conn也可以访问数据库,那么排除下来。只要关注QueryRunner初始化和执行update两个地方就可以了。
QueryRunner 初始化有四个方法,看下类的说明,好像有两个和元数据有关系。
那就试一试,诶,都可以。
把上面的代码稍微调整下:
QueryRunner qRunner= new QueryRunner(dataSource,true);
或者
QueryRunner qRunner= new QueryRunner(true);
都可以解决问题,输出结果为:
-------------test_insert()-------------
成功插入1条数据!
数据插入了,那么下一步就是要查询了。
哎呦,又出异常了:
-------------test_query()-------------
Exception in thread"main" java.sql.SQLException: Cannot createtest.ffm83.commons.dbutils.QueryRunnerError$tb_user:test.ffm83.commons.dbutils.QueryRunnerError$tb_user Query: select username,passwordfrom tb_user Parameters: []
atorg.apache.commons.dbutils.AbstractQueryRunner.rethrow(AbstractQueryRunner.java:392)
atorg.apache.commons.dbutils.QueryRunner.query(QueryRunner.java:351)
atorg.apache.commons.dbutils.QueryRunner.query(QueryRunner.java:226)
attest.ffm83.commons.dbutils.QueryRunnerError.test_query(QueryRunnerError.java:90)
attest.ffm83.commons.dbutils.QueryRunnerError.main(QueryRunnerError.java:67)
这可如何是好?
先看下这段利用QueryRunner进行查询的源代码:
packagetest.ffm83.commons.dbutils;
importjava.sql.Connection;
importjava.sql.SQLException;
importjava.util.List;
importjava.util.Properties;
importorg.apache.commons.dbcp.BasicDataSource;
importorg.apache.commons.dbcp.BasicDataSourceFactory;
importorg.apache.commons.dbutils.DbUtils;
importorg.apache.commons.dbutils.QueryRunner;
importorg.apache.commons.dbutils.handlers.ArrayHandler;
importorg.apache.commons.dbutils.handlers.BeanListHandler;
/**
* 通过commons dbUtils进行数据库的简单访问和实用,同时暴露一些异常 dbUtils1.6,Oracle驱动:class12
*
* @author 范芳铭
*/
public classQueryRunnerError {
private static BasicDataSourcedataSource = null;
private QueryRunner runner = null;
public QueryRunnerError() {
init();
runner = newQueryRunner(dataSource);
}
public static void init() {
if (dataSource != null) {
try {
dataSource.close();
} catch (Exceptione) {
e.printStackTrace();
}
dataSource = null;
}
try {
Properties p = newProperties();
p.setProperty("driverClassName","oracle.jdbc.driver.OracleDriver");
p.setProperty("url","jdbc:oracle:thin:@192.168.1.1:1521:fanfangming");
p.setProperty("password","ffm");
p.setProperty("username","ffm");
p.setProperty("maxActive","4");
p.setProperty("maxIdle","1");
p.setProperty("maxWait","100");
dataSource =(BasicDataSource) BasicDataSourceFactory
.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
}
public static synchronized ConnectiongetConnection() throws SQLException {
if (dataSource == null) {
init();
}
Connection conn = null;
if (dataSource != null) {
conn =dataSource.getConnection();
}
return conn;
}
public static void main(String[] args)throws SQLException {
// test_insert();
test_query();
}
public static void test_insert() throwsSQLException {
System.out.println("-------------test_insert()-------------");
// 创建连接
Connection conn =getConnection();
// 创建SQL执行工具
QueryRunner qRunner = newQueryRunner(dataSource, true);
// 执行SQL插入
int n = qRunner.update(conn,
"insertinto tb_user(username,password) values(‘范芳铭‘,‘ffm‘)");
System.out.println("成功插入" + n + "条数据!");
// 关闭数据库连接
DbUtils.closeQuietly(conn);
}
public static void test_query() throwsSQLException {
System.out.println("-------------test_query()-------------");
// 创建连接
Connection conn =getConnection();
QueryRunner qRunner = newQueryRunner(true);
// 执行SQL查询,并获取结果
List<tb_user> list =(List<tb_user>) qRunner.query(conn,
"select username,password from tb_user ", new BeanListHandler(
tb_user.class));
// 输出查询结果
for (tb_user user : list) {
System.out.println(user);
}
//关闭数据库连接
DbUtils.closeQuietly(conn);
}
public class tb_user {
private String username;
private String password;
public tb_user(String username,String password) {
this.username =username;
this.password =password;
}
public String getUsername() {
return username;
}
public voidsetUsername(String username) {
this.username =username;
}
public String getPassword() {
return password;
}
public voidsetPassword(String password) {
this.password =password;
}
}
}
既然能插入,那么肯定也能读出来,但是我们在准备处理这个问题的生活,有好几个地方可能出错,比如List,比如tb_user,那么我们还是老办法,看看更加简单的办法行不行。
下面是一个尝试的方法,一个是直接读取数据,另外一个是转换为简单bean,而不是list,先看看吧。
package test.ffm83.commons.dbutils;
importjava.sql.Connection;
importjava.sql.SQLException;
importjava.util.Arrays;
importjava.util.List;
importjava.util.Properties;
importorg.apache.commons.dbcp.BasicDataSource;
importorg.apache.commons.dbcp.BasicDataSourceFactory;
importorg.apache.commons.dbutils.DbUtils;
importorg.apache.commons.dbutils.QueryRunner;
importorg.apache.commons.dbutils.handlers.ArrayHandler;
importorg.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
importtest.ffm83.commons.dbutils.QueryRunnerExample.Auser;
/**
* 通过commons dbUtils进行数据库的简单访问和实用,同时暴露一些异常 dbUtils1.6,Oracle驱动:class12
*
* @author 范芳铭
*/
public classQueryRunnerError {
private static BasicDataSourcedataSource = null;
private QueryRunner runner = null;
public QueryRunnerError() {
init();
runner = newQueryRunner(dataSource);
}
public static void init() {
if (dataSource != null) {
try {
dataSource.close();
} catch (Exceptione) {
e.printStackTrace();
}
dataSource = null;
}
try {
Properties p = newProperties();
p.setProperty("driverClassName","oracle.jdbc.driver.OracleDriver");
p.setProperty("url","jdbc:oracle:thin:@192.168.1.1:1521:fanfangming");
p.setProperty("password","ffm");
p.setProperty("username","ffm");
p.setProperty("maxActive","4");
p.setProperty("maxIdle","1");
p.setProperty("maxWait","100");
dataSource = (BasicDataSource)BasicDataSourceFactory
.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
}
public static synchronized ConnectiongetConnection() throws SQLException {
if (dataSource == null) {
init();
}
Connection conn = null;
if (dataSource != null) {
conn =dataSource.getConnection();
}
return conn;
}
public static void main(String[] args)throws SQLException {
// test_insert();
test_query();
}
public static void test_insert() throwsSQLException {
System.out.println("-------------test_insert()-------------");
// 创建连接
Connection conn =getConnection();
// 创建SQL执行工具
QueryRunner qRunner = newQueryRunner(dataSource, true);
// 执行SQL插入
int n = qRunner.update(conn,
"insertinto tb_user(username,password) values(‘范芳铭‘,‘ffm‘)");
System.out.println("成功插入" + n + "条数据!");
// 关闭数据库连接
DbUtils.closeQuietly(conn);
}
public static void test_query() throwsSQLException {
System.out.println("-------------test_query()-------------");
// 创建连接
Connection conn =getConnection();
QueryRunner qRunner = newQueryRunner(true);
//先看看能不能查询
String sql = "SELECT *FROM tb_user WHERE rownum < ? ";
System.out.println("1.TestQueryRunner query, ArrayHandler");
//把ResultSet第一行包装成Object[]
Object[] r1 = qRunner.query(conn,sql,new ArrayHandler(), "3");
System.out.println(" " + Arrays.deepToString(r1));
System.out.println("2.TestQueryRunner query, BeanHandler");
//把ResultSet第一行包装成一个JavaBean
tb_user r2 = qRunner.query(conn,sql,new BeanHandler<tb_user>(tb_user.class), "3");
System.out.println(" " + r2.toString());
/* // 执行SQL查询,并获取结果
List<tb_user> list =(List<tb_user>) qRunner.query(conn,
"select username,password from tb_user ", new BeanListHandler(
tb_user.class));
// 输出查询结果
for (tb_user user : list) {
System.out.println(user);
}*/
//关闭数据库连接
DbUtils.closeQuietly(conn);
}
public class tb_user {
private String username;
private String password;
public tb_user(Stringusername, String password) {
this.username =username;
this.password =password;
}
public String getUsername() {
return username;
}
public voidsetUsername(String username) {
this.username =username;
}
public String getPassword() {
return password;
}
public voidsetPassword(String password) {
this.password =password;
}
}
}
运行结果如下:
-------------test_query()-------------
1.Test QueryRunnerquery, ArrayHandler
[范芳铭, ffm]
2.Test QueryRunnerquery, BeanHandler
Exception in thread"main" java.sql.SQLException: Cannot createtest.ffm83.commons.dbutils.QueryRunnerError$tb_user:test.ffm83.commons.dbutils.QueryRunnerError$tb_user Query: SELECT * FROMtb_user WHERE rownum < ? Parameters:[3]
atorg.apache.commons.dbutils.AbstractQueryRunner.rethrow(AbstractQueryRunner.java:392)
atorg.apache.commons.dbutils.QueryRunner.query(QueryRunner.java:351)
atorg.apache.commons.dbutils.QueryRunner.query(QueryRunner.java:212)
attest.ffm83.commons.dbutils.QueryRunnerError.test_query(QueryRunnerError.java:105)
attest.ffm83.commons.dbutils.QueryRunnerError.main(QueryRunnerError.java:73)
这样一来,问题就比较清晰了,QueryRunner读取数据没有问题,在转换成对象的时候,可能有点状况。
仔细看这段错误异常:
Test QueryRunnerquery, BeanHandler
Exception in thread"main" java.sql.SQLException: Cannot createtest.ffm83.commons.dbutils.QueryRunnerError$tb_user:test.ffm83.commons.dbutils.QueryRunnerError$tb_user Query: SELECTUSERNAME,PASSWORD FROM tb_user WHERE rownum < ? Parameters: [3]
是无法创建这个tb_user对象,那么问题可能不在QueryRunner上面,有可能问题出现在tb_user上面。
和创建有关的首先看构造函数,没有默认的构造函数,那么试一试加上。
这个调用的方法是反射方法,反射可能要调用空的默认的构造函数。因此导致异常的出现。
加一个默认构造函数:
public tb_user(){
}
好吧,运行下看看,异常还是出来了?
为什么额?
我们上面的tb_user是个什么东东呢?是个内部类。内部类在反射机制中,问题会变的很复杂,简单点,把tb_user拿出来吧,就有了2个class.
packagetest.ffm83.commons.dbutils;
/**
* 通过commons dbUtils进行数据库的简单访问和实用的javaBean
* QueryRunner 代码实例
* @author 范芳铭
*/
public classTb_user {
private String username;
private String password;
public Tb_user(){
}
public Tb_user(String username, Stringpassword) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(Stringusername) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(Stringpassword) {
this.password = password;
}
@Override
public String toString(){
return "name:" +username + ",pass:" + password;
}
}
packagetest.ffm83.commons.dbutils;
importjava.sql.Connection;
importjava.sql.SQLException;
importjava.util.Arrays;
importjava.util.List;
importjava.util.Properties;
importorg.apache.commons.dbcp.BasicDataSource;
importorg.apache.commons.dbcp.BasicDataSourceFactory;
import org.apache.commons.dbutils.DbUtils;
importorg.apache.commons.dbutils.QueryRunner;
importorg.apache.commons.dbutils.handlers.ArrayHandler;
importorg.apache.commons.dbutils.handlers.BeanHandler;
importorg.apache.commons.dbutils.handlers.BeanListHandler;
/**
* 通过commons dbUtils进行数据库的简单访问和实用,同时暴露一些异常 dbUtils1.6,Oracle驱动:class12
* QueryRunner 代码实例
* @author 范芳铭
*/
public classQueryRunnerError {
private static BasicDataSourcedataSource = null;
private QueryRunner runner = null;
public QueryRunnerError() {
init();
runner = newQueryRunner(dataSource);
}
public static void init() {
if (dataSource != null) {
try {
dataSource.close();
} catch (Exceptione) {
e.printStackTrace();
}
dataSource = null;
}
try {
Properties p = new Properties();
p.setProperty("driverClassName","oracle.jdbc.driver.OracleDriver");
p.setProperty("url","jdbc:oracle:thin:@192.168.1.1:1521:fanfangming");
p.setProperty("password","ffm");
p.setProperty("username","ffm");
p.setProperty("maxActive","4");
p.setProperty("maxIdle","1");
p.setProperty("maxWait","100");
dataSource =(BasicDataSource) BasicDataSourceFactory
.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
}
public static synchronized ConnectiongetConnection() throws SQLException {
if (dataSource == null) {
init();
}
Connection conn = null;
if (dataSource != null) {
conn =dataSource.getConnection();
}
return conn;
}
public static void main(String[] args)throws SQLException {
// test_insert();
test_query();
}
public static void test_insert() throwsSQLException {
System.out.println("-------------test_insert()-------------");
// 创建连接
Connection conn =getConnection();
// 创建SQL执行工具
QueryRunner qRunner = newQueryRunner(dataSource, true);
// 执行SQL插入
int n = qRunner.update(conn,
"insertinto tb_user(username,password) values(‘范芳铭‘,‘ffm‘)");
System.out.println("成功插入" + n + "条数据!");
// 关闭数据库连接
DbUtils.closeQuietly(conn);
}
public static void test_query() throwsSQLException {
System.out.println("-------------test_query()-------------");
// 创建连接
Connection conn =getConnection();
QueryRunner qRunner = newQueryRunner(true);
//先看看能不能查询
String sql = "SELECTUSERNAME,PASSWORD FROM tb_user WHERE rownum < ? ";
System.out.println("TestQueryRunner query, ArrayHandler");
//把ResultSet第一行包装成Object[]
Object[] r1 = qRunner.query(conn,sql,new ArrayHandler(), "3");
System.out.println(" "+ Arrays.deepToString(r1));
System.out.println("TestQueryRunner query, BeanHandler");
//把ResultSet第一行包装成一个JavaBean
Tb_user rBean= qRunner.query(conn,sql,new BeanHandler<Tb_user>(Tb_user.class), "3");
System.out.println(" " + rBean.toString());
// 执行SQL查询,并获取结果
List<Tb_user> list =(List<Tb_user>) qRunner.query(conn,
"select username,password from tb_user ", newBeanListHandler<Tb_user>(
Tb_user.class));
// 输出查询结果
for (Tb_user user : list) {
System.out.println(user);
}
//关闭数据库连接
DbUtils.closeQuietly(conn);
}
}
运行结果如下:
-------------test_query()-------------
Test QueryRunnerquery, ArrayHandler
[范芳铭, ffm]
Test QueryRunnerquery, BeanHandler
name:范芳铭,pass:ffm
name:范芳铭,pass:ffm
name:2,pass:ffm