Connection能设置成静态的吗

miracleliu 2010-09-15 01:54:40
    
public class CampaignDao {

private static Connection conn = null;
private ResultSet rs = null;
private PreparedStatement pstmt = null;

public CampaignDao(){
try {
conn = BaseUtil.getConnection();
} catch (Exception e1) {
e1.printStackTrace();
}
}

public Campaign queryById(int campaignId){
Campaign campaign = null;
log.debug("campaign queryByid() run");

String sql = null;

try {
sql="select * from campaign where campaignId=?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, campaignId);
rs = pstmt.executeQuery();
rs.next();
campaign = new Campaign(campaignId,rs.getString("campaignName"),
rs.getString("contentProvider"),rs.getString("createUser"),rs.getString("description"),
rs.getTimestamp("startDate"),rs.getTimestamp("endDate"));
} catch (SQLException e) {
e.printStackTrace();
}finally{

try {
if(rs!=null)rs.close();
if(pstmt!=null)pstmt.close();
if(conn!=null)conn.close();
} catch (SQLException e) {
e.printStackTrace();
}

}
return campaign;
}


我想把这个类的方法全部设置成静态的,这样的话connection、Resultset,preparedStatement都要设置成静态的。
这样会不会导致同步之类的问题?

另外:希望大家对我写的这个DAO的类提出优化意见。谢谢
...全文
530 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
cooljia 2010-09-17
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 bao110908 的回复:]
Java code
private Connection con;

public void test() {
con = ConnectionFactory.getConnection();
....
}


试看这样的代码。

由于 con 对象是被多个线程共享的。

A 线程先进来获得连接 A,B 线程获得连接 B,此时 con 的连接是连接 B
……
[/Quote]

谢谢,完全理解!这样确实会造成泄漏!
cooljia 2010-09-16
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 bao110908 的回复:]
并不是说不能把连接对象弄成成员变量,只是不能将其弄成成员变量后,在多线程环境下处于共享这些对象,如果同步处理得不好,那就会产生严重的连接泄漏。

为了避免这种情况发生,仅在用时获取连接,用完后马上关掉。

我想 JDBC 的代码套路大家应该都知道吧?


Java code
public void query() {
Connection con = null;
……
[/Quote]


火龙果这个贴确实让我受益匪浅!!
不过这个泄漏是如何产生的呢?看了一下java.sql.Connection接口的javadoc,关于close方法有这样的一段注释
If the <code>close</code> method is called and there is an active transaction, the results are implementation-defined.

我认为有两种情况:
1. 线程1,线程2同时获得connection, 只要其中一个关闭了 connection connection就立刻关闭这样是不会有连接泄漏问题的(当然很明显,有其他严重问题:))。
2. 线程1在关闭connection的时候因为线程2在transaction中,所以线程1没有关闭掉,但是这样的情况下
a. 线程1应该获得一个close exception
b. 线程2在结束transaction之后应该也要去close
内存,连接泄漏何来之有呢?我觉得应该是很多线程的执行情况很古怪,查询失败很多吧。
zn85600301 2010-09-16
  • 打赏
  • 举报
回复
完全是偏离了方向
24K純帥 2010-09-16
  • 打赏
  • 举报
回复
顶火龙果大哥的,设置成静态的后果很严重,会泄露的
  • 打赏
  • 举报
回复
当然了,这个 Connection 所在的类处于单例模式,或者被多个线程共享的状态下才会出现这样的结果,如果都是 new 出来的就不会有这种现象了。
  • 打赏
  • 举报
回复
private Connection con;

public void test() {
con = ConnectionFactory.getConnection();
....
}


试看这样的代码。

由于 con 对象是被多个线程共享的。

A 线程先进来获得连接 A,B 线程获得连接 B,此时 con 的连接是连接 B
A 线程执行完后需要关闭连接,当前连接为连接 B,因此关闭的是连接 B
B 线程执行完后需要关闭连接,当前连接为连接 B,且已被闭

示意图:

   线程   时间片
--------------------------------------------------------
A 获得连接A 关闭
B 获得连接B 关闭
--------------------------------------------------------
con状态 连接A 连接B 连接B关闭 报错


连接 A 在连接 B 获得后,就处于垃圾对象状态,如果连接是从池中取出来的,那这个连接就泄漏了。
  • 打赏
  • 举报
回复
并不是说不能把连接对象弄成成员变量,只是不能将其弄成成员变量后,在多线程环境下处于共享这些对象,如果同步处理得不好,那就会产生严重的连接泄漏。

为了避免这种情况发生,仅在用时获取连接,用完后马上关掉。

我想 JDBC 的代码套路大家应该都知道吧?

