一个简单的Python MVC框架(2)

2)数据库访问层
数据访问层是与数据库进行交互的接口,这里我仅仅实现了mysql的访问接口。下面是代码:

import pymysql
import os
#用于测试
class EmptyModel:
      def __init__(self,name=None):
            self.TableName=name
#数据库帮助基类,相当于接口。其实对于python这种语言,这个类完全没必要存在.
#不过对于多种数据库支持时,还是有点用.
#注意:这里的参数是格式化到字符串,无法防止SQL注入。为了防止SQL注入,可以对SQL进行处理。
#一般来说最好的办法是真正参数化,但我看了一下pymysql,并没有提供真正参数化的方法。
class DbHelper:
      def QueryByParam(self,sql,pms,EntityName,conn=None):
          return []
      def ExecuteCommand(self,sql,pms,conn=None):
          return 0
#Mysql的访问类,基于pymysql.
class DbHelperMySql(DbHelper):
    def __init__(self,CharsetName=‘utf8‘):
        self.CharsetName = CharsetName
        if(self.CharsetName==‘‘):
            self.CharsetName=‘utf8‘
      
        
    def ExecuteCommand(self,sql,pms,conn=None):
        theNeedCloseConn = False
        if(conn==None):
            conn=self.GetMySqlDbConnDefault()
            theNeedCloseConn = True
        theCursor = conn.cursor()
        try:
            theCursor.execute("set NAMES "+self.CharsetName) #保证字符集正确.
            theRet = theCursor.execute(sql,pms)
        finally:
            theCursor.close()
            if theNeedCloseConn:
                conn.close()
        return theRet
        
    @staticmethod
    def GetMySqlDbConn(host,port,user,pwd,dbname):
         return pymysql.connect(host=host, port=port,user=user, passwd=pwd, db=dbname)
    
    @staticmethod
    def GetMySqlDbConnDefault():
        return DbHelperMySql.GetMySqlDbConn(‘127.0.0.1‘,3306,‘xxxxx‘,‘xxxxx‘,‘dbname‘)
    #pms 为Dict类型.
    def QueryByParam1(self,sql,pms,EntityName,conn=None):
        theNeedCloseConn = False
        if(conn==None):
            conn=self.GetMySqlDbConnDefault()
            theNeedCloseConn = True
        theCursor = conn.cursor(pymysql.cursors.DictCursor)
        try:
            theCursor.execute("set NAMES "+self.CharsetName) #保证字符集正确.
            theCursor.execute(sql,pms)
            rows = theCursor.fetchall()
            models=[]
            for r in rows:
                m=EmptyModel(EntityName)
                for fld in r.items():
                      setattr(m,fld[0],fld[1])
                models.append(m)
            return models
        finally:
            theCursor.close()
            if theNeedCloseConn:
                conn.close()
        return []
      #pms 为Dict类型.
    def QueryByParam2(self,EntityType,sql,pms,conn=None):
        theNeedCloseConn = False
        if(conn==None):
            conn=self.GetMySqlDbConnDefault()
            theNeedCloseConn = True
        theCursor = conn.cursor(pymysql.cursors.DictCursor)
        try:
            theCursor.execute("set NAMES "+self.CharsetName) #保证字符集正确.
            theCursor.execute(sql,pms)
            rows = theCursor.fetchall()
            models=[]
            for r in rows:
                m=EntityType()
                for fld in r.items():
                      setattr(m,fld[0],fld[1])
                      m.CurrFields.append(fld[0])
                models.append(m)
            return models
        finally:
            theCursor.close()
            if theNeedCloseConn:
                conn.close()
        return []


没有单独做一个数据访问层,实体访问就放在业务基类中:
3)业务层基类:
主要提供实体类的增加,修改,删除和查询(单个和List),现在的应用模式,一般情况下不要缓存实体。EF和Hibernate那种缓存,其实都是灾难的开始。给实体打状态编辑,也仅仅是为了处理前面传过来的实体集合可以分解成增加,修改和删除。除此之外,实体状态的维护也是没必要的。

from DbOpts import *
import uuid
class BusinessBase(object):
    def __init__(self,EntityType):
        self.EntityType = EntityType
        
    def AddModel(self,model,conn=None):
        theDb=DbHelperMySql()
        theInsertSQL=model.GetInsertSQL()
        theValues=[]
        theFields = model.GetFields()
        for theF in theFields:
            theValues.append(model[theF])
        theRet= theDb.ExecuteCommand(theInsertSQL,theValues,conn)
        return theRet
    def GetModels(self,sql,pms,conn=None):
        theDb=DbHelperMySql()
        return theDb.QueryByParam2(self.EntityType,sql,pms,conn)
    def GetModel(self,pk,conn=None):
        theTable = self.EntityType.TableName
        theKeyField=self.EntityType.KeyField
        theSQL = ‘SELECT * FROM ‘+theTable+‘ WHERE ‘+theKeyField+‘=‘+self.EntityType.FieldParams[theKeyField][‘DSFmt‘]
        theParam=(pk)
        theModels = self.GetModels(theSQL,theParam,conn)
        if len(theModels)>0:
            return theModels[0]
        return None
    def UpdateModel(self,model,conn=None):
        theDb=DbHelperMySql()
        theSQL=model.GetUpdateAllSQL()
        theValues=[]
        theFields = model.GetFields()
        for theF in theFields:
            theValues.append(model[theF])
        theRet= theDb.ExecuteCommand(theSQL,theValues,conn)
        return theRet
    @staticmethod
    def GetGuid():
        return uuid.uuid1().__str__()
    def GetDbTables(self,dbname,conn=None):
        theSQL=‘select table_Comment as Script, table_Name as TableName,table_Type from INFORMATION_SCHEMA.tables where 1=1‘
        if(dbname!=None and dbname !=‘‘):
            theSQL += ‘ and table_schema=\‘‘+dbname+‘\‘‘
        theDb=DbHelperMySql()
        return theDb.QueryByParam1(theSQL,None,‘tables‘,conn)
    def GetTabFields(self,dbname,tablename,conn=None):
        theSQL =‘select a.table_name,a.column_name,a.data_type,a.is_nullable,           a.character_maximum_length as maxlengthb,a.character_octet_length as lengthb,           a.numeric_precision as precisionlen,a.numeric_scale as scalelen,            b.iskey            from information_schema.columns as a            left join ( select t.TABLE_NAME,c.COLUMN_NAME,1 as iskey from            INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS t,  INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS c            WHERE  t.TABLE_NAME = c.TABLE_NAME  AND t.CONSTRAINT_TYPE = \‘PRIMARY KEY\‘ ) as b            on a.table_name =b.table_name and a.column_name=b.column_name            where 1=1‘
        if(dbname!=None and dbname !=‘‘):
            theSQL += ‘ and a.table_schema=\‘‘+dbname+‘\‘‘
        if(tablename!=None and tablename !=‘‘):
            theSQL += ‘ and a.table_name=\‘‘+tablename+‘\‘‘
        theDb=DbHelperMySql()
        return theDb.QueryByParam1(theSQL,None,‘columns‘,conn)


我在基本方法中增加了conn参数,目的是为了扩展后面的事务处理。对于分布式的事务,这种方法是不适合的,但也只需要定义一个自己的事务类,这个事务包含参与事务的连接即可。



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。