根据网友的设计进行了部分调整: 用户分为管理员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. Java Lambda 表达式源码分析

    基本概念 Lambda 表达式 函数式接口 方法引用 深入实现原理 字节码 为什么不使用匿名内部类? invokedynamic 总结 参考链接 GitHub 项目 Lambda 表达式是什么?JVM ...

  2. 一个系列搞懂YARN(1)——Yarn架构

    前言 几天前和大哥说起了Yarn,大哥问我,你知道Yarn里面怎么进行资源的动态分配回收的吗?我和诚实,说不知道,然后就有了这个系列博文.不同版本的hadoop版本对应的yarn文档会有差别,本文中选 ...

  3. NOIP 模拟 $29\; \rm 最长不下降子序列$

    题解 \(by\;zj\varphi\) 观察这个序列,发现模数很小,所以它的循环节很小. 那么可以直接在循环节上做最长上升子序列,但是循环节中的逆序对会对拼接后的答案造成影响. 没有必要找逆序对个数 ...

  4. 【C++】 四种强制类型转换(static_cast 与 dynamic_cast 的区别!)

    强制类型转换 1. static_cast 2. dynamic_cast 3. const_cast 4. reinterpret_cast 5. 为什么要需要四种类型转换? 1. static_c ...

  5. 【转】分布式之redis复习精讲

    转自:https://www.cnblogs.com/rjzheng/p/9096228.html 引言 为什么写这篇文章? 博主的<分布式之消息队列复习精讲>得到了大家的好评,内心诚惶诚 ...

  6. 输入npm install 报错node-sass@4.13.0 postinstall:`node scripts/build.js` Failed at the node-sass@4.13.0

    这个是因为sass安装时获取源的问题,先修改sass安装的源,再运行npm install就成功了 npm config set sass_binary_site=https://npm.taobao ...

  7. Timer和TimerTask(转载)

    下面内容转载自: http://blog.csdn.net/xieyuooo/article/details/8607220 其实就Timer来讲就是一个调度器,而TimerTask呢只是一个实现了r ...

  8. 关于在mysql和oracle中编码对varchar等类型的影响

    今天在测试oracle的时候发现,我用varchar2(10),的字段,居然存不下"凯尔特人"四个字符:和我在学习mysql中显然是不一样的,查阅资料发现: mysql 5.0 之 ...

  9. 测试linux python import module

    源码test.py #!/usr/bin/env python # -*- coding: UTF-8 -*- import os os.system("df -h") 运行结果( ...

  10. Java的Class类及static块的执行时机

    要理解RTTI在Java中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工程由Class对象完成,它包含了与类有关的信息.Java使用Class对象来执行其RTTI,即使你执行的是类似转型 ...