Python 有监听数据库变化的模块吗?

Python 有监听数据库变化的模块吗?,第1张

MySQL 的 Binlog 记录着 MySQL 数据库的所有变更信息,了解 Binlog 的结构可以帮助我们解析Binlog,甚至对 Binlog 进行一些修改,或者说是“篡改”,例如实现类似于 Oracle 的 flashback 的功能,恢复误删除的记录,把 update 的记录再还原回去等。本文将带您探讨一下这些神奇功能的实现,您会发现比您想象地要简单得多。本文指的 Binlog 是 ROW 模式的 Binlog,这也是 MySQL 8 里的默认模式,STATEMENT 模式因为使用中有很多限制,现在用得越来越少了。

Binlog 由事件(event)组成,请注意是事件(event)不是事务(transaction),一个事务可以包含多个事件。事件描述对数据库的修改内容。

现在我们已经了解了 Binlog 的结构,我们可以试着修改 Binlog 里的数据。例如前面举例的 Binlog 删除了一条记录,我们可以试着把这条记录恢复,Binlog 里面有个删除行(DELETE_ROWS_EVENT)的事件,就是这个事件删除了记录,这个事件和写行(WRITE_ROWS_EVENT)的事件的数据结构是完全一样的,只是删除行事件的类型是 32,写行事件的类型是 30,我们把对应的 Binlog 位置的 32 改成 30 即可把已经删除的记录再插入回去。从前面的 “show binlog events” 里面可看到这个 DELETE_ROWS_EVENT 是从位置 378 开始的,这里的位置就是 Binlog 文件的实际位置(以字节为单位)。从事件(event)的结构里面可以看到 type_code 是在 event 的第 5 个字节,我们写个 Python 小程序把把第383(378+5=383)字节改成 30 即可。当然您也可以用二进制编辑工具来改。

找出 Binlog 中的大事务

由于 ROW 模式的 Binlog 是每一个变更都记录一条日志,因此一个简单的 SQL,在 Binlog 里可能会产生一个巨无霸的事务,例如一个不带 where 的 update 或 delete 语句,修改了全表里面的所有记录,每条记录都在 Binlog 里面记录一次,结果是一个巨大的事务记录。这样的大事务经常是产生麻烦的根源。我的一个客户有一次向我抱怨,一个 Binlog 前滚,滚了两天也没有动静,我把那个 Binlog 解析了一下,发现里面有个事务产生了 1.4G 的记录,修改了 66 万条记录!下面是一个简单的找出 Binlog 中大事务的 Python 小程序,我们知道用 mysqlbinlog 解析的 Binlog,每个事务都是以 BEGIN 开头,以 COMMIT 结束。我们找出 BENGIN 前面的 “# at” 的位置,检查 COMMIT 后面的 “# at” 位置,这两个位置相减即可计算出这个事务的大小,下面是这个 Python 程序的例子。

切割 Binlog 中的大事务

对于大的事务,MySQL 会把它分解成多个事件(注意一个是事务 TRANSACTION,另一个是事件 EVENT),事件的大小由参数 binlog-row-event-max-size 决定,这个参数默认是 8K。因此我们可以把若干个事件切割成一个单独的略小的事务

ROW 模式下,即使我们只更新了一条记录的其中某个字段,也会记录每个字段变更前后的值,这个行为是 binlog_row_image 参数控制的,这个参数有 3 个值,默认为 FULL,也就是记录列的所有修改,即使字段没有发生变更也会记录。这样我们就可以实现类似 Oracle 的 flashback 的功能,我个人估计 MySQL 未来的版本从可能会基于 Binlog 推出这样的功能。

了解了 Binlog 的结构,再加上 Python 这把瑞士军刀,我们还可以实现很多功能,例如我们可以统计哪个表被修改地最多?我们还可以把 Binlog 切割成一段一段的,然后再重组,可以灵活地进行 MySQL 数据库的修改和迁移等工作。

先说下我对socket.io的理解,websocket更像是开启了一个端口服务,来监视过往的通讯。所以我们可以依赖于当前站点80端口启socket服务,也可以放于其他端口上,比如:

1

require('socket.io').listen(3000)

这样就是监视3000端口了,由于我用的免费服务器,没有权限打开其他端口,所以,我还是使用80了,由于80已经被express使用了,所以我只好在express使用的时候传进来了。

var server = http.createServer(app)

var socket = require('./socket/msg')(server)

 然后 我在msg.js里是这样写的

var db = require('../db/mysql')

var sio = require('socket.io')

