【问题标题】:SQLalchemy: changes not committing to dbSQLalchemy:未提交到数据库的更改
【发布时间】:2013-12-20 06:47:27
【问题描述】:

我正在尝试使用 SQLalchemy 编写一个相对简单的脚本来与 MySQL 数据库交互。我对 sqlalchemy 和一般编程很陌生,所以我需要帮助。

由于某种原因,我在运行脚本后没有看到影响数据库的更新查询。运行脚本时我没有收到任何错误,我只是看不到数据库中的任何更改。我认为我在提交会话时遇到了问题,但我不确定我哪里出错了。

#!/usr/bin/env python

from sqlalchemy import Column, Integer, String, DateTime, create_engine, update
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime
from IPy import IP
from optparse import OptionParser
from getpass import getpass

#parse the command line options 
parser = OptionParser()
parser.add_option('-x', '--expunging', action='store_true',  default=False, dest='expunging', help='remove virtual machines that are stuck in expunging state')
parser.add_option('-v', '--volumes', action='store_true',  default=False, dest='volumes', help='remove orphaned volumes')
parser.add_option('-n', '--nics', action='store_true',  default=False, dest='nics', help='update the ip address and gateway on the nic')
parser.add_option('-d', '--display', action='store_true',  default=False, dest='display', help='display the current VMs or volumes ')
(opts, args) = parser.parse_args()


#connect to the database and create some required objects
addr = raw_input('IP address of the MySQL CloudStack database:\n> ')
passwd = getpass('MySQL root passwd:\n> ')
connect_string='mysql://root:'+passwd+'@'+addr+'/cloud'
engine = create_engine(connect_string)
Session = sessionmaker(bind=engine)
Base = declarative_base()
session = Session()


#create the table objects
class cloud_vm(Base):
    __tablename__ = 'vm_instance'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    state = Column(String)
    removed = Column(DateTime)

    def __init__(self, id, name, state, removed):
        self.id = id
        self.name = name
        self.state = state
        self.removed = removed

    def __repr__(self):
        return '%s %s %s %s' % (self.id, self.name, self.state, self.removed)

class cloud_vol(Base):
    __tablename__ = 'volumes'   

    id = Column(Integer, primary_key=True)
    name = Column(String)
    removed = Column(DateTime)
    path = Column(String)

    def __init__(self, name, removed, path):
        self.name = name
        self.removed = removed
        self.path = path

    def __repr__(self):
        return '%s %s %s' % (self.name, self.removed, self.path)

class cloud_networks(Base):
    __tablename__ = 'networks'  

    id = Column(Integer, primary_key=True)
    name = Column(String)
    cidr = Column(String)
    gateway = Column(String)

    def __init__(self, name, cidr, gateway):
        self.name = name
        self.cidr = cidr
        self.gateway = gateway

    def __repr__(self):
        return '%s %s %s' % (self.name, self.cidr, self.gateway)

class cloud_nics(Base):
    __tablename__ = 'nics'  

    id = Column(Integer, primary_key=True)
    instance_id = Column(String)
    ip4_address = Column(String)
    gateway = Column(String)

    def __init__(self, state):
        self.instance_id = instance_id
        self.ip4_address = ip4_address
        self.gateway = gateway

    def __repr__(self):
        return '%s %s %s' % (self.instance_id, self.ip4_address, self.gateway)



#define functions for interacting with the database     
def display_current_vm():
    for name, state, removed in session.query(cloud_vm.name, cloud_vm.state, cloud_vm.removed).filter(cloud_vm.removed==None):
        print name, state

def display_volume_paths():
    for name, path in session.query(cloud_vol.name, cloud_vol.path).filter(cloud_vol.removed==None):
        print name, '/dev/cskvm-1/'+path

def remove_expunging_vm():
    session.query(cloud_vm).filter(cloud_vm.removed==None, cloud_vm.state=='Expunging').update({"removed": datetime.now()})
    session.commit()

def remove_orphan_vol(vols): #use a list type for vols
    print "Volumes no longer in use:\n"
    for i in vols:
        for name, path in session.query(cloud_vol.name, cloud_vol.path).filter(cloud_vol.name==i):
            print '==>  '+name
            print '/dev/cskvm-1/'+path
            print '\n'      
    for j in vols:
        session.query(cloud_vol).filter(cloud_vol.name==i).update({"removed": datetime.now()})
    session.commit()

def update_instance_ip(name, ipaddr, gate):
    try:
        IP(ipaddr)
        IP(gate)
    except:
        print "not a valid ip address"
    for vm_id in session.query(cloud_vm.id).filter(cloud_vm.name==name)[0]:
        session.query(cloud_nics).filter(cloud_nics.instance_id==vm_id).update({"ip4_address": ipaddr, "gateway": gate})
    session.commit()





update_instance_ip("free-public1","10.1.1.1","10.1.1.1")    

'''
#run the main program
def main():
#put program here!

if __name__ == "__main__":
    main()

'''

【问题讨论】:

  • echo=True 参数添加到您的create_engine 调用以记录SQL(默认为STDOUT)。
  • @Mark Hildreth:很酷,这对调试很有帮助。但是,我自己解决了这个问题:脚本正在运行。我用于 MySQL 的 GUI 前端在我断开连接并重新连接到数据库之前不会反映更改,只是在表上反复运行查询不会显示更改。我应该坚持使用 CLI
  • 我假设您实际上不需要断开/重新连接数据库,但 GUI 正在事务中运行您的查询,因此不会看到由事务引起的差异SQLAlchemy 制作的。也许关闭和打开一个新的查询窗口会给你一个新的交易。

标签: python mysql sql sqlalchemy


【解决方案1】:

尝试使用

session.flush

来自文档

Flush all the object changes to the database.

http://docs.sqlalchemy.org/en/latest/orm/session.html?highlight=flush#sqlalchemy.orm.session.Session.flush

【讨论】:

  • flush() 应该在 commit() 之前还是之后?
  • commit 在提交任何事务之前调用flush 本身,因此不需要手动调用session.flush()
猜你喜欢
  • 2021-12-26
  • 1970-01-01
  • 2011-04-29
  • 2019-01-31
  • 2012-01-08
  • 1970-01-01
  • 2020-06-18
  • 2019-06-18
相关资源
最近更新 更多