`

JDBC查询缓存

    博客分类:
  • JAVA
阅读更多

原文地址:http://blog.csdn.net/shajunxing/archive/2010/01/06/5144950.aspx

前段时间因为实际需要,写了一个简单的JDBC查询缓存,发表在这里:

http://topic.csdn.net/u/20091209/18/e366812c-5cc6-47b2-83d6-f78350206781.html?1092065064


经过一段时间的使用,发现很严重的问题:缓存的CachedRowSet因为是通过游标访问记录的,所以如果多线程同时操作一个CachedRowSet,游标就会冲突,为了解决这个问题,我在上面补了很多代码,非常非常难看!


今天重拾旧题,也多亏了“火龙果@菜菜宝宝”的点拨,使用了Apache Commons DbUtil的List格式的结果集代替了CachedRowSet,这样游标冲突就避免了(多线程肯定是拥有独立的迭代器的,而不像游标只有一个),然 后再使用Apache Commons Collections中的LRUMap以Collections.synchronizedMap()方法包装成线程安全的Map作为缓存,懒得自己写 线程安全的代码了,呵呵。最后,连接池使用的是C3P0。


废话少说,上代码:

import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;
import org.apache.commons.collections.map.LRUMap;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapListHandler;

/**
 * JDBC查询缓存
 * @author shajunxing
 */
public class QueryCache {

    private static final Logger logger = Logger.getLogger(QueryCache.class.getName());
    private Map<String, List<Map<String, Object>>> cache = null;
    private String driver;
    private String url;
    private String user;
    private String password;
    private ComboPooledDataSource cpds;
    private AtomicLong visitedCount = new AtomicLong(0);
    private AtomicLong hitCount = new AtomicLong(0);

    /**
     * 默认构造函数
     * @param driver JDBC驱动类
     * @param url 连接字符串
     * @param user 用户名
     * @param password 口令
     * @param maxSize 查询缓存大小
     */
    public QueryCache(String driver, String url, String user, String password, int maxSize) {
        this.driver = driver;
        this.url = url;
        this.user = user;
        this.password = password;
        cache = Collections.synchronizedMap(new LRUMap(maxSize));
        cpds = new ComboPooledDataSource();
        cpds.setJdbcUrl(url);
        cpds.setUser(user);
        cpds.setPassword(password);
        try {
            Class.forName(driver);
            cpds.setDriverClass(driver);
        } catch (ClassNotFoundException ex) {
            logger.severe(ex.toString());
        } catch (PropertyVetoException ex) {
            logger.severe(ex.toString());
        }
    }

    public void clear() {
        cache.clear();
    }

    /**
     * 非缓存查询
     * @param sql SQL语句
     * @param pooled 是否使用连接池
     * @return 查询结果
     */
    public List<Map<String, Object>> query(String sql, boolean pooled) {
        Connection conn = null;
        try {
            if (pooled) {
                conn = cpds.getConnection();
            } else {
                conn = DriverManager.getConnection(url, user, password);
            }
            return new QueryRunner().query(conn, sql, new MapListHandler());
        } catch (SQLException ex) {
            logger.severe(ex.toString());
            return null;
        } finally {
            DbUtils.closeQuietly(conn);
        }
    }

    /**
     * 缓存查询
     * @param sql SQL语句
     * @param pooled 是否使用连接池
     * @return 查询结果
     */
    public List<Map<String, Object>> cachedQuery(String sql, boolean pooled) {
        visitedCount.incrementAndGet();
        if (cache.containsKey(sql)) {
            hitCount.incrementAndGet();
            return cache.get(sql);
        } else {
            List<Map<String, Object>> result = query(sql, pooled);
            cache.put(sql, result);
            return result;
        }
    }

    public long getVisitedCount() {
        return visitedCount.get();
    }

    public long getHitCount() {
        return hitCount.get();
    }

    public int getSize() {
        return cache.size();
    }

    public Set<String> getKeySet() {
        return cache.keySet();
    }
}


进行了两个测试:


其一测试了下面7种情形:

A单线程,无连接池、无查询缓存

B单线程,有连接池、无查询缓存

C单线程,无连接池、有查询缓存

D单线程,有连接池、有查询缓存

E多线程,有连接池、无查询缓存

F多线程,无连接池、有查询缓存

G多线程,有连接池、有查询缓存

注:多线程,无连接池、无查询缓存的情况因为数据库最大连接数的限制,不做测试。

import java.util.logging.Logger;

/**
 * 性能测试1
 * @author shajunxing
 */
public class PerformanceTest {

    private static final Logger logger = Logger.getLogger(PerformanceTest.class.getName());
    private static final String driver = "XXX";
    private static final String url = "XXX";
    private static final String user = "XXX";
    private static final String password = "XXX";
    private static final String sql = "XXX";
    private static final int loopCount = 1000;
    private static QueryCache cache = new QueryCache(driver, url, user, password, 1000000);

    private static void testQuery() {
        for (int i = 0; i < loopCount; i++) {
            cache.query(sql, false);
        }
    }

    private static void testPooledQuery() {
        for (int i = 0; i < loopCount; i++) {
            cache.query(sql, true);
        }
    }

    private static void testCachedQuery() {
        for (int i = 0; i < loopCount; i++) {
            cache.cachedQuery(sql, false);
        }
    }

    private static void testCachedPooledQuery() {
        for (int i = 0; i < loopCount; i++) {
            cache.cachedQuery(sql, true);
        }
    }

    private static void testPooledQueryMS() {
        Thread[] threads = new Thread[loopCount];
        for (int i = 0; i < loopCount; i++) {
            Thread thread = new Thread(new Runnable() {

                public void run() {
                    cache.query(sql, true);
                }
            });
            thread.start();
            threads[i] = thread;
        }
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException ex) {
                logger.severe(ex.toString());
            }
        }
    }

    private static void testCachedQueryMS() {
        Thread[] threads = new Thread[loopCount];
        for (int i = 0; i < loopCount; i++) {
            Thread thread = new Thread(new Runnable() {

                public void run() {
                    cache.cachedQuery(sql, false);
                }
            });
            thread.start();
            threads[i] = thread;
        }
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException ex) {
                logger.severe(ex.toString());
            }
        }
    }

    private static void testCachedPooledQueryMS() {
        Thread[] threads = new Thread[loopCount];
        for (int i = 0; i < loopCount; i++) {
            Thread thread = new Thread(new Runnable() {

                public void run() {
                    cache.cachedQuery(sql, true);
                }
            });
            thread.start();
            threads[i] = thread;
        }
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException ex) {
                logger.severe(ex.toString());
            }
        }
    }

    public static void main(String[] args) {
        testQuery();
        testPooledQuery();
        testCachedQuery();
        testCachedPooledQuery();
        testPooledQueryMS();
        testCachedQueryMS();
        testCachedPooledQueryMS();
    }
}


使用NetBeans Profiler做三次测试,结果如下:


从中可以得出结论:

单线程的四种方式时间比大约为A : B : C : D = 15000 : 2000 : 15 : 1;
多线程三种方式耗时差不多,估计在线程的创建以及调度上花费了很多时间。

其二测试了缓存在模拟的实际情况下面的增长以及命中率等数值。

方法是首先通过JDBC元数据操作获取数据库中的所有表名和各个表的字段名,然后将字段名和表名随机组合构造SQL语句,测试10000次(单线程,在我们的项目中多线程同时访问的情况很少),每100次统计一下缓存的命中率等信息,代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.logging.Logger;
import org.apache.commons.dbutils.DbUtils;

/**
 * 性能测试2
 * @author shajunxing
 */
public class PerformanceTest2 {

    private static final Logger logger = Logger.getLogger(PerformanceTest2.class.getName());
    private static final String driver = "XXX";
    private static final String url = "XXX";
    private static final String user = "XXX";
    private static final String password = "XXX";
    private static QueryCache cache = new QueryCache(driver, url, user, password, 1000000);
    private static Map<String, List<String>> tables = new HashMap<String, List<String>>();
    private static List<String> tableNames = new LinkedList<String>();
    private static Random rand = new Random(Calendar.getInstance().getTimeInMillis());

    private static void getTables() {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        DbUtils.loadDriver(driver);

        try {
            conn = DriverManager.getConnection(url, user, password);
            // 获取所有表名称
            logger.info("获取所有表名称");
            try {
                DatabaseMetaData dbMeta = conn.getMetaData();
                rs = dbMeta.getTables(null, null, null, new String[]{"TABLE"});
                if (rs != null) {
                    while (rs.next()) {
                        tables.put(rs.getString("TABLE_NAME"), new LinkedList<String>());
                    }
                }
            } catch (SQLException ex) {
                logger.severe(ex.toString());
            } finally {
                DbUtils.closeQuietly(rs);
            }

            // 获取所有表的字段名称
            Set<String> illegalTables = new HashSet<String>();
            for (String tableName : tables.keySet()) {
                logger.info(String.format("获取表%s的字段", tableName));
                List<String> tableColumns = tables.get(tableName);
                try {
                    stmt = conn.createStatement();
                    rs = stmt.executeQuery(String.format("select * from %s where rownum=1", tableName));
                    ResultSetMetaData rsMeta = rs.getMetaData();
                    for (int i = 1; i <= rsMeta.getColumnCount(); i++) {
                        String columnName = rsMeta.getColumnName(i);
                        tableColumns.add(columnName);
                    }
                } catch (SQLException ex) {
                    logger.severe(String.format("获取表%s的字段失败:%s", tableName, ex.toString()));
                    illegalTables.add(tableName);
                } finally {
                    DbUtils.closeQuietly(rs);
                    DbUtils.closeQuietly(stmt);
                }
            }

            // 删除非法的表
            for (String illegal : illegalTables) {
                tables.remove(illegal);
            }

            // 表名列表
            for (String tableName : tables.keySet()) {
                tableNames.add(tableName);
            }

        } catch (SQLException ex) {
            logger.severe(ex.toString());
        } finally {
            DbUtils.closeQuietly(conn);
        }
    }

    public static void main(String[] args) {
        // 获取所有的表和字段名
        getTables();

        // 打印所有的表和字段名
        for (String tableName : tables.keySet()) {
            System.out.println(tableName);
            for (String columnName : tables.get(tableName)) {
                System.out.println("    " + columnName);
            }
            System.out.println();
        }

        // 用随机组合的SQL语句测试
        long lastVisitedCount = 0;
        long lastHitCount = 0;
        long lastTime = Calendar.getInstance().getTimeInMillis();
        for (int i = 0; i < 100; i++) {
            // 每100次循环统计一次
            for (int j = 0; j < 100; j++) {
                String tableName = tableNames.get(rand.nextInt(tableNames.size()));
                List<String> columnNames = tables.get(tableName);
                String columnName = columnNames.get(rand.nextInt(columnNames.size()));
                String sql = String.format("select \"%s\" from \"%s\"", columnName, tableName);
                cache.cachedQuery(sql, true);
            }
            long visitedCount = cache.getVisitedCount();
            long hitCount = cache.getHitCount();
            long time = Calendar.getInstance().getTimeInMillis();
            System.out.println(String.format("缓存总访问数:%d,总命中数:%d,当前大小:%d,命中率:%.2f%%,耗时:%d毫秒",
                    visitedCount,
                    hitCount,
                    cache.getSize(),
                    100.0 * (hitCount - lastHitCount) / (visitedCount - lastVisitedCount),
                    time - lastTime));
            lastVisitedCount = visitedCount;
            lastHitCount = hitCount;
            lastTime = time;
        }

        // 按任意键继续
        System.out.println("按任意键继续...");
        try {
            new BufferedReader(new InputStreamReader(System.in)).readLine();
        } catch (IOException ex) {
            logger.severe(ex.toString());
        }

        // 打印缓存中的键
        for (String key : cache.getKeySet()) {
            System.out.println(key);
        }
    }
}

结果是:

缓存总访问数:100,总命中数:2,当前大小:98,命中率:2.00%,耗时:4157毫秒
缓存总访问数:200,总命中数:16,当前大小:184,命中率:14.00%,耗时:2062毫秒
缓存总访问数:300,总命中数:40,当前大小:260,命中率:24.00%,耗时:1860毫秒
缓存总访问数:400,总命中数:74,当前大小:326,命中率:34.00%,耗时:578毫秒
缓存总访问数:500,总命中数:111,当前大小:389,命中率:37.00%,耗时:1281毫秒
缓存总访问数:600,总命中数:154,当前大小:446,命中率:43.00%,耗时:3391毫秒
缓存总访问数:700,总命中数:188,当前大小:512,命中率:34.00%,耗时:953毫秒
缓存总访问数:800,总命中数:237,当前大小:563,命中率:49.00%,耗时:1515毫秒
缓存总访问数:900,总命中数:283,当前大小:617,命中率:46.00%,耗时:2094毫秒
缓存总访问数:1000,总命中数:350,当前大小:650,命中率:67.00%,耗时:297毫秒
缓存总访问数:1100,总命中数:415,当前大小:685,命中率:65.00%,耗时:531毫秒
缓存总访问数:1200,总命中数:477,当前大小:723,命中率:62.00%,耗时:953毫秒
缓存总访问数:1300,总命中数:538,当前大小:762,命中率:61.00%,耗时:328毫秒
缓存总访问数:1400,总命中数:604,当前大小:796,命中率:66.00%,耗时:1172毫秒
缓存总访问数:1500,总命中数:667,当前大小:833,命中率:63.00%,耗时:2000毫秒
缓存总访问数:1600,总命中数:739,当前大小:861,命中率:72.00%,耗时:2000毫秒
缓存总访问数:1700,总命中数:813,当前大小:887,命中率:74.00%,耗时:188毫秒
缓存总访问数:1800,总命中数:893,当前大小:907,命中率:80.00%,耗时:1265毫秒
缓存总访问数:1900,总命中数:973,当前大小:927,命中率:80.00%,耗时:516毫秒
缓存总访问数:2000,总命中数:1055,当前大小:945,命中率:82.00%,耗时:422毫秒
缓存总访问数:2100,总命中数:1134,当前大小:966,命中率:79.00%,耗时:516毫秒
缓存总访问数:2200,总命中数:1212,当前大小:988,命中率:78.00%,耗时:1015毫秒
缓存总访问数:2300,总命中数:1287,当前大小:1013,命中率:75.00%,耗时:438毫秒
缓存总访问数:2400,总命中数:1371,当前大小:1029,命中率:84.00%,耗时:937毫秒
缓存总访问数:2500,总命中数:1457,当前大小:1043,命中率:86.00%,耗时:750毫秒
缓存总访问数:2600,总命中数:1540,当前大小:1060,命中率:83.00%,耗时:235毫秒
缓存总访问数:2700,总命中数:1627,当前大小:1073,命中率:87.00%,耗时:140毫秒
缓存总访问数:2800,总命中数:1719,当前大小:1081,命中率:92.00%,耗时:1235毫秒
缓存总访问数:2900,总命中数:1806,当前大小:1094,命中率:87.00%,耗时:125毫秒
缓存总访问数:3000,总命中数:1889,当前大小:1111,命中率:83.00%,耗时:312毫秒
缓存总访问数:3100,总命中数:1981,当前大小:1119,命中率:92.00%,耗时:63毫秒
缓存总访问数:3200,总命中数:2071,当前大小:1129,命中率:90.00%,耗时:125毫秒
缓存总访问数:3300,总命中数:2161,当前大小:1139,命中率:90.00%,耗时:62毫秒
缓存总访问数:3400,总命中数:2254,当前大小:1146,命中率:93.00%,耗时:172毫秒
缓存总访问数:3500,总命中数:2344,当前大小:1156,命中率:90.00%,耗时:156毫秒
缓存总访问数:3600,总命中数:2436,当前大小:1164,命中率:92.00%,耗时:141毫秒
缓存总访问数:3700,总命中数:2529,当前大小:1171,命中率:93.00%,耗时:125毫秒
缓存总访问数:3800,总命中数:2624,当前大小:1176,命中率:95.00%,耗时:78毫秒
缓存总访问数:3900,总命中数:2717,当前大小:1183,命中率:93.00%,耗时:16毫秒
缓存总访问数:4000,总命中数:2811,当前大小:1189,命中率:94.00%,耗时:93毫秒
缓存总访问数:4100,总命中数:2906,当前大小:1194,命中率:95.00%,耗时:16毫秒
缓存总访问数:4200,总命中数:3003,当前大小:1197,命中率:97.00%,耗时:47毫秒
缓存总访问数:4300,总命中数:3095,当前大小:1205,命中率:92.00%,耗时:47毫秒
缓存总访问数:4400,总命中数:3190,当前大小:1210,命中率:95.00%,耗时:47毫秒
缓存总访问数:4500,总命中数:3285,当前大小:1215,命中率:95.00%,耗时:15毫秒
缓存总访问数:4600,总命中数:3372,当前大小:1228,命中率:87.00%,耗时:500毫秒
缓存总访问数:4700,总命中数:3471,当前大小:1229,命中率:99.00%,耗时:16毫秒
缓存总访问数:4800,总命中数:3563,当前大小:1237,命中率:92.00%,耗时:15毫秒
缓存总访问数:4900,总命中数:3658,当前大小:1242,命中率:95.00%,耗时:0毫秒
缓存总访问数:5000,总命中数:3751,当前大小:1249,命中率:93.00%,耗时:32毫秒
缓存总访问数:5100,总命中数:3846,当前大小:1254,命中率:95.00%,耗时:15毫秒
缓存总访问数:5200,总命中数:3937,当前大小:1263,命中率:91.00%,耗时:219毫秒
缓存总访问数:5300,总命中数:4034,当前大小:1266,命中率:97.00%,耗时:0毫秒
缓存总访问数:5400,总命中数:4131,当前大小:1269,命中率:97.00%,耗时:16毫秒
缓存总访问数:5500,总命中数:4230,当前大小:1270,命中率:99.00%,耗时:0毫秒
缓存总访问数:5600,总命中数:4327,当前大小:1273,命中率:97.00%,耗时:0毫秒
缓存总访问数:5700,总命中数:4423,当前大小:1277,命中率:96.00%,耗时:297毫秒
缓存总访问数:5800,总命中数:4520,当前大小:1280,命中率:97.00%,耗时:703毫秒
缓存总访问数:5900,总命中数:4618,当前大小:1282,命中率:98.00%,耗时:0毫秒
缓存总访问数:6000,总命中数:4715,当前大小:1285,命中率:97.00%,耗时:47毫秒
缓存总访问数:6100,总命中数:4811,当前大小:1289,命中率:96.00%,耗时:125毫秒
缓存总访问数:6200,总命中数:4907,当前大小:1293,命中率:96.00%,耗时:31毫秒
缓存总访问数:6300,总命中数:5005,当前大小:1295,命中率:98.00%,耗时:62毫秒
缓存总访问数:6400,总命中数:5103,当前大小:1297,命中率:98.00%,耗时:16毫秒
缓存总访问数:6500,总命中数:5201,当前大小:1299,命中率:98.00%,耗时:16毫秒
缓存总访问数:6600,总命中数:5299,当前大小:1301,命中率:98.00%,耗时:0毫秒
缓存总访问数:6700,总命中数:5397,当前大小:1303,命中率:98.00%,耗时:31毫秒
缓存总访问数:6800,总命中数:5496,当前大小:1304,命中率:99.00%,耗时:15毫秒
缓存总访问数:6900,总命中数:5593,当前大小:1307,命中率:97.00%,耗时:0毫秒
缓存总访问数:7000,总命中数:5691,当前大小:1309,命中率:98.00%,耗时:0毫秒
缓存总访问数:7100,总命中数:5791,当前大小:1309,命中率:100.00%,耗时:0毫秒
缓存总访问数:7200,总命中数:5889,当前大小:1311,命中率:98.00%,耗时:16毫秒
缓存总访问数:7300,总命中数:5988,当前大小:1312,命中率:99.00%,耗时:16毫秒
缓存总访问数:7400,总命中数:6088,当前大小:1312,命中率:100.00%,耗时:0毫秒
缓存总访问数:7500,总命中数:6185,当前大小:1315,命中率:97.00%,耗时:0毫秒
缓存总访问数:7600,总命中数:6281,当前大小:1319,命中率:96.00%,耗时:62毫秒
缓存总访问数:7700,总命中数:6381,当前大小:1319,命中率:100.00%,耗时:0毫秒
缓存总访问数:7800,总命中数:6480,当前大小:1320,命中率:99.00%,耗时:31毫秒
缓存总访问数:7900,总命中数:6580,当前大小:1320,命中率:100.00%,耗时:0毫秒
缓存总访问数:8000,总命中数:6679,当前大小:1321,命中率:99.00%,耗时:0毫秒
缓存总访问数:8100,总命中数:6777,当前大小:1323,命中率:98.00%,耗时:0毫秒
缓存总访问数:8200,总命中数:6877,当前大小:1323,命中率:100.00%,耗时:0毫秒
缓存总访问数:8300,总命中数:6975,当前大小:1325,命中率:98.00%,耗时:16毫秒
缓存总访问数:8400,总命中数:7074,当前大小:1326,命中率:99.00%,耗时:0毫秒
缓存总访问数:8500,总命中数:7172,当前大小:1328,命中率:98.00%,耗时:0毫秒
缓存总访问数:8600,总命中数:7270,当前大小:1330,命中率:98.00%,耗时:16毫秒
缓存总访问数:8700,总命中数:7368,当前大小:1332,命中率:98.00%,耗时:0毫秒
缓存总访问数:8800,总命中数:7465,当前大小:1335,命中率:97.00%,耗时:0毫秒
缓存总访问数:8900,总命中数:7563,当前大小:1337,命中率:98.00%,耗时:15毫秒
缓存总访问数:9000,总命中数:7663,当前大小:1337,命中率:100.00%,耗时:0毫秒
缓存总访问数:9100,总命中数:7763,当前大小:1337,命中率:100.00%,耗时:0毫秒
缓存总访问数:9200,总命中数:7862,当前大小:1338,命中率:99.00%,耗时:0毫秒
缓存总访问数:9300,总命中数:7960,当前大小:1340,命中率:98.00%,耗时:0毫秒
缓存总访问数:9400,总命中数:8060,当前大小:1340,命中率:100.00%,耗时:0毫秒
缓存总访问数:9500,总命中数:8158,当前大小:1342,命中率:98.00%,耗时:16毫秒
缓存总访问数:9600,总命中数:8258,当前大小:1342,命中率:100.00%,耗时:0毫秒
缓存总访问数:9700,总命中数:8356,当前大小:1344,命中率:98.00%,耗时:0毫秒
缓存总访问数:9800,总命中数:8455,当前大小:1345,命中率:99.00%,耗时:0毫秒
缓存总访问数:9900,总命中数:8554,当前大小:1346,命中率:99.00%,耗时:0毫秒
缓存总访问数:10000,总命中数:8654,当前大小:1346,命中率:100.00%,耗时:0毫秒

从中大致可以看出缓存的增长趋势以及性能不断改进的趋势。

最后的内存占用率如下图所示:

当然了,这也是不得已而为之的技术,呵呵,如果项目中能用到Hibernate等高级技术的话(Hibernate内置查询缓存了,甚至很多数据库也内置了),还是尽量高级的吧。

总结这个查询缓存应用的场合:

1、SQL语句的可能性不能无限多(例如如果语句中包含可变的时间日期就不行);
2、读操作远远多于写操作。

例如,在权限管理(登陆注销、操作鉴权...)中,还是很合适的。

分享到:
评论

相关推荐

    Oracle JDBC连接缓存对JSP数据库处理性能的优化.pdf

    【Oracle JDBC连接缓存对JSP数据库处理性能的优化】 Oracle JDBC连接缓存技术是针对JSP页面数据库处理性能优化的重要手段。在电子商业站点中,动态Web页面对数据库的高效访问是性能和稳定性关键所在。JDBC连接缓存...

    如何避免JDBC引起的内存溢出情况

    这种配置下,MySQL会使用游标的方式返回结果集,即只在客户端缓存部分数据,并且可以按需获取更多的行,这样可以有效地减少内存占用。 **2. SQL Server** 对于SQL Server,同样推荐使用游标模式来获取结果集。可以...

    3.1 JDBC消息存储持久化jdbc persistenceFactory高速缓存1

    本篇将详细讲解如何利用JDBC实现ActiveMQ的消息存储持久化以及高速缓存。 1. **JDBC消息持久化**: - **MySQL驱动集成**:为了使用MySQL作为数据存储,你需要将MySQL的JDBC驱动添加到ActiveMQ的lib目录下。 - **...

    jdbc分页查询源码

    本源码示例着重讲解如何利用JDBC进行分页查询,以避免一次性加载所有数据导致的性能瓶颈。 首先,我们需要了解分页查询的基本概念。分页查询是将数据库中的数据按一定的数量(如每页10条)分割,每次只查询一部分,...

    第16章OracleJDBC连接池和缓存161OracleJDBC连接池和缓存包.ppt

    Oracle JDBC 连接池和缓存是数据库管理中优化数据库访问效率的重要机制。在Java应用程序中,使用JDBC(Java Database Connectivity)与Oracle数据库交互时,通过连接池可以有效地管理和复用数据库连接,减少每次建立...

    多线程以JDBC的方式返回海量数据

    通过JDBC,我们可以执行SQL语句,查询、更新和管理数据库中的数据。然而,当数据量非常大时,一次性加载所有数据可能会导致内存溢出,降低应用程序性能。 为了解决这个问题,我们可以采用多线程技术。多线程允许...

    springboot声明式缓存+jdbc+restfull接口 例子

    结合这些技术,我们可以构建一个高效的微服务,其中缓存可以减少数据库查询,提高性能;JDBC使我们能够灵活地与数据库交互;RESTful接口则为客户端提供了直观且易于使用的数据访问方式。在"spring_cache"这个示例...

    JDBC性能优化.pdf

    ### JDBC性能优化详解 #### 一、引言 在当今数据密集型的应用环境中,Java数据库连接(JDBC)作为Java应用程序与数据库之间的重要桥梁,其性能优化显得尤为重要。本文将根据“JDBC性能优化.pdf”文件提供的信息,...

    Mysql JDBC驱动 .zip_MYSQL_jdbc mysql_mysql jdbc_mysql jdbc driver_

    此外,根据应用需求,可能需要进行性能优化,如设置合适的连接超时、查询缓存等配置。 综上所述,MySQL JDBC驱动是Java开发者与MySQL数据库通信的重要桥梁,通过它,我们可以方便地执行SQL语句,进行数据操作。了解...

    jdbc 连接impala或者jdbc连接hive

    在这个场景下,JDBC提供了连接Hive和Impala的功能,使得开发者可以通过编写Java程序或使用支持JDBC的任何其他工具来执行查询和操作数据。下面将详细介绍如何使用JDBC连接Hive和Impala。 1. **JDBC连接Hive** Hive...

    使用java原生jdbc完成数据的增删改查

    虽然这种方式相对简单,但实际项目中更推荐使用ORM框架如Hibernate或MyBatis,它们提供了更高级的功能,如对象关系映射、缓存支持和更便捷的SQL操作。不过理解JDBC的基础对于学习这些框架非常有帮助。

    jdbc 源码 oracle 自带jdbc

    - 如何优化SQL执行,如批处理和缓存复用。 - 对特定数据库特性(如Oracle的PL/SQL、索引、分区等)的支持。 此外,深入源码有助于解决实际开发中遇到的问题,比如性能优化、错误调试、新功能的实现等。对于希望成为...

    jdbc(jar文件)

    10. **性能优化**:使用JDBC时,可以考虑批处理操作、结果集缓存、关闭不必要的资源等策略来提高性能。 总结来说,这个压缩包中的jar文件是连接Eclipse与MySQL、Oracle和SQL Server数据库的关键,提供了Java程序与...

    JDBC与Hibernate区别

    此外,Hibernate支持缓存机制,可以通过二级缓存提高性能,尤其是在查询小部分数据时,Iterator方式的效率较高。 对于数据状态,JDBC操作的数据通常是瞬时的,需要开发者手动同步数据库和内存中的数据。而Hibernate...

    优化JDBC方法功略

    一旦获取了MetaData信息,应将其缓存起来,避免重复执行可能导致复杂查询的元数据获取操作。例如,程序可以一次性调用getTypeInfo方法,然后缓存返回的结果,而不是在需要时反复调用。 其次,避免在MetaData方法中...

    JDBC 书籍 学习

    这意味着缓存的大小不是根据实际查询结果来确定的,而是根据查询结果的最大可能值来预估。 - **缓存大小计算**:一旦 SQL 语句被解析,所有列的数据类型都会被明确下来,因此可以计算出每列的最大可能内存量。结合 ...

    Jdbc实用教程

    通过JDBC,开发者可以编写SQL语句、执行查询、处理结果集以及管理事务,实现了数据库操作的跨平台性。 二、JDBC API组件 1. **DriverManager**: 这是Java应用程序连接到数据库的关键。它负责注册驱动程序,建立和...

    SQL Server JDBC Jar包

    它遵循Java Database Connectivity (JDBC) API标准,使Java开发者能够利用SQL Server的功能进行数据存取、查询和处理。在这个4.0版本的JDBC驱动中,开发者可以支持从Java应用连接到SQL Server2008R2、SQL Server2008...

    hive-jdbc-1.1.0-cdh5.12.1-standalone.rar

    3. **结果集缓存**:Hive JDBC可以缓存部分或全部查询结果,提高数据读取效率。 4. **连接池管理**:通过连接池,可以更有效地管理和复用Hive连接,减少资源消耗。 5. **安全认证**:支持多种认证机制,如Kerberos、...

    sqljdbc4.0

    使用JDBC,开发者可以编写SQL语句执行数据库操作,如查询、插入、更新和删除数据。JDBC驱动扮演了中间人的角色,将Java应用程序的请求转换为数据库可以理解的命令,并将数据库的响应返回给应用。 在“压缩包子文件...

Global site tag (gtag.js) - Google Analytics