1 5 package snaq.db; 6 7 import snaq.util.Reusable; 8 import java.sql.*; 9 import java.util.*; 10 11 18 public final class CacheConnection implements Connection, StatementListener, Reusable 19 { 20 private static int DEFAULT_RESULTSET_TYPE = ResultSet.TYPE_FORWARD_ONLY; 22 private static int DEFAULT_RESULTSET_CONCURRENCY = ResultSet.CONCUR_READ_ONLY; 23 private static int DEFAULT_RESULTSET_HOLDABILITY = ResultSet.HOLD_CURSORS_OVER_COMMIT; 24 25 protected ConnectionPool pool; 26 protected Connection con; 27 protected List ss = new ArrayList(); 29 protected List ssUsed = new ArrayList(); 30 protected Map ps = new HashMap(); 32 protected List psUsed = new ArrayList(); 33 protected Map cs = new HashMap(); 35 protected List csUsed = new ArrayList(); 36 protected List nonCachable = new ArrayList(); 38 private boolean cacheS, cacheP, cacheC; 40 private int ssReq, ssHit; 41 private int psReq, psHit; 42 private int csReq, csHit; 43 private boolean open = true; 44 45 46 49 public CacheConnection(ConnectionPool pool, Connection con) 50 { 51 this.pool = pool; 52 this.con = con; 53 setCacheAll(true); 54 ssReq = ssHit = psReq = psHit = csReq = csHit = 0; 55 } 56 57 60 void setOpen() 61 { 62 open = true; 63 } 64 65 68 boolean isOpen() 69 { 70 return open; 71 } 72 73 76 public void setCacheStatements(boolean cache) 77 { 78 if (cacheS && !cache) 80 { 81 try { flushSpareStatements(); } 82 catch (SQLException sqle) { pool.log(sqle); } 83 } 84 this.cacheS = cache; 85 } 86 87 90 public void setCachePreparedStatements(boolean cache) 91 { 92 if (cacheP && !cache) 94 { 95 try { flushSparePreparedStatements(); } 96 catch (SQLException sqle) { pool.log(sqle); } 97 } 98 this.cacheP = cache; 99 } 100 101 104 public void setCacheCallableStatements(boolean cache) 105 { 106 if (cacheC && !cache) 108 { 109 try { flushSpareCallableStatements(); } 110 catch (SQLException sqle) { pool.log(sqle); } 111 } 112 this.cacheC = cache; 113 } 114 115 118 public void setCacheAll(boolean cache) 119 { 120 setCacheStatements(cache); 121 setCachePreparedStatements(cache); 122 setCacheCallableStatements(cache); 123 } 124 125 126 public boolean isCachingAllStatements() { return cacheS && cacheP && cacheC; } 127 128 129 public boolean isCachingStatements() { return cacheS; } 130 131 132 public boolean isCachingPreparedStatements() { return cacheP; } 133 134 135 public boolean isCachingCallableStatements() { return cacheC; } 136 137 145 public Connection getRawConnection() 146 { 147 return con; 148 } 149 150 154 155 public Statement createStatement() throws SQLException 156 { 157 return createStatement(DEFAULT_RESULTSET_TYPE, DEFAULT_RESULTSET_CONCURRENCY, DEFAULT_RESULTSET_HOLDABILITY); 158 } 159 160 161 public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException 162 { 163 return createStatement(resultSetType, resultSetConcurrency, DEFAULT_RESULTSET_HOLDABILITY); 164 } 165 166 167 public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException 168 { 169 CachedStatement cs = null; 170 if (!cacheS) 171 { 172 cs = new CachedStatement(con.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)); 173 cs.setStatementListener(this); 174 cs.setOpen(); 175 } 176 else 177 { 178 synchronized(ss) 179 { 180 ssReq++; 181 for (Iterator it = ss.iterator(); it.hasNext();) 183 { 184 CachedStatement x = (CachedStatement)it.next(); 185 if (x.getResultSetType() == resultSetType && 186 x.getResultSetConcurrency() == resultSetConcurrency && 187 x.getResultSetHoldability() == resultSetHoldability) 188 { 189 cs = x; 190 it.remove(); 191 } 192 } 193 if (cs != null) 195 { 196 cs.setOpen(); 197 ssHit++; 198 if (pool.isDebug()) 199 pool.log("Statement cache hit [" + cs.getParametersString() + "] - " + calcHitRate(ssHit, ssReq)); 200 } 201 else 202 { 203 cs = new CachedStatement(con.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)); 204 cs.setStatementListener(this); 205 cs.setOpen(); 206 if (pool.isDebug()) 207 pool.log("Statement cache miss [" + cs.getParametersString() + "] - " + calcHitRate(ssHit, ssReq)); 208 } 209 } 210 } 211 ssUsed.add(cs); 212 return cs; 213 } 214 215 216 public PreparedStatement prepareStatement(String sql) throws SQLException 217 { 218 return prepareStatement(sql, DEFAULT_RESULTSET_TYPE, DEFAULT_RESULTSET_CONCURRENCY, DEFAULT_RESULTSET_HOLDABILITY); 219 } 220 221 222 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException 223 { 224 return prepareStatement(sql, resultSetType, resultSetConcurrency, DEFAULT_RESULTSET_HOLDABILITY); 225 } 226 227 230 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException 231 { 232 CachedPreparedStatement cps = null; 233 if (!cacheP) 234 { 235 cps = new CachedPreparedStatement(sql, con.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); 236 cps.setStatementListener(this); 237 cps.setOpen(); 238 } 239 else 240 { 241 synchronized(ps) 242 { 243 psReq++; 244 List list = (List)ps.get(sql); 246 if (list != null && !list.isEmpty()) 247 { 248 for (Iterator it = list.iterator(); it.hasNext();) 250 { 251 CachedPreparedStatement x = (CachedPreparedStatement)it.next(); 252 if (x.getResultSetType() == resultSetType && 253 x.getResultSetConcurrency() == resultSetConcurrency && 254 x.getResultSetHoldability() == resultSetHoldability) 255 { 256 cps = x; 257 it.remove(); 258 } 259 } 260 if (list.isEmpty()) 262 ps.remove(sql); 263 } 264 if (cps != null) 266 { 267 cps.setOpen(); 268 psHit++; 269 if (pool.isDebug()) 270 pool.log("PreparedStatement cache hit [" + sql + "," + cps.getParametersString() + "] - " + calcHitRate(psHit, psReq)); 271 } 272 else 273 { 274 cps = new CachedPreparedStatement(sql, con.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); 275 cps.setStatementListener(this); 276 cps.setOpen(); 277 if (pool.isDebug()) 278 pool.log("PreparedStatement cache miss [" + sql + "," + cps.getParametersString() + "] - " + calcHitRate(psHit, psReq)); 279 } 280 } 281 } 282 psUsed.add(cps); 283 return cps; 284 } 285 286 287 public CallableStatement prepareCall(String sql) throws SQLException 288 { 289 return prepareCall(sql, DEFAULT_RESULTSET_TYPE, DEFAULT_RESULTSET_CONCURRENCY, DEFAULT_RESULTSET_HOLDABILITY); 290 } 291 292 293 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException 294 { 295 return prepareCall(sql, resultSetType, resultSetConcurrency, DEFAULT_RESULTSET_HOLDABILITY); 296 } 297 298 301 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException 302 { 303 CachedCallableStatement ccs = null; 304 if (!cacheC) 305 { 306 ccs = new CachedCallableStatement(sql, con.prepareCall(sql)); 307 ccs.setStatementListener(this); 308 ccs.setOpen(); 309 } 310 else 311 { 312 synchronized(cs) 313 { 314 csReq++; 315 List list = (List)cs.get(sql); 317 if (list != null && !list.isEmpty()) 318 { 319 for (Iterator it = list.iterator(); it.hasNext();) 321 { 322 CachedCallableStatement x = (CachedCallableStatement)it.next(); 323 if (x.getResultSetType() == resultSetType && 324 x.getResultSetConcurrency() == resultSetConcurrency && 325 x.getResultSetHoldability() == resultSetHoldability) 326 { 327 ccs = x; 328 it.remove(); 329 } 330 } 331 if (list.isEmpty()) 333 cs.remove(sql); 334 } 335 if (ccs != null) 337 { 338 ccs.setOpen(); 339 csHit++; 340 if (pool.isDebug()) 341 pool.log("CallableStatement cache hit [" + sql + "," + ccs.getParametersString() + "] - " + calcHitRate(csHit, csReq)); 342 } 343 else 344 { 345 CallableStatement st = con.prepareCall(sql); 346 ccs = new CachedCallableStatement(sql, st); 347 ccs.setStatementListener(this); 348 ccs.setOpen(); 349 if (pool.isDebug()) 350 pool.log("CallableStatement cache miss [" + sql + "," + ccs.getParametersString() + "] - " + calcHitRate(csHit, csReq)); 351 } 352 } 353 } 354 csUsed.add(ccs); 355 return ccs; 356 } 357 358 361 public void statementClosed(CachedStatement s) throws SQLException 362 { 363 if (s instanceof CachedPreparedStatement) 364 { 365 synchronized(ps) 366 { 367 String key = ((CachedPreparedStatement)s).getSQLString(); 368 psUsed.remove(s); 369 if (!cacheP) 371 s.release(); 372 else { 374 try 375 { 376 s.recycle(); 377 List list = (List)ps.get(key); 379 if (list == null) 380 { 381 list = new ArrayList(); 382 ps.put(key, list); 383 } 384 list.add(s); 385 } 386 catch (SQLException sqle) 387 { 388 s.release(); 389 } 390 } 391 } 392 } 393 else if (s instanceof CachedCallableStatement) 394 { 395 synchronized(cs) 396 { 397 String key = ((CachedCallableStatement)s).getSQLString(); 398 csUsed.remove(s); 399 if (!cacheC) 401 s.release(); 402 else { 404 try 405 { 406 s.recycle(); 407 List list = (List)cs.get(key); 409 if (list == null) 410 { 411 list = new ArrayList(); 412 cs.put(key, list); 413 } 414 list.add(s); 415 } 416 catch (SQLException sqle) 417 { 418 s.release(); 419 } 420 } 421 } 422 } 423 else if (s instanceof CachedStatement) 424 { 425 synchronized(ss) 426 { 427 ssUsed.remove(s); 428 if (!cacheS) 430 s.release(); 431 else { 433 try 434 { 435 s.recycle(); 436 ss.add(s); 437 } 438 catch (SQLException sqle) 439 { 440 s.release(); 441 } 442 } 443 } 444 } 445 } 446 447 private String calcHitRate(int hits, int reqs) 448 { 449 return (reqs == 0) ? "" : (((float)hits / reqs) * 100f) + "% hit rate"; 450 } 451 452 public String nativeSQL(String sql) throws SQLException 453 { 454 return con.nativeSQL(sql); 455 } 456 457 public void setAutoCommit(boolean autoCommit) throws SQLException 458 { 459 con.setAutoCommit(autoCommit); 460 } 461 462 public boolean getAutoCommit() throws SQLException 463 { 464 return con.getAutoCommit(); 465 } 466 467 public void commit() throws SQLException 468 { 469 con.commit(); 470 } 471 472 public void rollback() throws SQLException 473 { 474 con.rollback(); 475 } 476 477 480 public void recycle() throws SQLException 481 { 482 if (cacheS) 484 { 485 int count = (ssUsed != null) ? ssUsed.size() : 0; 486 if (count > 0) 487 { 488 if (pool.isDebug()) 489 pool.log("Cleaning " + count + " cached Statement" + (count > 1 ? "s" : "")); 490 synchronized(ssUsed) 491 { 492 while (!ssUsed.isEmpty()) 493 ((Statement)ssUsed.remove(0)).close(); 494 } 495 } 496 } 497 else 498 { 499 flushOpenStatements(); 500 flushSpareStatements(); 501 } 502 503 if (cacheP) 505 { 506 int count = (psUsed != null) ? psUsed.size() : 0; 507 if (count > 0) 508 { 509 if (pool.isDebug()) 510 pool.log("Cleaning " + count + " cached PreparedStatement" + (count > 1 ? "s" : "")); 511 synchronized(psUsed) 512 { 513 while (!psUsed.isEmpty()) 514 ((CachedPreparedStatement)psUsed.remove(0)).close(); 515 } 516 } 517 } 518 else 519 { 520 flushOpenPreparedStatements(); 521 flushSparePreparedStatements(); 522 } 523 524 if (cacheC) 526 { 527 int count = (csUsed != null) ? csUsed.size() : 0; 528 if (count > 0) 529 { 530 if (pool.isDebug()) 531 pool.log("Cleaning " + count + " cached CallableStatement" + (count > 1 ? "s" : "")); 532 synchronized(csUsed) 533 { 534 while (!csUsed.isEmpty()) 535 ((CachedCallableStatement)csUsed.remove(0)).close(); 536 } 537 } 538 } 539 else 540 { 541 flushOpenCallableStatements(); 542 flushSpareCallableStatements(); 543 } 544 545 flushOpenNonCachableStatements(); 547 548 if (!getAutoCommit()) 550 { 551 try { rollback(); } 552 catch (SQLException sqle) { pool.log(sqle); } 553 setAutoCommit(true); 554 } 555 clearWarnings(); 556 557 Map tm = getTypeMap(); 559 if (tm != null) 560 tm.clear(); 561 } 562 563 566 public void close() throws SQLException 567 { 568 if (!open) 569 throw new SQLException("Connection already closed"); 570 open = false; 571 pool.freeConnection(this); 573 } 574 575 578 public int getSpareStatementCount() 579 { 580 return ss.size(); 581 } 582 583 587 public int getOpenStatementCount() 588 { 589 return ssUsed.size(); 590 } 591 592 595 public int getSparePreparedStatementCount() 596 { 597 int count = 0; 598 synchronized(ps) 599 { 600 for (Iterator it = ps.values().iterator(); it.hasNext();) 601 count += ((List)it.next()).size(); 602 } 603 return count; 604 } 605 606 610 public int getOpenPreparedStatementCount() 611 { 612 return psUsed.size(); 613 } 614 615 618 public int getSpareCallableStatementCount() 619 { 620 int count = 0; 621 synchronized(cs) 622 { 623 for (Iterator it = cs.values().iterator(); it.hasNext();) 624 count += ((List)it.next()).size(); 625 } 626 return count; 627 } 628 629 632 public int getOpenCallableStatementCount() 633 { 634 return csUsed.size(); 635 } 636 637 645 public int getOpenNonCachableStatementCount() 646 { 647 return nonCachable.size(); 648 } 649 650 653 protected void flushSpareStatements() throws SQLException 654 { 655 int count = (ss != null) ? ss.size() : 0; 657 if (count > 0) 658 { 659 if (pool.isDebug()) 660 pool.log("Closing " + count + " cached Statement" + (count > 1 ? "s" : "")); 661 synchronized(ss) 662 { 663 while (!ss.isEmpty()) 664 ((CachedStatement)ss.remove(0)).release(); 665 } 666 } 667 } 668 669 672 protected void flushOpenStatements() throws SQLException 673 { 674 int count = (ssUsed != null) ? ssUsed.size() : 0; 676 if (count > 0) 677 { 678 if (pool.isDebug()) 679 pool.log("Closing " + count + " open Statement" + (count > 1 ? "s" : "")); 680 synchronized(ssUsed) 681 { 682 while (!ssUsed.isEmpty()) 683 ((CachedStatement)ssUsed.remove(0)).release(); 684 } 685 } 686 } 687 688 691 protected void flushSparePreparedStatements() throws SQLException 692 { 693 int count = (ps != null) ? ps.size() : 0; 695 if (count > 0) 696 { 697 if (pool.isDebug()) 698 pool.log("Closing " + count + " cached PreparedStatement" + (count > 1 ? "s" : "")); 699 synchronized(ps) 700 { 701 for (Iterator iter = ps.values().iterator(); iter.hasNext();) 702 { 703 List list = (List)iter.next(); 704 for (Iterator it = list.iterator(); it.hasNext();) 705 ((CachedPreparedStatement)it.next()).release(); 706 } 707 ps.clear(); 708 } 709 } 710 } 711 712 715 protected void flushOpenPreparedStatements() throws SQLException 716 { 717 int count = (psUsed != null) ? psUsed.size() : 0; 719 if (count > 0) 720 { 721 if (pool.isDebug()) 722 pool.log("Closing " + count + " open PreparedStatement" + (count > 1 ? "s" : "")); 723 synchronized(psUsed) 724 { 725 while (!psUsed.isEmpty()) 726 ((CachedPreparedStatement)psUsed.remove(0)).release(); 727 } 728 } 729 } 730 731 734 protected void flushSpareCallableStatements() throws SQLException 735 { 736 int count = (cs != null) ? cs.size() : 0; 738 if (count > 0) 739 { 740 if (pool.isDebug()) 741 pool.log("Closing " + count + " cached CallableStatement" + (count > 1 ? "s" : "")); 742 synchronized(cs) 743 { 744 for (Iterator iter = cs.values().iterator(); iter.hasNext();) 745 { 746 List list = (List)iter.next(); 747 for (Iterator it = list.iterator(); it.hasNext();) 748 ((CachedCallableStatement)it.next()).release(); 749 } 750 cs.clear(); 751 } 752 } 753 } 754 755 758 protected void flushOpenCallableStatements() throws SQLException 759 { 760 int count = (csUsed != null) ? csUsed.size() : 0; 762 if (count > 0) 763 { 764 if (pool.isDebug()) 765 pool.log("Closing " + count + " open CallableStatement" + (count > 1 ? "s" : "")); 766 synchronized(csUsed) 767 { 768 while (!csUsed.isEmpty()) 769 ((CachedCallableStatement)csUsed.remove(0)).release(); 770 } 771 } 772 } 773 774 777 protected void flushOpenNonCachableStatements() throws SQLException 778 { 779 int count = (nonCachable != null) ? nonCachable.size() : 0; 780 if (count > 0) 781 { 782 if (pool.isDebug()) 783 pool.log("Closing " + count + " open non-cachable Statement" + (count > 1 ? "s" : "")); 784 synchronized(nonCachable) 785 { 786 while (!nonCachable.isEmpty()) 787 { 788 try { ((Statement)nonCachable.remove(0)).close(); } 789 catch (SQLException sqle) { pool.log(sqle); } 790 } 791 } 792 } 793 } 794 795 798 public void release() throws SQLException 799 { 800 open = false; 801 ArrayList list = new ArrayList(); 802 803 try { flushSpareStatements(); flushOpenStatements(); } 804 catch (SQLException e) { list.add(e); } 805 try { flushSparePreparedStatements(); flushOpenPreparedStatements(); } 806 catch (SQLException e) { list.add(e); } 807 try { flushSpareCallableStatements(); flushOpenCallableStatements(); } 808 catch (SQLException e) { list.add(e); } 809 try { flushOpenNonCachableStatements(); } 810 catch (SQLException e) { list.add(e); } 811 812 try { con.close(); } 813 catch (SQLException e) { list.add(e); } 814 815 if (!list.isEmpty()) 816 { 817 SQLException sqle = new SQLException("Problem releasing connection resources"); 818 for (Iterator it = list.iterator(); it.hasNext();) 819 { 820 SQLException x = (SQLException)it.next(); 821 sqle.setNextException(x); 822 sqle = x; 823 } 824 throw sqle; 825 } 826 } 827 828 public boolean isClosed() throws SQLException 829 { 830 return con.isClosed(); 831 } 832 833 public DatabaseMetaData getMetaData() throws SQLException 834 { 835 return con.getMetaData(); 836 } 837 838 public void setReadOnly(boolean readOnly) throws SQLException 839 { 840 con.setReadOnly(readOnly); 841 } 842 843 public boolean isReadOnly() throws SQLException 844 { 845 return con.isReadOnly(); 846 } 847 848 public void setCatalog(String catalog) throws SQLException 849 { 850 con.setCatalog(catalog); 851 } 852 853 public String getCatalog() throws SQLException 854 { 855 return con.getCatalog(); 856 } 857 858 public void setTransactionIsolation(int level) throws SQLException 859 { 860 con.setTransactionIsolation(level); 861 } 862 863 public int getTransactionIsolation() throws SQLException 864 { 865 return con.getTransactionIsolation(); 866 } 867 868 public SQLWarning getWarnings() throws SQLException 869 { 870 return con.getWarnings(); 871 } 872 873 public void clearWarnings() throws SQLException 874 { 875 con.clearWarnings(); 876 } 877 878 public Map getTypeMap() throws SQLException 879 { 880 return con.getTypeMap(); 881 } 882 883 public void setTypeMap(Map map) throws SQLException 884 { 885 con.setTypeMap(map); 886 } 887 888 892 public void setHoldability(int holdability) throws SQLException 893 { 894 con.setHoldability(holdability); 895 } 896 897 public int getHoldability() throws SQLException 898 { 899 return con.getHoldability(); 900 } 901 902 public Savepoint setSavepoint() throws SQLException 903 { 904 return con.setSavepoint(); 905 } 906 907 public Savepoint setSavepoint(String name) throws SQLException 908 { 909 return con.setSavepoint(name); 910 } 911 912 public void rollback(Savepoint savepoint) throws SQLException 913 { 914 con.rollback(savepoint); 915 } 916 917 public void releaseSavepoint(Savepoint savepoint) throws SQLException 918 { 919 con.releaseSavepoint(savepoint); 920 } 921 922 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException 923 { 924 PreparedStatement x = con.prepareStatement(sql, autoGeneratedKeys); 925 nonCachable.add(x); 926 return x; 927 } 928 929 public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException 930 { 931 PreparedStatement x = con.prepareStatement(sql, columnIndexes); 932 nonCachable.add(x); 933 return x; 934 } 935 936 public PreparedStatement prepareStatement(String sql, String [] columnNames) throws SQLException 937 { 938 PreparedStatement x = con.prepareStatement(sql, columnNames); 939 nonCachable.add(x); 940 return x; 941 } 942 } | Popular Tags |