log4j 数据库 flushbuffer

本文介绍了如何通过自定义扩展log4j中的JDBCAppender,实现将聊天记录的日志信息根据XML格式解析,分别存储到数据库的不同字段中。具体步骤包括继承JDBCAppender类,重写flushBuffer方法,解析日志内容并将其转换为map,然后根据map中的键值对构建SQL语句完成数据存储。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在log4j中,可以用JDBCAppender将log的内容存贮到数据库中.但是,只能将内容整体放到数据库的一个字段中,如果想将log的内容分开来存贮到不同的字段中,就要对JDBCAppender重写做扩展了.这几天看了一下log4j的源码.做了一下简单的扩展.

例如;想将聊天记录的log存到数据库中,要将聊天记录的相关信息.fromid,toid,fromname,toname,time,content分开来,存到数据库中的不同字段时,将要怎么做呢. 可以继承JDBCAppender,对方法flushBuffer重写.如下;

import org.apache.log4j.jdbc.JDBCAppender;
import java.util.Iterator;
import java.sql.SQLException;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.LoggingEvent;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Element;
import java.util.Map;
import java.util.HashMap;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;

public class ChatSaveAppender extends JDBCAppender {
public void flushBuffer() {
//Do the actual logging
removes.ensureCapacity(buffer.size());
for (Iterator i = buffer.iterator(); i.hasNext(); ) {
try {
LoggingEvent logEvent = (LoggingEvent) i.next();
Object obj = logEvent.getMessage();
String msg = obj.toString();
System.out.println(msg);

//例如log是与xml文件输出的。格式如;<hi toname="小猫" cmd="msg" time="2007-5-21 00:00:41" fromid="2871146" toid="2534882" content="您好" status="0" fromname="小猪"/>
Map<String,String> map = xmlToMap(msg);//将xml解析成map
if(map!=null){
String fromid = "";
String fromname = "";
String toid = "";
String toname = "";
String content ="";
String time = "";
String status = "";
if(map.containsKey("fromid")){
fromid = map.get("fromid");
}

if(map.containsKey("fromname")){
fromname = ""+ map.get("fromname");
}
if(map.containsKey("toid")){
toid = ""+ map.get("toid");
}
if(map.containsKey("toname")){
toname = ""+ map.get("toname");
}
if(map.containsKey("content")){
content = ""+ map.get("content");
}
if(map.containsKey("status")){
status = ""+ map.get("status");
}
if(map.containsKey("time")){
time = ""+ map.get("time");
}
String sql = "insert into CHAT_LOG (FROMID,FROMNAME,TOID,TONAME,CONTENT,TIME,STATUS) values ("
+fromid+",'"+fromname+"',"+toid+",'"+toname+"','" + content
+ "',to_date('"+time+"','yyyy-mm-dd hh24-mi-ss'),"+status+")";
execute(sql);
}
removes.add(logEvent);
} catch (SQLException e) {
errorHandler.error("Failed to excute sql", e,
ErrorCode.FLUSH_FAILURE);
}
}
// remove from the buffer any events that were reported
buffer.removeAll(removes);
// clear the buffer of reported events
removes.clear();
}

//下面解析log,由xml解析成map,用dom4j.
public Map<String, String> xmlToMap(String parameters) {
Map map =null;
if (parameters != null && parameters.indexOf(CMD_NAME)>0 ) {
try {
Document document = DocumentHelper.parseText(parameters);
if (document != null) {
Element root = document.getRootElement();
if (root != null && root.getName().equalsIgnoreCase(ROOT_NAME)) {
map = attributeToMap(root);
root = null;
}
}
document = null;
} catch (Exception e) {
System.out.println("format String:\n"+parameters + e);
} finally {
parameters = null;
}
}
return map;
}


public Map<String, String> attributeToMap(Element root) {
List<Attribute> attributes = root.attributes();
Map<String, String> map = new HashMap<String, String>(5);
for (Attribute attribute : attributes) {
map.put(attribute.getName(), attribute.getText());
}
attributes = null;
root = null;
return map;
}
}

log4j.properties文件可以写成如下;

log4j.rootLogger=DEBUG, DATABASE

log4j.appender.DATABASE = com.logsave.ChatSaveAppender
log4j.appender.DATABASE.Driver = oracle.jdbc.driver.OracleDriver
log4j.appender.DATABASE.URL = jdbc:oracle:thin:@127.0.0.1:1521:orc2
log4j.appender.DATABASE.User = myuser
log4j.appender.DATABASE.Password = mypassword
log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern=%m

也可以在程序中引用;

