2 baidu 28379135 baidu_28379135 于 2015.07.22 16:28 提问

java中多线程下静态connection的问题

普遍观点是不要使用静态的连接,但是……我面临的需求情况是1.数据只查不改2.该连接只在用户登陆时使用,而其他过程有单独的连接池(与登录不是一个库),用池
觉得浪费3.可能在同一时间有几千人同时登陆,而一天内的其他时间登录次数很少。
以下是部分代码:

 public class CWJdbcConnection {
    private static Map<String, String> map = new GetFile().getFile(
            "FcgDriverClassName", "FcgIp", "FcgName", "FcgPasswd");//获取连接信息
    private static int flag = 0;
    private static Connection conn;
    private PreparedStatement ps = null;
    private boolean isClosed = false;

    static {
        try {
            Class.forName(map.get("fcgDriverClassName"));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public CWJdbcConnection() {
        CWJdbcConnection.doConnection(1);
    }

    public ResultSet doSql(String sql) {
        if (conn == null)
            try {
                conn = DriverManager.getConnection(map.get("fcgIp").toString(),
                        map.get("fcgName").toString(), map.get("fcgPasswd")
                                .toString());
            } catch (SQLException e) {
                e.printStackTrace();
            }
        try {
            ps = conn.prepareStatement(sql);
            return ps.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public void close() {
        if (isClosed)
            return;
        if (ps != null)
            try {
                ps.close();
            } catch (SQLException e) {
            }
        isClosed = true;
        CWJdbcConnection.doConnection(-1);
    }

    private synchronized static void doConnection(int a) {
        flag += a;
        if (flag < 0)
            flag = flag / 0;//不要嘲笑我……
        if (flag == 0 && conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn = null;
        }
    }
}

使用方法是:

CWJdbcConnection cw = new CWJdbcConnection();
ResultSet   rs = cw.doSql(sql);
doRS(rs);//进行操作
cw.close();

我在这里向大家请教的是:这个类在并发的情况下会出现什么问题?
PS:在手头没有测试工具和不熟悉程序测试的情况下,我仅仅是开了100个线程,让它们并发读数据,暂时没发现问题,线程全部结束后Connection也都关闭了。但是我不放心啊!!

4个回答

danielinbiti
danielinbiti   Ds   Rxr 2015.07.22 16:37
已采纳
 public ResultSet doSql(String sql) {
        if (conn == null)
            try {//这里并发的时候可能会进入不止1次,对conn初始化进行加锁,这单例初始化很常见,一搜一堆。
                conn = DriverManager.getConnection(map.get("fcgIp").toString(),
                        map.get("fcgName").toString(), map.get("fcgPasswd")
                                .toString());
            } catch (SQLException e) {
                e.printStackTrace();
            }
        try {
            ps = conn.prepareStatement(sql);
            return ps.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
danielinbiti
danielinbiti 回复baidu_28379135: 严谨的态度比较好,注意微观吧。我这用词也不一定都是术语,只能说把一件事过程描述一下。
接近 3 年之前 回复
baidu_28379135
baidu_28379135 我采纳不代表我认可,特此声明。
接近 3 年之前 回复
baidu_28379135
baidu_28379135 回复danielinbiti: 嗯。我找到“物理连接”这个词语的意思了。“当程序执行 SqlConnection.Close 后,物理连接并不会被立即释放”……我承认自己学的是简化版的JDBC。
接近 3 年之前 回复
baidu_28379135
baidu_28379135 我和同事研究了半天“指向”这个词,共识是指向是指“引用指向内存”。话说“物理连接”是什么?是PreparedStatement ?我觉得如果不是我学的JDBC是简化版,就是我和您学的不是一个JDBC。
接近 3 年之前 回复
danielinbiti
danielinbiti 回复baidu_28379135: A与数据库建立了物理连接,你不关闭,怎么断开与物理连接。不是说没有指向A,物理连接不存在了。正相反,物理连接存在,但你已经找不到手工关闭这个物理连接的变量(也就是开关了)
接近 3 年之前 回复
baidu_28379135
baidu_28379135 回复danielinbiti: 依照您的意思,既然没有变量指向A,那我为什么要关闭呢?只要所有Connection都关了不就行了?(其实那个“2个”和“指向”不知道是什么意思)。很抱歉这个解释我不能接受啊!啊!啊!如果没有其他人的解答我会采纳您,请允许我等待一阵子。
接近 3 年之前 回复
danielinbiti
danielinbiti 回复baidu_28379135: 静态指同一个类实例中都是一个值,但不意味着静态变量值不能变。因为java自动回收的,所以这很少考虑内存。如果有帮助,有时间顺手采纳一下。
接近 3 年之前 回复
danielinbiti
danielinbiti 回复baidu_28379135: conn是一个,但你初始化时是生成了2个,conn先指向A,再指向B,最终conn是B,也就是conn.close()是关闭b,那A怎么关闭呢,没有变量指向A了
接近 3 年之前 回复
baidu_28379135
baidu_28379135 A和B的conn不是一样的么?静态的。如果不是一个那单例就没意义了。
接近 3 年之前 回复
danielinbiti
danielinbiti 回复baidu_28379135: conn = DriverManager.getConnection就这段代码,加入A用户进来用了,申请了一个连接A,这时B用户并发进来了,这时候也申请了一个连接B,最终conn指向连接B,也就是连接A在程序里是取不到了。
接近 3 年之前 回复
baidu_28379135
baidu_28379135 没有理解为什么会出现空闲的connection和为什么会有没有close的。??
接近 3 年之前 回复
danielinbiti
danielinbiti 回复baidu_28379135: 因为你这里是只读,也不牵涉修改之类的。也不会出现问题。除非高并发,一下子把你的连接池耗光了。顶多上面代码出现空闲的connect,因为如果并发最终conn指向变了,并发时候生成的没有close掉。
接近 3 年之前 回复
baidu_28379135
baidu_28379135 慢的原因是在最开始conn为null时,设置了100个线程同时申请,于是华丽的堵住了……(该需求需要考虑同时初始化申请的情况)
接近 3 年之前 回复
baidu_28379135
baidu_28379135 谢!使用了双重锁,并且给conn加了volatile,于是只初始化一次了……但是好慢!!有其他方法吗?又及:代码在别的地方有问题吗?
接近 3 年之前 回复
danielinbiti
danielinbiti 回复baidu_28379135: http://blog.csdn.net/xubo578/article/details/6571660这是几种修改方式的优缺点
接近 3 年之前 回复
baidu_28379135
baidu_28379135 确实是这样。我竟然犯了这种错误…………加锁是不行的,是不是有其他方法呢?
接近 3 年之前 回复
baidu_28379135
baidu_28379135   2015.07.22 16:40

确实是这样。我竟然犯了这种错误…………
加锁是不行的,是不是有其他方法呢?

oyljerry
oyljerry   Ds   Rxr 2015.07.22 16:50

单独搞一个数据库连接类,它内部用数据库连接池等,其他线程有数据库查询等,都把数据放到一个队列等,有这个数据库类统一处理,并返回结果等。这样就不需要每个线程都进行数据库操作

baidu_28379135
baidu_28379135 回复oyljerry: 这位同志,请问您真的看了我的提问吗?虽然“提问”里有个“提”,但不是“题目”的“题”。(好吧,我理解太长不看。)
接近 3 年之前 回复
oyljerry
oyljerry 回复baidu_28379135: 就是你不要频繁open,close数据库连接,而是交给统一的处理,它一直打开,直到程序退出再close等、
接近 3 年之前 回复
baidu_28379135
baidu_28379135 实话是完全看不懂在说什么……
接近 3 年之前 回复
sina_2831808769
sina_2831808769   Rxr 2015.07.25 13:54

public ResultSet doSql(String sql) {
if (conn == null)
try {//这里并发的时候可能会进入不止1次,对conn初始化进行加锁,这单例初始化很常见,一搜一堆。
conn = DriverManager.getConnection(map.get("fcgIp").toString(),
map.get("fcgName").toString(), map.get("fcgPasswd")
.toString());
} catch (SQLException e) {
e.printStackTrace();
}
try {
ps = conn.prepareStatement(sql);
return ps.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐
java 获取Connection
package net.e_lian.bpm.util.sync; import java.io.IOException; import java.net.URL; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties
【java项目实战】ThreadLocal封装Connection,实现同一线程共享资源
线程安全一直是程序猿们关注的焦点,多线程也一直是比较让人头疼的话题,想必大家曾经也遇到过各种各种的问题,我就不再累述了。当然,解决方式也有很多,这篇博文给大家提供一种很好的解决线程安全问题的思路。 。。。。。。   ThreadLocal是解决线程安全问题一个很好的思路,在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,并且程序拥有更高的并发性。
关于Java多线程调用同一静态工具类方法时
Java是线程安全的,即对任何方法(包括静态方法)都可以不考虑线程冲突,但有一个前提,就是不能对全局变量(共享资源)进行写操作。 如果有,则需要使用同步机制:synchronized关键字。
为避免多线程Connection混乱使用ThreadLocal来封装事务
上一篇博客总结了动态代理的使用及代码的含义。接下来,继续探究动态代理的实地应用——利用动态代理来封装事务。 首先,要先来回忆一下最原始的封装好的事务的代码,这里在连接数据库时用到了TheadLocal这个类,通过它可以来保证在执行业务逻辑过程中来 保证每一次使用的connection的连接对象都执行的是同一个线程内的connection。 事务的封装 /** * 采用Thr
java基础:集合connection
<!-- @page {margin:2cm} td p {margin-bottom:0cm; direction:ltr; color:#000000; widows:0; orphans:0} td p.western {font-family:"DejaVu Serif",serif; font-size:12pt} td p.cjk {font
探索多线程使用同一个数据库connection的后果
在项目中看到有用到数据库的连接池,心里就思考着为什么需要数据库连接池,只用一个连接会造成什么影响?(只用一个connection)?1  猜想:jdbc的事务是基于connection的,如果多线程共用一个connection,会造成多线程之间的事务相互干扰。(connection.setAutoCommit(false);//connection.commit())2  于是就模仿以下场景来做一...
java database connection 3
java database connection version 3
Java Connection Pool
a book of java connection pool
Java中Connection集合简介
一、Connection概括1. ConnectionAPI2. Connection架构(图片来自网络)3.说明 Connection是一个接口,是高度抽象的集合,它包含了集合的基本操作:对集合元素的增、删、改、查、判断是否为空,获取大小、遍历等操作; 根据Connection接口规范的建议:Collection接口的所有子类(直接子类和间接子类)都必须实现2种构造函数:不带参数的构造函数 和 参
Connection实例是线程安全的吗
关于JDBC中关于Connection的两个疑问:   1.Connection实例是线程安全的吗?     即一个connection实例,在多线程环境中是否可以确保数据操作是安全的? Java代码   private static Connection connection;       上述代码,设计会不会有问题? 一个Connection