public void query() {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = ConnectionFactory.getConnection();
String sql = "xxxx";
ps = con.preparedSatement(sql);
ps.setXxxxx(1, xxx);
rs = ps.executeQuery();
while(rs.next()) {
Xxxx xxx = rs.getXxxx();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (rs != null) try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }
if (ps != null) try { ps.close(); } catch (SQLException e) { e.printStackTrace(); }
if (con != null) try { con.close(); } catch (SQLException e) { e.printStackTrace(); }
}
}


如果谁要是自作聪明的话,那就看看这些帖子吧:

tomcat连接池,重复多次调用方法出错: Connection is closed
http://topic.csdn.net/u/20090206/23/fcb94d20-c996-4e00-9951-966a509c849d.html

并发时出现的 java.sql.SQLException: 关闭的 Resultset: next
http://topic.csdn.net/u/20100815/16/ecca6662-feb6-4942-8495-6dd67260dc22.html

关于连接池的问题
http://topic.csdn.net/u/20081216/22/ff2d17d9-0722-4c0e-8656-7e8aa3e2ccb2.html


关于 JDBC 连接对象成员变量,或者弄成成员变量而出现的的问题,我在 CSDN 中将以这个帖子作为结束,今后不再参与讨论了。
  • 打赏
  • 举报
回复 1
再说第 101 次,严禁将数据库连接对象 Connection, PreparedStatement, ResultSet 弄成成员变量,更严禁弄成静态的成员变量!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
gaoyangboy 2010-09-15
  • 打赏
  • 举报
回复
public class DBManager {

//用户名

private String user = "";

//密码

private String password = "";

//主机

private String host = "";

//数据库名字

private String database = "";

//private DBManager dbm=null;



/*

private String url="jdbc:mysql://"+host+"/"+"useUnicode=true&characterEncoding=GB2312";

*/

private String url ="";

private Connection con = null;



Statement stmt;

/**

* 私有的构造方法,保证外部不能实例化,只能由DBManager自己能提供自

* 己的实例,并且只能有一个。

* 根据主机、数据库名称、数据库用户名、数据库用户密码取得连接。

* @param host String

* @param database String

* @param user String

* @param password String

*/

private DBManager(String host, String database, String user, String password) {



this.host = host;

this.database = database;

this.user = user;

this.password = password;

//显示中文

this.url = "jdbc:mysql://" + host + "/" + database +

"?useUnicode=true&characterEncoding=GB2312";



try {

Class.forName("org.gjt.mm.mysql.Driver");

}

catch (ClassNotFoundException e) {

System.err.println("class not found:" + e.getMessage());

}



try {

con = DriverManager.getConnection(this.url, this.user, this.password);

//连接类型为ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY

stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_READ_ONLY);

}

catch (SQLException a) {

System.err.println("sql exception:" + a.getMessage());

}

}

/**

* 静态工厂方法,来获得一个DBManager实例

*/

public static DBManager getInstance(String host, String database, String user, String password){

if(dbm==null){

dbm=new DBManager(host,database,user,password);

}

return dbm;

}

/**

* 返回取得的连接

*/

public Connection getCon() {

return con;

}

/**

* 执行一条简单的查询语句

* 返回取得的结果集

*/

public ResultSet executeQuery(String sql) {

ResultSet rs = null;

try {

rs = stmt.executeQuery(sql);

}

catch (SQLException e) {

e.printStackTrace();

}

return rs;

}

/**

* 执行一条简单的更新语句

* 执行成功则返回true

*/

public boolean executeUpdate(String sql) {

boolean v = false;

try {

v = stmt.executeUpdate(sql) > 0 ? true : false;

}

catch (SQLException e) {

e.printStackTrace();

}

finally {

return v;

}

}



}
miracleliu 2010-09-15
  • 打赏
  • 举报
回复
楼上,单例具体怎么写?
能说详细点吗 O(∩_∩)O谢谢
gaoyangboy 2010-09-15
  • 打赏
  • 举报
回复
呵呵。晕死,为什么要设置成静态变量,还不如写一个单例模式,这样不方便些么?
sound9world 2010-09-15
  • 打赏
  • 举报
回复
要设置成静态的方法的话. 构造里面不要调用工具类了

Connection在方法里取得好了..变成局部变量..
jdjwxj 2010-09-15
  • 打赏
  • 举报
回复
应该可以都设置成静态的,忘记了,至少方法可以,以后调用的时候不用实例化对象了!
miracleliu 2010-09-15
  • 打赏
  • 举报
回复
那怎么修改啊?我想设置成静态的方法,有办法吗?
soli11722984 2010-09-15
  • 打赏
  • 举报
回复
会死翘翘
miracleliu 2010-09-15
  • 打赏
  • 举报
回复
你怎么知道我不是用连接池取得connection。。
我的问题是:connection、Resultset,preparedStatement都要设置成静态的。有同步的问题吗?
madFatso 2010-09-15
  • 打赏
  • 举报
回复
配置数据连接池取connection

81,122

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