ChatSaveAppender chatAppender = new ChatSaveAppender();
chatAppender.setUser("myuser");
chatAppender.setPassword("marryfive");
chatAppender.setDriver("oracle.jdbc.driver.OracleDriver");
chatAppender.setURL("jdbc:oracle:thin:@192.168.0.213:1521:orc2");
org.apache.log4j.PatternLayout layout = new PatternLayout();
layout.setConversionPattern("%m");
chatAppender.setLayout(layout);
logger.addAppender(chatAppender);
<think>嗯,用户想了解MySQL数据库每分钟能插入多少数据。这个问题看起来简单,但实际上影响因素很多。首先,我需要回忆一下之前学过的MySQL性能优化知识。记得引用[2]提到批量插入和事务处理对性能的影响很大,比如使用INSERT语句一次插入多条数据比逐条插入快很多。还有引用[3]里提到的事务机制,开启事务后批量提交可以减少磁盘I/O次数,这应该能显著提升插入速度。 然后,硬件配置方面,磁盘类型比如SSD和HDD的差异,SSD的IOPS更高,写入速度更快。CPU和内存足够的话,处理数据的速度也会更快。还有网络延迟,如果是远程连接数据库,网络状况不好可能会成为瓶颈。 存储引擎的选择,InnoDB和MyISAM的不同。InnoDB支持事务,适合高并发写入,而MyISAM在插入速度上可能更快,但不支持事务。不过现在大多数情况都用InnoDB,尤其是需要事务安全的时候。 表结构设计,比如索引的数量。每次插入数据时,索引的更新会消耗时间,尤其是如果有多个索引的话。所以表设计时要合理规划索引,避免不必要的索引。 系统配置参数,比如innodb_flush_log_at_trx_commit。设置为0或2可以减少磁盘刷新的频率,提高插入速度,但可能会影响数据安全性。需要在性能和数据安全之间做权衡。 实际测试方法的话,用户可能需要用脚本模拟插入操作。比如用Python写个多线程的脚本,批量插入数据,然后计算每分钟的插入量。记得在测试前调整配置参数,比如增大innodb_buffer_pool_size,使用LOAD DATA INFILE语句等优化手段。 用户可能还关心如何优化插入性能,所以需要总结几个关键点:批量插入、事务控制、调整配置、硬件升级、表结构优化。同时要提醒他们根据具体场景选择合适的方案,比如日志记录可以牺牲一些安全性换取速度,而交易数据则需要保证事务安全。 最后,可能的问题包括如何测试具体数值,或者不同配置下的差异,以及优化方法的具体步骤。需要确保回答覆盖这些方面,并且引用正确的资料,比如引用[2]和[3]提到的批量插入和事务处理的重要性,引用[4]提到的硬件和配置优化的实际案例。</think>### MySQL数据库每分钟插入数据量分析 MySQL每分钟插入数据量的性能受**硬件配置、表结构、存储引擎、系统参数**等多方面因素影响。以下为关键因素及性能测试方法: --- #### 一、核心影响因素 1. **硬件配置** - **磁盘类型**:SSD的IOPS(如10,000+)通常比HDD(100-200)高数十倍,直接影响写入速度[^2][^4]。 - **CPU与内存**:高并发插入时,CPU处理能力与内存缓冲(如`innodb_buffer_pool_size`)决定数据处理效率。 - **网络延迟**:远程连接数据库时,网络带宽和稳定性可能成为瓶颈。 2. **存储引擎选择** - **InnoDB**:支持事务和行级锁,适合高并发写入,但需平衡事务提交频率(如`innodb_flush_log_at_trx_commit=2`可提升性能)[^3]。 - **MyISAM**:表级锁,无事务支持,适合低并发批量插入场景。 3. **表结构与索引** - **索引数量**:每增加一个索引,插入时需额外更新索引数据,性能可能下降20%-50%[^2]。 - **字段类型**:使用`VARCHAR`代替`TEXT`、合理选择数值类型(如`INT` vs `BIGINT`)可减少存储开销。 4. **系统参数优化** - **事务提交频率**:批量插入时合并事务(如每1000条提交一次)可减少磁盘I/O。 - **日志写入策略**:设置`sync_binlog=0`和`innodb_flush_log_at_trx_commit=0`可提升速度,但可能丢失部分数据。 --- #### 二、性能测试方法 1. **基础测试脚本(Python示例)** ```python import mysql.connector import time config = { "user": "root", "password": "123456", "host": "localhost", "database": "test_db" } def batch_insert(num_records, batch_size=1000): conn = mysql.connector.connect(**config) cursor = conn.cursor() start_time = time.time() try: conn.start_transaction() for i in range(0, num_records, batch_size): data = [(f"name_{j}", j) for j in range(i, min(i+batch_size, num_records))] cursor.executemany("INSERT INTO test_table (name, value) VALUES (%s, %s)", data) conn.commit() finally: cursor.close() conn.close() total_time = time.time() - start_time return num_records / total_time * 60 # 每分钟插入量 # 测试插入10万条数据 records_per_minute = batch_insert(100000) print(f"每分钟插入量: {records_per_minute:.0f} 条") ``` 2. **典型性能范围** | 场景 | 插入量(条/分钟) | 说明 | |-----------------------|-------------------|--------------------------| | 单线程逐条插入 | 1,000 - 5,000 | 性能最差,适合低频操作 | | 批量插入(每批1000条)| 50,000 - 200,000 | 推荐常规用法 | | LOAD DATA INFILE | 500,000+ | 文件导入,最快但需预处理 | --- #### 三、优化建议 1. **批量插入与事务** - 合并多条INSERT语句:`INSERT INTO table VALUES (1),(2),(3);` - 显式事务控制:减少自动提交次数 2. **参数调优** ```sql -- 临时关闭日志同步 SET GLOBAL sync_binlog = 0; SET GLOBAL innodb_flush_log_at_trx_commit = 2; ``` 3. **硬件与架构升级** - 使用SSD并配置RAID 0/10 - 读写分离或分库分表 --- #### 四、注意事项 - **数据安全**:优化参数(如`sync_binlog=0`)可能导致故障时丢失最近1秒数据[^4]。 - **锁竞争**:高并发插入时,建议使用分区表或分库分表。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值