`
悲剧了
  • 浏览: 144304 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

一个常见的JDBC封装导致的问题

阅读更多
大家看一个数据库封装类
操作一次没问题,操作两次就报错
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.


Debug调试,发现connection不能真正关掉,使用connection完后,调用close()方法,下次getConnection()时候
instance不为null



public class ConnectionUtil {
	private final static String  url="jdbc:mysql://localhost:3306/qq?useUnicode=true&characterEncoding=UTF-8";
	private final static String  username="root";
	private final static String  password="root";
	private  static Connection   instance=null;
	
	private ConnectionUtil(){
		if(instance==null){
			try {
				Class.forName("org.gjt.mm.mysql.Driver");
				instance=DriverManager.getConnection(url, username, password);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	public static Connection getConnection(){
		if(instance==null){
			new ConnectionUtil();
		}
		return instance;
		
	}
	
	
	public static void close(Connection con,PreparedStatement ps,ResultSet rs){
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				con=null;
			}
		}
		if(ps!=null){
			try {
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				ps=null;
			}
		}
		if(rs!=null){
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				rs=null;
			}
		}
		
	}
	
	public static void close(Connection con,PreparedStatement ps){
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				con=null;
			}
		}
		if(ps!=null){
			try {
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				ps=null;
			}
		}
		
		
	}
	
	public static void close(Connection con){
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				con=null;
			}
		}
	}

}



结贴了。。。。有其他结贴方式吗?
分享到:
评论
59 楼 fatesymphony 2011-05-18  
kakaluyi 写道
算了解释一下,发现楼主还是云里雾里
public void static main(String args[])
{
int i=3;
changevalue(i);
System.out.println(i);
//你以为i现在是2吧,错了,i还是3!不好意思楼主,你理解错误了。这个是很容易搞错的概念
}
public void changevalue(int i)
{
i=2;
}


朋友很热心,但是你却没有明白Java的基本数据类型与引用类型的区别。
你这样会对人造成误导的,不是楼主搞错了而是你搞错了。


楼主的代码写得确实很混乱。
58 楼 sebatinsky 2011-05-17  
这个单列写的。。。。。。。我看着似乎不敢发言了。
57 楼 jekyll 2011-05-17  
没发现搂主 instance=null 的语句
56 楼 Technoboy 2011-05-17  
悲剧了 写道
kakaluyi 写道
悲剧了 写道
gaosheng08 写道
close()中还要加一句instance = null;


调用的时候传进来的就是instance ,这个connection是通过这个类的getConnection()得到的

lz你难道不知道java通过close方法传递进去的instance只是个引用吗,真正的instance是不会置为null的??





哥们我明白了

con,intance 两个引用指向同一个栈,con为空但intance不为空,开始是以为传进去的是intance

Connection con=instance
con=null
但intance不为空

哎,悲剧,估计又要挨骂了


+1
new ConnectionUtil 匿名对象
55 楼 Technoboy 2011-05-17  
ecokozhangtao 写道
你这个单例写的,有可能产生死锁

连同步都没有,还能出来死锁....
54 楼 tom&jerry 2011-05-17  
悲剧了 写道
gaosheng08 写道
close()中还要加一句instance = null;


调用的时候传进来的就是instance ,这个connection是通过这个类的getConnection()得到的


instance 和 con 是一个对象的两个引用,假设对象为A, B和C为到A的引用,C=null只是切断了C到A的联系,B与A的联系依然存在。
53 楼 wingok 2011-05-16  
非常常用的功能,建议先找找有没通用的开源实现
http://commons.apache.org/dbutils/
52 楼 shanga 2011-05-16  
悲剧了 写道
大家看一个数据库封装类
操作一次没问题,操作两次就报错
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.


Debug调试,发现connection不能真正关掉,使用connection完后,调用close()方法,下次getConnection()时候
instance不为null



public class ConnectionUtil {
	private final static String  url="jdbc:mysql://localhost:3306/qq?useUnicode=true&characterEncoding=UTF-8";
	private final static String  username="root";
	private final static String  password="root";
	private  static Connection   instance=null;
	
	private ConnectionUtil(){
		if(instance==null){
			try {
				Class.forName("org.gjt.mm.mysql.Driver");
				instance=DriverManager.getConnection(url, username, password);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	public static Connection getConnection(){
		if(instance==null){
			new ConnectionUtil();
		}
		return instance;
		
	}
	
	
	public static void close(Connection con,PreparedStatement ps,ResultSet rs){
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				con=null;
			}
		}
		if(ps!=null){
			try {
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				ps=null;
			}
		}
		if(rs!=null){
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				rs=null;
			}
		}
		
	}
	
	public static void close(Connection con,PreparedStatement ps){
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				con=null;
			}
		}
		if(ps!=null){
			try {
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				ps=null;
			}
		}
		
		
	}
	
	public static void close(Connection con){
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				con=null;
			}
		}
	}

}

一个connetion.close掉了就不可以用了,你这里if(instance==null),第二次用的时候install不为null,是一个connection对象,但他的状态时closed,所以下面的if语句块,不会执行。今天没认真看代码,罪过,罪过...

结贴了。。。。有其他结贴方式吗?

51 楼 zhangchen 2011-05-16  
sswh 写道

代码真够混乱的。

本来不想回了,算了,还是说一下吧。

悲剧了 写道
public class ConnectionUtil {
	private  static Connection   instance=null;
}


这儿:instance是ConnectionUtil 类的静态变量。

悲剧了 写道
	public static void close(Connection con){
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				con=null;
			}
		}
	}
}


这儿:close()方法中,置空的con=null,是方法参数。ConnectionUtil.instance 并没有受到影响。


正解,Java的参数都是值传递,非引用传递
50 楼 ecokozhangtao 2011-05-16  
你这个单例写的,有可能产生死锁
49 楼 悲剧了 2011-05-16  
<div class="quote_title">woaiwofengkuang 写道</div>
<div class="quote_div">
<div class="quote_title">ericslegend 写道</div>
<div class="quote_div">
<div class="quote_title">悲剧了 写道</div>
<div class="quote_div">
<div class="quote_title">kakaluyi 写道</div>
<div class="quote_div">算了解释一下,发现楼主还是云里雾里<br>public void static main(String args[])<br>{<br>int i=3;<br>changevalue(i);<br>System.out.println(i);<br>//你以为i现在是2吧,错了,i还是3!不好意思楼主,你理解错误了。这个是很容易搞错的概念<br>}<br>public void changevalue(int i)<br>{<br>i=2;<br>}</div>
<br><br><br>恩,明白了,谢了<br>
</div>
<br>都说楼主不理解,我看回答问题的没几个理解的(当然,我也很菜),传个String试试,传个其它引用对象试试,看看是不是改的原有对象,基本类型和引用类型是不一样的。</div>
<p><br><br>哎,这就是典型的参数传递问题。<br>java中只有值传递的。当你传一个引用类型的参数时,实际上是将引用copy一份传过去。所以在方法中将copy的新的引用设为null是不会影响,原先外部的引用的。<br>用图来说明:<img alt=""></p>
<p><img alt=""></p>
<p>第一张是传值copy后再设为空的。</p>
<p>第二第是传传时copy的。</p>
<p> </p>
<p> </p>
</div>
<p>就是这么回事,对了哥们,这帖子能结贴吗?</p>
48 楼 woaiwofengkuang 2011-05-16  
<div class="quote_title">ericslegend 写道</div>
<div class="quote_div">
<div class="quote_title">悲剧了 写道</div>
<div class="quote_div">
<div class="quote_title">kakaluyi 写道</div>
<div class="quote_div">算了解释一下,发现楼主还是云里雾里<br>public void static main(String args[])<br>{<br>int i=3;<br>changevalue(i);<br>System.out.println(i);<br>//你以为i现在是2吧,错了,i还是3!不好意思楼主,你理解错误了。这个是很容易搞错的概念<br>}<br>public void changevalue(int i)<br>{<br>i=2;<br>}</div>
<br><br><br>恩,明白了,谢了<br>
</div>
<br>都说楼主不理解,我看回答问题的没几个理解的(当然,我也很菜),传个String试试,传个其它引用对象试试,看看是不是改的原有对象,基本类型和引用类型是不一样的。</div>
<p><br><br>哎,这就是典型的参数传递问题。<br>java中只有值传递的。当你传一个引用类型的参数时,实际上是将引用copy一份传过去。所以在方法中将copy的新的引用设为null是不会影响,原先外部的引用的。<br>用图来说明:<img alt=""></p>
<p><img alt=""></p>
<p>第一张是传值copy后再设为空的。</p>
<p>第二第是传传时copy的。</p>
<p> </p>
<p> </p>
47 楼 uin57 2011-05-16  
1  单例模式 应用错误
2  由于单例使用错误 多次getconnection都是同一连接  调用一次close 其他地方持有的连接全部报废...
3  关闭连接时候并不判断是不是本池所产生的 就乱关闭 这样关闭了连接并未多对象池的连接造成任何影响.
剩下的就是 次要错误了, 解决了这三个其他的自然就没有错误了..
46 楼 ericslegend 2011-05-16  
<pre name="code" class="java">public class Test
{
public static void main(String args[])
{
int i = 1;
change(i);
System.out.println(i);

String str = "aaa";
change(str);
System.out.println(str);

StringBuffer strb = new StringBuffer("buffer");
change(strb);
//strb=null;对比方法体内的null
System.out.println(strb.toString());

Demo d = new Demo();
change(d.s);
System.out.println(d.s);
change(d);
System.out.println(d.s);

}

public static void change(int i)
{
i = 0;
}

public static void change(String str)
{
str = "object property stay";

}

public static void change(Demo demo)
{
demo.s = "object changed";

}

public static void change(StringBuffer sb)
{
sb.append(" -- added");
//sb=null;
sb.append(" -- added twice");
}
}

class Demo
{
String s = "initial string value";
}</pre>
<p> </p>
<p>结果:</p>
<p> </p>
<pre name="code" class="java">aaa
buffer -- added -- added twice
initial string value
object changed</pre>
<p> </p>
<p>楼主可以看一下。</p>
45 楼 悲剧了 2011-05-16  
woaiwofengkuang 写道
哎,这代码写的。第一个的close的关闭顺序就有问题。
第二个,你在返回后再传入的Connection已经不是ConnectionUtil类中那个类变量了。
不会影响instance的。所以拿到的永远是同个一个Connection.
再说了instance是个类变量。只要它有值了,所有实例是共有的。

哎,杯具呀。



哥们你还真没说到点子上,这个是由于咋们java基础不好,建议你看看前面的帖子
44 楼 woaiwofengkuang 2011-05-16  
哎,这代码写的。第一个的close的关闭顺序就有问题。
第二个,你在返回后再传入的Connection已经不是ConnectionUtil类中那个类变量了。
不会影响instance的。所以拿到的永远是同个一个Connection.
再说了instance是个类变量。只要它有值了,所有实例是共有的。

哎,杯具呀。
43 楼 悲剧了 2011-05-16  
shanga 写道
悲剧了 写道
shanga 写道
在23行代码中,楼主做了创造主,创造了无数的逃逸对象,但他只握住了女娲,是何等的专一,使我想起了中国警察的故事。这些逃逸对象做的事(楼主说得instance存在),但是实际上抛出connection close错误,因为楼主只记住女娲,其他人一个也没放眼里。



哥们,我语文不太好,真没看懂

new的对象没引用,就成了逃逸对象,这就是你debug到instance存在,而connection closed(就是我刚刚说的女娲)的原因。而且你这个所谓的单例也写的。。。。



new对象只是为了调用构造方法时候,给instance赋值,我还是没太明白你的意思
42 楼 悲剧了 2011-05-16  
<div class="quote_title">uin57 写道</div>
<div class="quote_div">
<pre name="code" class="java"> public static void close(Connection con){ 
       if(instance!=con){
                  throw new RunTimeException("你还给我的连接并不是从我这里拿走的(此处省略粗口1万字)....");
       }
        if(con!=null){  
            try {  
                con.close();  
            } catch (SQLException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }finally{
                 instance=con=null;  
            }  
        }  
    }  
</pre>
<p>好吧 你要鱼就给你鱼 看好了</p>
<p> </p>
</div>
<p>。。。。。。。</p>
41 楼 shanga 2011-05-16  
悲剧了 写道
shanga 写道
在23行代码中,楼主做了创造主,创造了无数的逃逸对象,但他只握住了女娲,是何等的专一,使我想起了中国警察的故事。这些逃逸对象做的事(楼主说得instance存在),但是实际上抛出connection close错误,因为楼主只记住女娲,其他人一个也没放眼里。



哥们,我语文不太好,真没看懂

new的对象没引用,就成了逃逸对象,这就是你debug到instance存在,而connection closed(就是我刚刚说的女娲)的原因。而且你这个所谓的单例也写的。。。。
40 楼 uin57 2011-05-16  
<pre name="code" class="java"> public static void close(Connection con){ 
       if(instance!=con){
                  throw new RunTimeException("你还给我的连接并不是从我这里拿走的(此处省略粗口1万字)....");
       }
        if(con!=null){  
            try {  
                con.close();  
            } catch (SQLException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }finally{
                 instance=con=null;  
            }  
        }  
    }  
</pre>
<p>好吧 你要鱼就给你鱼 看好了</p>
<p> </p>

相关推荐

    原创的JDBC封装可支持各种数据库

    通过以上步骤,我们可以创建一个高度可配置、易于使用的JDBC封装库,支持多种数据库。在实际项目中,只需在配置文件中更改数据库相关参数,就能轻松切换到不同的数据库系统,极大地提高了代码的可维护性和可扩展性。...

    游戏服务器 数据库连接池 jdbc 简单封装

    在`nebula-jdbc-master`这个项目中,我们可以看到一个名为Nebula JDBC的实现,它可能就是对JDBC和数据库连接池的一个自定义封装。通过分析该项目的源码,我们可以学习如何自定义数据库连接池组件,如何优化JDBC的...

    jdbc-utils.rar_Utils_jdbc_jdbc封装

    这个文件很可能是封装好的一个基类,为具体的DAO(Data Access Object)提供通用的方法。可能包含以下功能: - 连接管理:自动获取和释放连接,通常会利用`PoolManager`来获取连接池中的连接。 - SQL执行:提供...

    jdbc封装的代码

    这个例子展示了如何使用封装后的JDBC工具类来执行一个查询操作,无需关心连接的创建与关闭,SQL参数的设置以及结果集的处理,大大提高了代码的可读性和易用性。这就是JDBC封装的主要目的和实现方式。

    自己写一个DAO 实现对jdbc dbcp封装 开源小组件

    本组件"自己写的一个DAO 实现对jdbc dbcp封装 开源小组件"是作者学习研究的成果,适用于小型项目,同时也是初学者了解和实践DAO设计模式、JDBC以及Apache DBCP连接池的好材料。 1. JDBC(Java Database ...

    有关于jdbc的基本封装

    JDBC是Java平台上的一个API,允许Java开发者与各种类型的数据库进行交互。它提供了一组接口和类,使得程序员可以编写数据库独立的代码,从而不必关心底层数据库的具体实现。 2. 基本CRUD操作: - 创建(Create)...

    JDBC 工具类JdbcUtils封装与测试应用(针对mysql)

    因此,JdbcUtils还可以进一步封装这些操作,例如添加一个执行SQL查询的方法: ```java // 执行SQL查询,返回结果集 public static ResultSet executeQuery(String sql) { Connection conn = getConnection(); ...

    SQL封装

    在IT行业中,SQL封装是Java开发中常见的一个实践,它能帮助我们更高效、更安全地操作数据库。本文将深入探讨“SQL封装”这一主题,尤其是对于初学者来说,掌握好这一技能对于提升JDBC(Java Database Connectivity)...

    Oracle jdbc 单例 工具类

    本示例中的"Oracle jdbc 单例 工具类"着重讨论了单例模式的应用,单例模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点。在数据库连接管理中,使用单例模式可以避免频繁创建和关闭连接,提高...

    sharding-jdbc按月分表样例

    【标题】"sharding-jdbc按月分表样例"是一个关于使用Sharding-JDBC进行数据库分片的示例项目,旨在展示如何根据月份动态地将数据分散到不同的表中,以实现数据的水平扩展和负载均衡。Sharding-JDBC是阿里巴巴开源的...

    spring+jdbc整合

    "spring+jdbc整合"是一个常见的话题,尤其对于初学者而言,理解这两者的结合是提升开发效率的关键。下面我们将详细探讨Spring如何与JDBC进行整合,以及这种整合在实际项目中的应用。 首先,Spring框架通过其JDBC...

    JDBC知识点总结

    所有对数据库的操作都需要在一个有效的连接上进行。 3. **Statement**:用于执行 SQL 语句,并获取执行结果。 4. **ResultSet**:存储 SQL 查询结果的集合,通常被视为一张虚拟表。 #### 三、JDBC 的准备工作 1. *...

    SpringJDBC注解事务.zip

    Spring JDBC提供了一个JdbcTemplate类,它封装了常见的JDBC操作,如执行SQL查询、更新、调用存储过程等,减少了代码量和出错的可能性。此外,它还处理了诸如打开和关闭连接、结果集遍历等繁琐任务。 2. **注解驱动...

    JDBC数据库访问工具类 强大 精巧 高效

    总结来说,一个强大的JDBC数据库访问工具类是Java项目中必不可少的一部分,它通过封装和优化JDBC操作,降低了开发难度,提高了代码的可读性和维护性,同时提升了系统的运行效率。在设计和实现这样的工具类时,我们...

    jdbc分页查询源码

    在给定的源码中,可能包含了一个封装好的分页查询工具类,这个类通常会有以下方法: - `queryByPage(Connection conn, String sql, int pageNum, int pageSize)`:接收数据库连接、基础SQL语句以及分页参数,返回...

    Spring与JDBC整合

    - 在执行SQL时,需要提供一个Map或SqlParameterSource对象来传递参数值。 3. **事务管理**: - Spring提供了PlatformTransactionManager接口,如DataSourceTransactionManager,用于管理事务。 - 可以使用@...

    JDBC学习笔记

    - 将每条记录封装为一个Map,然后存储到List中。 #### 二十五、Java反射技术入门 - **概念**:反射是在运行时分析类和对象的能力。 - **应用**:使用反射技术根据结果集元数据动态创建Java对象,实现查询结果的...

    效率很高的java jdbc类

    2. **迭代器模式**:提供一个迭代器接口,使得遍历结果集更加灵活且节省内存,避免一次性加载所有数据导致内存溢出。 3. **类型转换**:根据需要自动将数据库中的值转换为适当的Java类型,例如将字符串转换为日期、...

    JSP+JDBC_假分页

    - **传递数据到JSP**:将ResultSet封装到一个集合对象(如ArrayList),然后通过请求转发或者模型视图适配器(MVC)模式传递到JSP页面。 - **JSP页面处理**:在JSP页面上,使用JavaScript或者jQuery等前端技术,...

    JDBC代码详解.docx

    JDBC的接口由数据库提供商实现,这意味着只要有一个支持JDBC的驱动程序,就可以使用相同的Java代码来访问不同的数据库。 #### JDBC入门案例详解 ##### 1.2.1 流程分析 假设我们的需求是查询数据库中的数据并在...

Global site tag (gtag.js) - Google Analytics