sqlalchemy审计提供了一种为数据设置修订跟踪的简单方法。

sqlalchemy_audit的Python项目详细描述


sqlalchemy审计提供了一种为数据设置修订跟踪的简单方法。它的灵感来自sqlalchemy的versioned_history示例,但使用映射器事件而不是会话事件。

示例

Versioned共享DBSession

DBSession=...Versioned.versioned_session(DBSession)

然后像往常一样声明类并让它继承Versioned

classReservation(Versioned,Base):__tablename__='reservation'id=Column(Integer,primary_key=True)name=Column(String(50))date=Column(Date)time=Column(Time)party=Column(Integer)last_modified=Column(DateTime)Reservation.broadcast_crud()# todo: handle this automagically

注意

您还可以从声明性基类中的子类Versioned

正常使用保持不变:

# make new reservationsteve_reservation=Reservation(name='Steve',date=datetime.date(2015,04,15),time=datetime.time(19,00),party=6)session.add(steve_reservation)session.commit()# change reservation to party of 4steve_reservation.party=4session.commit()# cancel the reservationsession.delete(steve_reservation)session.commit()

另外,您可以访问它的修订历史。

>>>DBSession.query(ReservationRev).all()[ReservationRev(rev_id='c74d5bce...',rev_created=1427995346.0,rev_isdelete=False,id=1,name='Steve',date='2015-04-15',time='19:00',party=6,last_modified='2015-04-02 13:22:26.291670'),ReservationRev(rev_id='f3f5091d...',rev_created=1428068391.0,rev_isdelete=False,id=1,name='Steve',date='2015-04-15',time='19:00',party=4,last_modified='2015-04-03 09:39:51.098798'),ReservationRev(rev_id='3cf1394b...',rev_created=1428534191.0,rev_isdelete=True,id=1,name=None,date=None,time=None,party=None,last_modified=None)]

工作原理

假设您有一个reservations表。

idnamedatetimepartylast_modified
1Steve2015-04-1519:0042015-04-08 13:22:26.291670
2Phil2015-05-0118:3032015-04-13 09:38:01.060898

在幕后,我们创建一个映射到表reservations_rev的修订类ReservationRev。它具有相同的模式,并具有三个附加列:

rev_id :string (uuid)
Surrogate key for the revision table.
rev_created :timestamp
Timestamp (seconds since the epoch as a floating point number) of when the revision was created. (See Use of rev_created.)
rev_isdelete :boolean
Whether the entry was deleted. (See Use of rev_isdelete.)

每当您写入reservations表时,我们将在reservations_rev表中插入新行。这允许您使用reservations保持不变。如果需要,可以引用reservations_rev来获取修订时间。

示例

对于以下时间线:

  • 2015年4月2日,史蒂夫在19:30预订了2015年4月15日的6人派对。
  • 2015年4月3日,史蒂夫将预订改为4人。
  • 2015年4月8日,史蒂夫取消了预订。

reservations_rev将具有以下内容

rev_idrev_createdrev_isdeleteidnamedatetimepartylast_modified
c74d5bce…1427995346.0False1Steve2015-04-1519:0062015-04-02 13:22:26.291670
f3f5091d…1428068391.0False1Steve2015-04-1519:0042015-04-03 09:39:51.098798
3cf1394b…1428534191.0True1(null)(null)(null)(null)(null)

设计决策

为所有写入操作写入修订表

对于所有写入,写入修订表有几个优点:

  1. complete transaction history in the revision table for easy reads (no joins required)
  2. complete timeline even if the original table doesn’t have a last modified column

但是,这种方法对于具有动态默认值(如序列或自动日期时间)的INSERT语句有一个特殊的缺点。插入时,修订表没有动态值。我们建议采取以下解决方法:

  1. generate dynamic defaults during object instantiation instead using database defaults
  2. strictly use client-side defaults in the ORM
  3. create server-side database triggers to copy values to revision table for inserts
  4. perform a write-read-write transaction for inserts, which is sub-optimal due to the performance hit

创建的rev_的使用

要重新创建修订时间线,我们依赖于时间戳的使用。虽然我们认识到在不同的服务器之间可能存在时钟漂移或不同步,但有解决这些问题的方法。因此,我们选择继续使用timestamp的简单性。

使用rev廑isdelete

rev_isdelete是一种快速方便的方法,可以在不检查条目的情况下确定行已被删除。它还允许所有为空的条目。

主键/复合键的要求

待定

关联对象对多对多关系的要求

待定

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
在Java中从本地文件系统导入文件   spring boot如何在Java SpringBoot项目中集成Olingo(Odata)   java查找连续数组中缺少的第k个元素(超过时间限制)   java为什么在mySql中插入1/2行时会得到2/4行   java不能在静态上下文中使用它   File Observer方法的java My onEvent()部分不起作用   java Netty NioSocketChannel在多线程写入时收到中断消息   java将文件夹与父文件夹一起复制   java我的TictaToe代码出了什么问题?如何检查已采取的措施?   java Swing JTable更新   java如何将cordinates查找为int   如何使用selenium和java在firefox中打开新的空选项卡   java Gradle构建输出Jar未运行   java没有GET/WEBINF/jsp/login的映射。jsp