Java 传统的DB单例连接效果不佳
我在java应用程序中使用单例数据库连接,下面是我的连接管理器类的代码:Java 传统的DB单例连接效果不佳,java,jdbc,query-performance,Java,Jdbc,Query Performance,我在java应用程序中使用单例数据库连接,下面是我的连接管理器类的代码: public abstract class DatabaseManager { //Static instance of connection, only one will ever exist private static Connection connection = null; private static String dbName="SNfinal";
public abstract class DatabaseManager {
//Static instance of connection, only one will ever exist
private static Connection connection = null;
private static String dbName="SNfinal";
//Returns single instance of connection
public static Connection getConnection(){
//If instance has not been created yet, create it
if(DatabaseManager.connection == null){
initConnection();
}
return DatabaseManager.connection;
}
//Gets JDBC connection instance
private static void initConnection(){
try{
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String connectionUrl = "jdbc:sqlserver://localhost:1433;" +
"databaseName="+dbName+";integratedSecurity=true";
DatabaseManager.connection =
DriverManager.getConnection(connectionUrl);
}
catch (ClassNotFoundException e){
System.out.println(e.getMessage());
System.exit(0);
}
catch (SQLException e){
System.out.println(e.getMessage());
System.exit(0);
}
catch (Exception e){
}
}
public static ResultSet executeQuery(String SQL, String dbName)
{
ResultSet rset = null ;
try {
Statement st = DatabaseManager.getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
rset = st.executeQuery(SQL);
//st.close();
}
catch (SQLException e) {
System.out.println(e.getMessage());
System.exit(0);
}
return rset;
}
public static void executeUpdate(String SQL, String dbName)
{
try {
Statement st = DatabaseManager.getConnection().createStatement();
st.executeUpdate(SQL);
st.close();
}
catch (SQLException e) {
System.out.println(e.getMessage());
System.exit(0);
}
}
}
问题是我的代码在开始时工作得很完美,但当时间过去时,它变得非常缓慢。是什么导致了这个问题?我如何解决这个问题?
在启动时,我的应用程序每秒处理20个查询,运行1小时后达到每秒10个查询,运行3天后达到每10秒1个查询!!
注:我的应用程序是一个单用户应用程序,通过数据库进行许多查询。
注意:下面是我在eclipse.ini中的JVM参数:
--launcher.XXMaxPermSize
512M
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
512m
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.6
-Xms500m
-Xmx4G
-XX:MaxHeapSize=4500m
不幸的是,数据库是远程的,我没有任何监控访问权限来了解那里发生了什么。
以下是我的用法示例:
String count="select count(*) as counter from TSN";
ResultSet rscount=DatabaseManager.executeQuery(count, "SNfinal");
if(rscount.next()) {
numberofNodes=rscount.getInt("counter");
}
语句
和结果集
,但如果您立即关闭它们会更好executeQuery()
方法。
您没有关闭语句
,我想您已经注释了行st.close()
,因为您需要打开ResultSet
以便进一步处理。
我可以看出,您的想法是避免在应用程序中看到重复的JDBC代码,但这不是正确的方法
规则是:关闭结果集
,然后关闭语句
,
否则,您将无法正确地释放资源,并且您将面临所描述的问题
关于如何正确关闭资源,您可以找到一个很好的解释(请记住,在您的情况下,您不需要
(关闭连接)
编辑:
例如:
试试看{
语句st=DatabaseManager.getConnection().createStatement(ResultSet.TYPE\u SCROLL\u不敏感,ResultSet.CONCUR\u只读);
ResultSet rsCount=st.executeQuery(count);//count=“选择count(*)作为TSN中的计数器”;
if(rsCount.next()){
numberofNodes=rscount.getInt(“计数器”);
}
}捕获(SQLE异常){
//日志异常
}最后{
rsCount.close();
圣克洛斯();
}
< /代码> 您应该考虑使用一个断开的结果集,如缓存行集
CachedRowSet实现ResultSet,因此它的行为应该类似于ResultSet
除了这些更改之外,我建议您使用池数据源来获取连接并关闭它们,而不是保留一个打开的连接
或者,如果您不是java7、bonecp或c3po
编辑:
为了回答您的问题,这解决了您的问题,因为CachedRowSetImpl
在使用时不会保持与数据库的连接。
这允许您在填充CachedRowSetImpl
后关闭Resultset
和语句
希望这能回答你的问题 在类中使用@singleton即使对于单用户应用程序,我建议使用一个连接池(例如BoneCP)和一个非常小的池。只需获得一个连接并在完成后关闭它,池将处理检查连接、在连接打开很长时间后替换连接等。它还保护您的代码不受以前执行的未提交事务等的影响。实际上,我需要尽可能快地运行查询。我第一次使用c3p0,但它在我的应用程序中的性能确实不如传统的单例连接(大约慢90%)。为什么您的st.close()
被注释掉了?您是否正确地关闭了结果集
?在正确处理资源时,JDBC并不容易使用。我建议您使用像SpringJDBC及其JdbcTemplate
这样的包装器库。此外,您关于连接池速度慢的论点似乎有点奇怪。当涉及到DB通信时,一些方法调用开销是微不足道的。但我同意,如果您的用例不需要连接池,就不需要它。您可能缺少的唯一优势是连接验证。我无法关闭结果集或语句,因为我要运行多个查询。当我关闭它们时,我得到了错误。分配的内存没有满,所以不可能是内存问题。我认为这是由其他原因引起的,但我不知道是什么原因。我坚持认为您的executeQuery()方法设计得不好。尝试进行一些重构,以便关闭语句。我不知道你的应用程序代码,但它应该很容易替换每个DatabaseManager.executeQuery()方法调用,用于树语句(1->get Connection,2->create Statement,3->get ResultSet),允许你关闭结果集,尤其是语句。我添加了一个如何调用此方法的示例,请您解释一下您对这个示例的想法好吗?在我的代码的所有部分中更改它确实很耗时,所以我选择了Summit解决方案。我想知道为什么这个解决方案完全解决了我的问题!!如果是数据库问题,为什么它应该随着时间的推移而扩展?因为您的数据集在不断增长,查询100M记录肯定比100K记录慢。不,它没有增长,我一个记录一个记录地执行查询过程!请问为什么这个解决方案解决了我的问题?!我监控了这两种方法中的jvm资源使用情况。从资源管理的角度来看,默认方法似乎更好,因此它不会因为资源的高使用率而导致!!
public static ResultSet executeQuery(String SQL, String dbName)
{
CachedRowSetImpl crs = new CachedRowSetImpl();
ResultSet rset = null ;
Statement st = null;
try {
st = DatabaseManager.getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
rset = st.executeQuery(SQL);
crs.populate(rset);
}
catch (SQLException e) {
System.out.println(e.getMessage());
System.exit(0);
}finally{
rset.close();
st.close();
}
return crs;
}