step one is to make the behavior go away, then you can bisect versions of mysql-python (assuming that was the problem) to figure out the specific issue. Very little has happened with mysql-python between 1.2.3 and 1.2.5 so if that's where the problem is it wouldn't be very hard to figure out.

On 04/19/2016 06:56 PM, Shingo Toda wrote:
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
    <http://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
    <https://groups.google.com/group/sqlalchemy>.
     > For more options, visit https://groups.google.com/d/optout
    <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
<mailto:sqlalchemy+unsubscr...@googlegroups.com>.
To post to this group, send email to sqlalchemy@googlegroups.com
<mailto:sqlalchemy@googlegroups.com>.
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