关于JAVA编写的WEB程序多次并发访问数据库的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于JAVA编写的WEB程序多次并发访问数据库的问题相关的知识,希望对你有一定的参考价值。

关于JAVA编写的WEB程序多次并发访问数据库的问题
我们有个实时报表页面会30秒刷新一次,该页面可能同时有100人开着。
旧的逻辑是该页面利用<meta http-equiv="refresh" content="30" />来控制刷新,后端bean执行select语句查询然后在bean里拼接html返回页面显示。这样的实现方法会不会对数据库加重负担?
我想到一个解决方式,就是用一个对象来定时执行select语句和拼接HTML,然后返回一个静态的变量,用页面bean去获取该静态变量。
不知道这样算解决问题么?或者有什么更好的解决办法?

有一个思路,你可以用ajax局部刷新数据,不刷新整个页面,同时用缓存,例如第一个30秒的数据放入缓存,页面从缓存里取数据,第二个30秒,你从数据库取出数据后,写个对象对比的方法,来比对新数据和第一个30秒存入缓存的数据,如果数据没有改变,那页面什么操作也不用做,因为数据没变化,刷新也没意义,如果第二个30秒数据发生变化,那么就刷新缓存为第二个30秒的数据,并且局部刷新页面数据。数据库的查询是避免不了的,所以没发减轻数据库的压力,只能是优化数据的显示。就象我上边提到的,如果前后2个30秒数据没有变化,那么就不要刷新页面。 参考技术A 你把前台页面刷新,与后台定时查询数据两个刷新分开来。
旧的方案,每隔30秒的自动刷新保持不变。
后台查询业务可以设计成定时任务,请参考Timer或者quertz设计实现。保持没28秒刷新一次就可以满足前台对数据有效性的要求。
这样设计可以解决并发访问数据的情况,因为访问数据库的查询业务只有一个定时任务来实现。
希望对你有帮助本回答被提问者和网友采纳
参考技术B 这样经常刷新肯定对数据库有影响的,你这样是可行的,也可以放在缓存里面~~

编写高效的Java代码:常用的优化技巧之并发编程技巧

​编写高效的Java代码:常用的优化技巧【一】​

​编写高效的Java代码:常用的优化技巧【二】​

​编写高效的Java代码:常用的优化技巧【三】之JVM调优​


一、使用并发集合和原子变量来减少竞争

在多线程并发执行的场景中,如果多个线程同时访问同一个共享资源,就会出现竞争条件,这会导致数据不一致或者程序异常。因此,使用并发集合和原子变量来减少竞争是非常必要的。

1.1 并发集合

并发集合是Java提供的一种线程安全的集合框架,包括ConcurrentHashMap、ConcurrentLinkedQueue、CopyOnWriteArrayList等。它们在实现上使用了锁分段技术,不同的元素被分配到不同的段中,不同的段可以由不同的线程同时访问,从而实现高效的并发操作。

以ConcurrentHashMap为例,它是一个线程安全的哈希表,支持高效的并发访问。可以使用putIfAbsent()方法来向ConcurrentHashMap中添加元素。该方法会检查哈希表中是否已经存在对应的键值对,如果不存在则添加。该方法的具体实现如下:

public V putIfAbsent(K key, V value) 
V v = map.get(key);
if (v == null)
v = map.putIfAbsent(key, value);

return v;

1.2 原子变量

原子变量是Java提供的一种线程安全的变量类型,可以保证对变量的操作是原子性的。常见的原子变量有AtomicInteger、AtomicLong、AtomicBoolean等。

以AtomicInteger为例,它可以用来替代int类型的变量,在多线程环境下保证线程安全。可以使用compareAndSet()方法来进行原子操作。该方法会比较当前的值是否等于预期值,如果相等则更新为新值。该方法的具体实现如下:

public final boolean compareAndSet(int expect, int update) 
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

二、使用线程池和Future来提高并发性能

在高并发的场景中,使用线程池和Future来提高并发性能是非常必要的。

2.1 线程池

线程池是一个重要的并发编程工具,它可以重复利用已经创建的线程,避免频繁地创建和销毁线程所带来的开销。在Java中,可以使用ThreadPoolExecutor类来创建线程池。

下面是一个简单的线程池示例:

ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++)
final int taskIndex = i;
executorService.execute(() ->
// 执行任务
System.out.println("Task " + taskIndex + " executed.");
);

executorService.shutdown();

2.2 Future

Future是Java提供的一种异步编程工具,可以在执行耗时操作时返回一个Future对象,通过该对象可以获取操作结果。在高并发的场景中,使用Future可以提高代码的可读性和可维护性。

下面是一个简单的Future示例:

ExecutorService executorService = Executors.newFixedThreadPool(10);
Future<Integer> future = executorService.submit(() ->
// 执行耗时操作
return 1 + 2;
);
int result = future.get(); // 获取操作结果
System.out.println("Result: " + result);
executorService.shutdown();

三、避免使用阻塞调用和不必要的等待

在高并发的场景中,使用阻塞调用和不必要的等待会导致程序性能下降。因此,需要尽量避免使用阻塞调用和不必要的等待。

3.1 避免阻塞调用

在Java中,常见的阻塞调用有IO操作、synchronized关键字、Object.wait()等。可以使用NIO、Lock、Condition等代替这些阻塞调用,从而提高程序性能。

3.2 避免不必要的等待

在多线程并发执行的场景中,不必要的等待会导致程序性能下降。可以使用Lock和Condition来实现线程间的等待和通知。

下面是一个简单的Lock和Condition示例:

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
int count = 0;

Thread t1 = new Thread(() ->
lock.lock();
try
while (count == 0)
condition.await(); // 等待

System.out.println("Count: " + count);
catch (InterruptedException e)
e.printStackTrace();
finally
lock.unlock();

);

Thread t2 = new Thread(() ->
lock.lock();
try
count = 1;
condition.signal(); // 通知
finally
lock.unlock();

);

t1.start();
t2.start();

总结:

本文介绍了一些常用的并发编程技巧,包括使用并发集合和原子变量来减少竞争、使用线程池和Future来提高并发性能、避免使用阻塞调用和不必要的等待等。在实际应用中,可以根据具体需求选择合适的并发编程工具和技巧,从而提高程序的性能和可维护性。

​编写高效的Java代码:常用的优化技巧【一】​

​编写高效的Java代码:常用的优化技巧【二】​

​编写高效的Java代码:常用的优化技巧【三】之JVM调优​

以上是关于关于JAVA编写的WEB程序多次并发访问数据库的问题的主要内容,如果未能解决你的问题,请参考以下文章

编写高效的Java代码:常用的优化技巧之并发编程技巧

编写高效的Java代码:常用的优化技巧之并发编程技巧

采用SOAP的方法访问web derive有啥优点? 关于XML的

使用 JAVA 线程在 hsqldb 中进行并发访问

测试网站的高并发量访问压力

教妹学Java: 方法,我负责程序的行为