JDBC--06--报错net_write_timeout---MySQL JDBC StreamResult通信原理

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


1.报错背景

在这里插入图片描述

2.原因分析

在这里插入图片描述
在这里插入图片描述

MySQL JDBC StreamResult通信原理

  • JDBC与数据库之间的通信是通过Socket完成的,因此我们可以把数据库当成一个SocketServer的提供方,因此当SocketServer返回数据的时候(类似于SQL结果集的返回)其流程是:服务端程序数据(数据库) -> 内核Socket Buffer -> 网络 -> 客户端Socket Buffer -> 客户端程序(JDBC所在的JVM内存
  • 到目前为止,IT行业中大家所看到的JDBC无论是:MySQL JDBC、SQL Server JDBC、PG JDBC、Oracle JDBC。甚至于是NoSQL的Client:Redis Client、MongoDB Client,甚至于是SSH通信目前在Java中的实现做法也基本都是如此,也就是都是基于TCP通信的机制,它们的大致原理如下图所示:
    在这里插入图片描述

方式1:直接使用MySQL JDBC默认参数读取数据,为什么会挂?

在这里插入图片描述

方式2:JDBC参数上设置useCursorFetch=true可以解决问题

  • 这个方案配合FetchSize设置,确实可以解决问题,这个方案其实就是告诉MySQL服务端我要多少数据,每次要多少数据,通信过程有点像这样:
    在这里插入图片描述
    在这里插入图片描述

在这里的计算中,还没有包含系统调用次数增加了很多,线程等待和唤醒的上下文次数变多,网络包重传的情况对整体性能的影响,因此这种方案看似合理,但是性能确不怎么样

另外,由于MySQL方不知道客户端什么时候将数据消费完,而自身的对应表可能会有DML写入操作,此时MySQL需要建立一个临时空间来存放需要拿走的数据。因此对于当你启用useCursorFetch读取大表的时候会看到MySQL上的几个现象:

  1. IOPS飙升,因为存在大量的IO读取和写入,这个动作是正在准备要返回的数据到临时空间中,此时监控MySQL的网络输出是没有变化的。由于IO写入很大,如果是普通硬盘,此时可能会引起业务写入的抖动
  2. 磁盘空间飙升,这块临时空间可能比原表更大,如果这个表在整个库内部占用相当大的比重有可能会导致数据库磁盘写满,空间会在结果集读取完成后或者客户端发起Result.close()时由MySQL去回收。
  3. CPU和内存会有一定比例的上升,根据CPU的能力决定
  4. 客户端JDBC发起SQL后,长时间等待SQL响应数据,这段时间就是服务端在准备数据,这个等待与原始的JDBC不设置任何参数的方式也表现出等待,在内部原理上是不一样的,前者是一直在读取网络缓冲区的数据,没有响应给业务,现在是MySQL数据库在准备临时数据空间,没有响应给JDBC。
  5. 在数据准备完成后,开始传输数据的阶段,网络响应开始飙升,IOPS由“读写”转变为“读取”。

方式3:Stream读取数据

在这里插入图片描述

3.解决方案

  • 由于当前session参数的优先级大于数据库的全局参数优先级,直接修改数据的net_write_timeout是不能解决问题的
  • 需要在jdbc的连接参数中给netTimeoutForStreamingResults指定新的值,具体指的大小序言应用根据使用场景评估(单挑数据处理耗时),目前根据经验推介设置3600
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要将WMF转换为SVG并设置stroke-width,可以使用Java的Apache Batik库。Apache Batik是一个用于处理SVG的Java库,它提供了将WMF转换为SVG的功能。 以下是一个将WMF转换为SVG并设置stroke-width的示例代码: ```java // 读取WMF文件 InputStream is = new FileInputStream("example.wmf"); // 创建转换器 WMFTranscoder transcoder = new WMFTranscoder(); // 设置转换参数 TranscodingHints hints = new TranscodingHints(); hints.put(ImageTranscoder.KEY_WIDTH, (float) 400); hints.put(ImageTranscoder.KEY_HEIGHT, (float) 300); transcoder.setTranscodingHints(hints); // 执行转换 TranscoderInput input = new TranscoderInput(is); ByteArrayOutputStream os = new ByteArrayOutputStream(); TranscoderOutput output = new TranscoderOutput(os); transcoder.transcode(input, output); // 将转换后的SVG字符串解析为DOM对象 String svgString = os.toString("UTF-8"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); InputSource isource = new InputSource(new StringReader(svgString)); Document doc = builder.parse(isource); // 设置stroke-width Element root = doc.getDocumentElement(); NodeList pathNodes = root.getElementsByTagName("path"); for (int i = 0; i < pathNodes.getLength(); i++) { Element path = (Element) pathNodes.item(i); path.setAttribute("stroke-width", "2"); } // 将DOM对象写入文件 Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.transform(new DOMSource(doc), new StreamResult(new File("example.svg"))); ``` 在上面的代码中,首先读取WMF文件并创建WMFTranscoder对象。然后设置转换参数并执行转换,将转换后的SVG字符串解析为DOM对象。接着,遍历所有的path元素并设置stroke-width属性的值为2。最后,将DOM对象写入SVG文件。 注意:在上面的代码中,设置的stroke-width值为2,可以根据需要进行修改。另外,还需要在代码中添加异常处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值