Thank you very much for your quick response. I will try your suggestion. I 
just wonder if you know there is any bug fix e.g. identical commit log for 
this as, if possible, I want a kind of evidence that upgrading the driver 
could solve my problem.

On Tuesday, April 19, 2016 at 10:56:06 PM UTC+9, Mike Bayer wrote:
>
>
>
> On 04/18/2016 08:54 PM, Shingo Toda wrote: 
> > Hi all 
> > 
> > I am now seeing the SQLAlchemy raise 'NoSuchColumnError' occasionally 
> > when concurrent accesses happen with 'select for update'. 
> > 
> > My application uses 
> >      * SQLAlchemy 0.8.4 
> >      * MySQL-python 1.2.3 
> >      * CentOS6.7 
> >      * python 2.6 
> >      * MariaDB 10.0.20 (three-node Galera Cluster with haproxy 1.5.2) 
>
>
> the column missing from the result set is not typically a result of 
> concurrent updates or anything like that, if it is happening only 
> sometimes then the leading suspect is the driver, in this case 
> MySQL-Python 1.2.3.   I would recommend at the very least upgrading to 
> 1.2.5, and preferably swapping it out with mysqlclient which is the 
> now-maintained fork of MySQL-Python. 
>
> On the SQLA side, running logging with echo='debug' will show the column 
> names being reported for result sets; if these sporadically change to no 
> longer correspond to the query just emitted, that problem is on the 
> driver side. 
>
>
>
>
> > 
> > I know Galera does not support explicit lock so I configure haproxy to 
> > redirect incoming requests only to one active node. 
> > The reason of this is to make explicit locking work for 'select for 
> > update', like the way we use single database server. 
> > So the other Galera nodes are setup just for backup. 
> > 
> > To break down what that application does, firstly I create engine and 
> > sessioinmaker with isolation_level="READ COMMITTED" 
> > 
> > ``` 
> > import sqlalchemy 
> > from sqlalchemy.orm import sessionmaker 
> > from sqlalchemy.pool import NullPool 
> > 
> > # 192.168.0.2 is virtual IP 
> > engine = sqlalchemy.create_engine( 
> >      "mysql://test:testtest@192.168.0.2/test", 
> >      poolclass=NullPool, 
> >      isolation_level="READ COMMITTED") 
> > maker = sessionmaker(bind=engine, autocommit=True) 
> > ``` 
> > 
> > Secondary the model is defined below, which has a composite key 
> > (`data_id1`, `data_id2`). 
> > 
> > ``` 
> > Base = declarative_base() 
> > class MyData(Base): 
> >      __tablename__ = 'mydata' 
> >      __table_args__ = ( 
> >          UniqueConstraint('data_id1', 'data_id2'), 
> >      ) 
> >      data_id1 = Column(String(64), primary_key=True) 
> >      data_id2 = Column(String(64), primary_key=True) 
> >      status = Column(String(40), nullable=True) 
> > ``` 
> > 
> > There could be multiple application processes running(not daemon) which 
> > could access to the same record. 
> > Each process firstly tries to lock a row, then check status of MyData 
> > and update status attribute. 
> > 
> > ``` 
> > ..... 
> >      session.begin() 
> >      try: 
> >          mydata = get_mydata(session, data_id1, data_id2, 
> lockmode="update") 
> >          // do something here to check status 
> >          update_status(session, data_id1, data_id2, "some status") 
> >          session.commit() 
> >      except Exception as e: 
> >          session.rollback() 
> > ..... 
> > 
> > 
> > def get_mydata(session, data_id1, data_id2, lockmode=None): 
> >      query = 
> > 
> session.query(MyData).filter_by(data_id1=data_id1).filter_by(data_id2=data_id2)
>  
>
> >      if lockmode: 
> >          query = query.with_lockmode(lockmode) 
> >      return query.first() 
> > 
> > 
> > def update_status(session, data_id1, data_id2, status): 
> >      data = get_mydata(session, data_id1, data_id2) 
> >      data.status = status 
> >      session.flush() 
> > ``` 
> > 
> > When concurrent access happens and one process locks a row, subsequent 
> > processes are blocked from processing the same record at the same time. 
> > The subsequent processes will wait until the previous one releases the 
> lock. 
> > This usually works fine as I expect but sometimes I see 
> > `NoSuchColumnError` cast when the subsequent process call 
> > `query.first()` within `update_status()`. 
> > 
> > ``` 
> > Traceback (most recent call last): 
> >    File "/root/myapp.py", line 301, in some_func() 
> >      update_status(session, data_id1, data_id2, "some status") 
> >    File "/root/myapp.py", line 231, in update_status 
> >      data = get_mydata(session, data_id1, data_id2) 
> >    File "/root/myapp.py", line 256, in get_mydata 
> >      return query.first() 
> >    File "/usr/lib64/python2.6/site-packages/sqlalchemy/orm/query.py", 
> > line 2282, in first 
> >      ret = list(self[0:1]) 
> >    File "/usr/lib64/python2.6/site-packages/sqlalchemy/orm/query.py", 
> > line 2149, in __getitem__ 
> >      return list(res) 
> >    File "/usr/lib64/python2.6/site-packages/sqlalchemy/orm/loading.py", 
> > line 72, in instances 
> >      rows = [process[0](row, None) for row in fetch] 
> >    File "/usr/lib64/python2.6/site-packages/sqlalchemy/orm/loading.py", 
> > line 356, in _instance 
> >      tuple([row[column] for column in pk_cols]) 
> >    File 
> > "/usr/lib64/python2.6/site-packages/sqlalchemy/engine/result.py", line 
> > 314, in _key_fallback 
> >      expression._string_or_unprintable(key)) 
> > NoSuchColumnError: "Could not locate column in row for column 
> > 'mydata.data_id1'" 
> > ``` 
> > 
> > I wish someone knows which point causes this error. 
> > 
> > -- 
> > You received this message because you are subscribed to the Google 
> > Groups "sqlalchemy" group. 
> > To unsubscribe from this group and stop receiving emails from it, send 
> > an email to sqlalchemy+...@googlegroups.com <javascript:> 
> > <mailto:sqlalchemy+unsubscr...@googlegroups.com <javascript:>>. 
> > To post to this group, send email to sqlal...@googlegroups.com 
> <javascript:> 
> > <mailto:sqlal...@googlegroups.com <javascript:>>. 
> > Visit this group at https://groups.google.com/group/sqlalchemy. 
> > For more options, visit https://groups.google.com/d/optout. 
>

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to