var IO = function(server) {

var io = sio.listen(server)

这样就和谐了,db是创建mysql连接的方法,不在本节内容里,略。

在socket.io里是这样的,首先创建一个io通道的连接,然后监视里面的socket的事件,nodejs是事件驱动嘛。代码如下:

io.on('connection', function(socket) {

console.log('a user connected.')

socket.on('disconnect', function() {

console.log('user disconnected.')

})

})

这时只要有用户连接上,就会进入connection中了,然后它的参数是个socket,如果是公聊,我们可以直接用

1

io.emit('chat message', {})

这种形式了。但我们这里是私聊,所以我们要临时的把这个socket对象保存在全局里,供与你私聊的对象使用找到你的socket,很绕口,其实这里的私聊,不算完全的点对点,它还是经过了服务器的,消息传给服务器,服务器再找到你要传达给的那个人的socket对象,发给他。这就是整个的过程了。这里我使用的是一个类数组对象来存储的.

var users = {},

usocket = {}

socket.on('user join', function(data) {

users[username] = username

usocket[username] = socket

})

由于我这里需要用户名登录,所以我就把用户名作为了唯一的标识,这里用类数组的形式的好处就是我不用循环也能够很快的找到它。再我给A发送私聊时,我会先在这个uscoket里面找到它,然后调用它的emit。

function sendUserMsg(data) {

if (data.to in usocket) {

console.log('================')

console.log('to' + data.to, data)

usocket[data.to].emit('to' + data.to, data)

usocket[data.user].emit('to' + data.user, data)

console.log('================')

}

}

这里我emit了两次的原因是,我发给对方消息的同时,我自己也要收到这个消息,然后把它显示出来,为什么这样?其一,接口统一了,聊天里的内容全是服务器过来的,其二,证明我发送成功了。

然后我在客户端监听时,也用我自己的用户名起了一个to+用户名的事件监听。

socket.on('to' + user, function(data) {

//console.log(data)

formatMsg(data)

})

这样,不管是我发的消息,还是我收到消息,都会进入这个事件了。最后,在用户离开的时候别忘记delete掉这个对象。

socket.on('disconnect', function() {

console.log('disconnect')

if (username) {

counter--

delete users[username]

delete usocket[username]

if (home.name == username) {

homeLeave(username)

}

sendmsg({

type: 0,

msg: "用户<b>" + username + "</b>离开聊天室",

counter: counter,

users: users

})

}

})

Asp.net中C#使用Socket发送和接收TCP数据的方法。

具体程序代码如下:

using System

using System.Collections.Generic

using System.Net

using System.Net.Sockets

using System.Text

namespace ConsoleApplication1

{

    public static class SocketTest

    {

        private static Encoding encode = Encoding.Default

        /// <summary>

        /// 监听请求

        /// </summary>

        /// <param name="port"></param>

        public static void Listen(int port)

        {

            Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)

            listenSocket.Bind(new IPEndPoint(IPAddress.Any, port))

            listenSocket.Listen(100)

            Console.WriteLine("Listen " + port + " ...")

            while (true)

            {

                Socket acceptSocket = listenSocket.Accept()

                string receiveData = Receive(acceptSocket, 5000) //5 seconds timeout.

                Console.WriteLine("Receive:" + receiveData)

                acceptSocket.Send(encode.GetBytes("ok"))

                DestroySocket(acceptSocket) //import

            }

        }

        /// <summary>

        /// 发送数据

        /// </summary>

        /// <param name="host"></param>

        /// <param name="port"></param>

        /// <param name="data"></param>

        /// <returns></returns>

        public static string Send(string host, int port, string data)

        {

            string result = string.Empty

            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)

            clientSocket.Connect(host, port)

            clientSocket.Send(encode.GetBytes(data))

            Console.WriteLine("Send:" + data)

            result = Receive(clientSocket, 5000 * 2) //5*2 seconds timeout.

            Console.WriteLine("Receive:" + result)

            DestroySocket(clientSocket)

            return result

        }

        /// <summary>

        /// 接收数据

        /// </summary>

        /// <param name="socket"></param>

        /// <param name="timeout"></param>

        /// <returns></returns>

        private static string Receive(Socket socket, int timeout)

        {

            string result = string.Empty

            socket.ReceiveTimeout = timeout

            List<byte> data = new List<byte>()

            byte[] buffer = new byte[1024]

            int length = 0

            try

            {

                while ((length = socket.Receive(buffer)) > 0)

                {

                    for (int j = 0 j < length j++)

                    {

                        data.Add(buffer[j])

                    }

                    if (length < buffer.Length)

                    {

                        break

                    }

                }

            }

            catch { }

            if (data.Count > 0)

            {

                result = encode.GetString(data.ToArray(), 0, data.Count)

            }

            return result

        }

        /// <summary>

        /// 销毁Socket对象

        /// </summary>

        /// <param name="socket"></param>

        private static void DestroySocket(Socket socket)

        {

            if (socket.Connected)

            {

                socket.Shutdown(SocketShutdown.Both)

            }

            socket.Close()

        }

    }

}


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/sjk/9843292.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-02
下一篇2023-05-02

发表评论

登录后才能评论

评论列表(0条)

    保存