根据网友的设计进行了部分调整: 用户分为管理员admin表和用户user表

记录操作表数据 增删改: insert/delete/update

<?php
/**
* OperateLog.php
* description
*/ namespace app\service; use think\Db;
use think\Log; /**
* 操作日志
* Class OperateLog
* @package app\service
*/
class OperateLogService
{
// 日志表主键值id
protected $primaryid;
// 操作表的id
protected $tbid;
// 操作表名
protected $tbname;
// 操作表行字段名
protected $keys;
// 操作表行字段值
protected $values;
// 表前缀
protected $prefix;
// 操作用户类型: 1管理员,admin_id | 2用户,user_id
protected $user_type;
protected $user_id = 0;
protected $admin_id = 0;
protected $ip;
const LOGT1 = 'operatelog';
const LOGT2 = 'operatelog_content'; /**
* OperateLog constructor.
* @param int $userType 操作用户类型,1管理员
* @param int $uid 操作用户类型不为1时传入
*/
public function __construct($userType = 1, $uid = 0)
{
if ($userType == 1) {
$this->admin_id = session('admin_id');
} else {
$this->user_id = $uid;
}
$this->user_type = $userType;
$this->ip = ip2long(getIp());
$this->url = request()->url();
$this->prefix = config('database.prefix');
} /**
* 参数说明 插入行为
* int $tbid 查询指定表的id
* string $tbname 数据库表名
*/
public function insert($tbid, $tbname)
{
try {
//查询表注释
$tb = Db::query('show table status where name = "' . $this->prefix . $tbname . '"');
$priIdName = $this->getPrimaryKey($tbname);
$data = [
'type' => 1,
'create_time' => time(),
'tablename' => $tbname,
'tableid' => $tbid,
'tableid_name' => $priIdName,
'admin_id' => $this->admin_id,
'user_id' => $this->user_id,
'user_type' => $this->user_type,
'ip' => $this->ip,
'comment' => $tb['Comment'],
'url' => $this->url,
];
//插入日志主表
$returnid = Db::name(self::LOGT1)->insertGetId($data);
//查询字段注释
$fields = Db::query('show full columns from ' . $this->prefix . $tbname);
foreach ($fields as $v) {
$commentArray[$v['Field']] = $v['Comment'];
}
//查询所有字段信息,插入日志从表
$rs = Db::name($tbname)->where($priIdName, $tbid)->find();
$keys = array_keys($rs);
$values = array_values($rs);
for ($i = 0; $i < count($keys); $i++) {
Db::name(self::LOGT2)->insert([
'operatelog_id' => $returnid,
'tbkey' => $keys[$i],
'tbvalue' => $values[$i],
'comment' => $commentArray[$keys[$i]]
]);
}
} catch (\Exception $e) {
Log::error($e->getMessage());
} } /**
* 更新行为前
* @param $tbid
* @param $tbname
*/
public function updateStart($tbid, $tbname)
{
try {
//查询表注释
$tb = Db::query('show table status where name = "' . $this->prefix . $tbname . '"');
$priIdName = $this->getPrimaryKey($tbname);
$data = [
'type' => 2,
'create_time' => time(),
'tablename' => $tbname,
'tableid' => $tbid,
'tableid_name' => $priIdName,
'admin_id' => $this->admin_id,
'user_id' => $this->user_id,
'user_type' => $this->user_type,
'ip' => $this->ip,
'comment' => $tb['Comment'],
'url' => $this->url,
];
//插入日志主表
$returnid = Db::name(self::LOGT1)->insertGetId($data);
//查询修改前数据信息
$rs = Db::name($tbname)->where($priIdName, $tbid)->find();
$keys = array_keys($rs);
$values = array_values($rs);
$this->primaryid = $returnid;
$this->tbid = $tbid;
$this->tbname = $tbname;
$this->keys = $keys;
$this->values = $values;
} catch (\Exception $e) {
Log::error($e->getMessage());
} } /**
* 更新行为后
*/
public function updateEnd()
{
try {
//查询表注释
$tb = Db::query('show table status where name = "' . $this->prefix . $this->tbname . '"');
$priIdName = $this->getPrimaryKey($this->tbname);
foreach ($tb as $v) {
$commentArray[$v['Field']] = $v['Comment'];
}
//查询修改后数据信息
$rs = Db::name($this->tbname)->where($priIdName, $this->tbid)->find();
$currentvalues = array_values($rs);
//前后信息进行比较
for ($i = 0; $i < count($currentvalues); $i++) {
if ($this->values[$i] !== $currentvalues[$i]) {
Db::name(self::LOGT2)->insert([
'operatelog_id' => $this->primaryid,
'tbkey' => $this->keys[$i],
'tbvalue' => $this->values[$i],
'currenttbvalue' => $currentvalues[$i],
'comment' => $commentArray[$this->keys[$i]]
]);
}
}
} catch (\Exception $e) {
Log::error($e->getMessage());
} } /**
* 删除行为
* @param $tbid
* @param $tbname
*/
public function delete($tbid, $tbname)
{
try {
//查询表注释
$tb = Db::query('show table status where name = "' . $this->prefix . $this->tbname . '"');
$priIdName = $this->getPrimaryKey($this->tbname);
$data = [
'type' => 3,
'create_time' => time(),
'tablename' => $tbname,
'tableid' => $tbid,
'tableid_name' => $priIdName,
'admin_id' => $this->admin_id,
'user_id' => $this->user_id,
'user_type' => $this->user_type,
'ip' => $this->ip,
'comment' => $tb['Comment'],
'url' => $this->url,
];
//插入日志主表
$returnid = Db::name(self::LOGT1)->insertGetId($data);
//查询字段注释
$fields = Db::query('show full columns from ' . $this->prefix . $tbname);
foreach ($fields as $v) {
$commentArray[$v['Field']] = $v['Comment'];
}
//查询修改前数据信息
$rs = Db::name($tbname)->where($priIdName, $tbid)->find();
$keys = array_keys($rs);
$values = array_values($rs);
for ($i = 0; $i < count($keys); $i++) {
Db::name(self::LOGT2)->insert([
'operatelog_id' => $returnid,
'tbkey' => $keys[$i],
'tbvalue' => $values[$i],
'comment' => $commentArray[$keys[$i]]
]);
}
} catch (\Exception $e) {
Log::error($e->getMessage());
} } /**
* 查询表主键id名
* @param $tbname
* @return mixed
*/
protected function getPrimaryKey($tbname)
{
$priIdTb = Db::query("SELECT column_name FROM INFORMATION_SCHEMA.`KEY_COLUMN_USAGE` WHERE table_name='" . $this->prefix . $tbname . "' AND constraint_name='PRIMARY'");
return $priIdTb[0]['column_name'];
}
}

数据表设计:

CREATE TABLE `yed_operatelog` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned DEFAULT '0' COMMENT 'user表用户id',
`admin_id` int(11) unsigned DEFAULT '0' COMMENT 'admin表主键:管理员id',
`user_type` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '操作用户类型:1管理员,admin_id | 2用户,user_id',
`type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '操作类型:1新增2修改3删除',
`tableid` int(11) unsigned NOT NULL,
`tablename` varchar(255) NOT NULL COMMENT '表名',
`comment` varchar(255) DEFAULT NULL COMMENT '表的comment属性',
`create_time` int(11) unsigned NOT NULL COMMENT '创建时间',
`tableid_name` varchar(50) NOT NULL DEFAULT '' COMMENT '主键id名',
`ip` int(11) DEFAULT NULL COMMENT '操作ip',
`url` varchar(800) DEFAULT NULL COMMENT '操作url',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='操作日志表'; CREATE TABLE `yed_operatelog_content` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`operatelog_id` int(11) NOT NULL COMMENT 'operatelog表id',
`tbkey` longtext NOT NULL COMMENT '字段名',
`tbvalue` longtext COMMENT '改之前值',
`currenttbvalue` longtext COMMENT '改之后值',
`comment` varchar(255) DEFAULT NULL COMMENT '字段注释',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='操作日志从表';

TP5数据库数据变动日志记录设计的更多相关文章

  1. C#日志记录设计与实现(BenXHLog)

    C#日志记录设计与实现 日志记录: 日志记录在程序设计开发过程中,是非常重要的,可以供调试和记录数据,虽然说有开源的强大日志管理系统,比如apache的Log4Net,功能可谓强悍,但是有时候,不需要 ...

  2. mysql数据库安全性配置——日志记录

    一:开启数据库日志记录 (1)在查看数据库是否开启日志记录,默认是OFF,即关闭状态.(可在数据库中执行该查询语句,也可在服务器端执行) show variables like 'log_bin'; ...

  3. shell脚本之分析oracle数据库数据泵日志中表的大小

    1.分析日志格式如下 . . imported "xxx_330508"."xxx_T_DATA" 46.17 MB 268 rows . . imported ...

  4. (转)解释一下SQLSERVER事务日志记录

    本文转载自桦仔的博客http://www.cnblogs.com/lyhabc/archive/2013/07/16/3194220.html 解释一下SQLSERVER事务日志记录 大家知道在完整恢 ...

  5. 解释一下SQLSERVER事务日志记录

    解释一下SQLSERVER事务日志记录 大家知道在完整恢复模式下,SQLSERVER会记录每个事务所做的操作,这些记录会存储在事务日志里,有些软件会利用事务日志来读取 操作记录恢复数据,例如:log ...

  6. wcf利用IDispatchMessageInspector实现接口监控日志记录和并发限流

    一般对于提供出来的接口,虽然知道在哪些业务场景下才会被调用,但是不知道什么时候被调用.调用的频率.接口性能,当出现问题的时候也不容易重现请求:为了追踪这些内容就需要把每次接口的调用信息给完整的记录下来 ...

  7. 扔掉log4j、log4j2,自己动手实现一个多功能日志记录框架,包含文件,数据库日志写入,实测5W+/秒日志文件写入,2W+/秒数据库日志写入,虽然它现在还没有logback那么强大

    讲到log4j,现在国外基本是没有开发者用这个框架了,原因大致有几点,1.功能太少:2.效率低下:3.线程锁bug等等等各种莫名其妙的bug一直都没解决. 其实最重要的是log4j的作者自己也放弃了l ...

  8. tp5下通过composer实现日志记录功能

    tp5实现日志记录 1.安装 psr/log composer require psr/log 它的作用就是提供一套接口,实现正常的日志功能! 我们可以来细细的分析一下,LoggerInterface ...

  9. 也用 Log4Net 之将日志记录到数据库的后台实现 (二)

    也用 Log4Net 之将日志记录到数据库的后台实现 (二)  大家下午好,昨天讲了配置,今天我们讲讲后台实现,在完成了后台实现后,我们才能真正意义上的解决把自定义属性字段值录入到数据库中. 在开写之 ...

随机推荐

  1. IDEA Error:java: 无效的源发行版: 11错误

    IDEA Error:java: 无效的源发行版: 11错误 今天在网上下载了一个项目到本地运行报错 Error: Java : 无效的源发行版: 11 ,上网查了很多找到问题所在.项目的 JDK(P ...

  2. rabbitMQ批量删除指定的队列

    首先进入到rabbitmq目录下的sbin目录 方法1: ./rabbitmqctl list_queues| grep helloQueue | awk '{print $1}' | xargs - ...

  3. SpringBoot开发十二-账号设置

    需求介绍-账号设置 账号设置里面的上传头像(文件) 首先请求必须是一个 POST 请求,其次表单的属性 enctype = "multipart/form-data" 然后就是利用 ...

  4. 「移动端」Web页面适配

    一.什么是移动端适配 移动端 Web 页面,就是常说的手机 h5页面.webview页面.公众号开发的网页等. 由于手机机型较多,各个手机的屏幕尺寸不一样,所以做移动端页面,需要考虑在安卓和ios的各 ...

  5. Linux搭建Snmp服务

    1:安装snmp yum install net-snmp net-snmp-devel net-snmp-libs net-snmp-utils php-snmp 上面的程序首先会校验需要升级的文件 ...

  6. metasploit的数据库配置

    metasploit所处位置:/usr/share/metasploit-framework msf数据库连接命令:db_connect msf:msfadmin@127.0.0.1/msf 1.启动 ...

  7. 深层剖析鸿蒙轻内核M核的动态内存如何支持多段非连续性内存

    摘要:鸿蒙轻内核M核新增支持了多段非连续性内存区域,把多个非连续性内存逻辑上合一,用户不感知底层的不同内存块. 本文分享自华为云社区<鸿蒙轻内核M核源码分析系列九 动态内存Dynamic Mem ...

  8. Leaflet 中 删除 一个 标记(Marker)

    参考:https://blog.csdn.net/qq_34922009/article/details/81184004 下面是我在Leaflet官方文档所找到的答案 ,希望可以帮助到大家 比如以下 ...

  9. MVVMLight学习笔记(三)---数据双向绑定

    一.概述 本文与其说是MVVMLight框架的学习,不如说是温故一下数据的双向绑定. 二.Demo 建立好MVVMLight框架后的Wpf工程后,建立一个Model.Model.View以及ViewM ...

  10. 【java web】拦截器inteceptor

    一.简介 java里的拦截器提供的是非系统级别的拦截,也就是说,就覆盖面来说,拦截器不如过滤器强大,但是更有针对性. Java中的拦截器是基于Java反射机制实现的,更准确的划分,应该是基于JDK实现 ...