Day4

今日总结:

1.数据库学习总结

  因为这部分的内容都是记在纸上,一共四页。所以博客里的内容比较少

2.重写ORM框架:

  之前在使用aiomysql+sqlalchemy的学习中,因为不太熟悉ORM的操作,结果将数据库连接和ORM写在了一起,这样造成了较强的耦合,不利于SQL的扩展;

而今天的学习呢,思路更加明确了。使用aiomysql来执行SQL语句、连接、返回数据结果;SQLalchemy呢,它主要用来进行数据库关系映射ORM,以及生成SQL语句。

这样一来,思路清晰了很多;虽然aiomysql能代替一些SQLalchemy的功能,或者SQLalchemy能直接执行数据库的执行操作(使用sessionmaker),但是这样混乱的使用,

显然对程序的开发是不友好的,方便,但是降低了开发的效率;

今日学习:

  -重写ORM框架,我会从这三个方面叙述:1.实现了哪些功能 2.为什么要这样实现 3.我遇到了哪些问题

  1.将数据库连接单独写成一层,Class DBcontroller类,初始化连接时,会使用单例模式(创建一个pool),用户不使用相同的conn,但却在同一个pool下,解决了用户使用单一连线造成的问题(服务器压力,数据传输之类的);同时用户也不用需要手动去连接mysql服务器。 

  

 1 class DBcontroller:
 2     __engine=None
 3     __isinstance = False
 4     def __new__(cls, *args, **kwargs):
 5         if cls.__isinstance:  # 如果被实例化了
 6             return cls.__isinstance  # 返回实例化对象
 7         print('connecting to database...')
 8         asyncio.get_event_loop().run_until_complete(DBcontroller.connect())
 9         cls.__isinstance = object.__new__(cls)  # 否则实例化
10         return cls.__isinstance  # 返回实例化的对象
11 
12     @staticmethod
13     async def connect():
14         try:
15             __engine = await create_engine(user='root',
16                                               db='youku',
17                                               host='127.0.0.1',
18                                               password='root',
19                                               minsize=1,
20                                               maxsize=10,
21                                               autocommit=True)
22             if __engine:
23                 DBcontroller.__engine = __engine
24                 DBcontroller.connectStatue =True
25                 print('connect to mysql success!')
26             else:
27                 raise ("connect to mysql error ")
28         except:
29             print('connect error.', exc_info=True)
30 
31     def selectTable(self,sql):
32         res=''
33         async def select(res):
34             conn = await DBcontroller.__engine.acquire()
35             try:
36                 result = await conn.execute(sql)
37                 res = await result.fetchall()
38                 # for row in res:
39                 #     print(row)
40             except Exception as e :
41                 print(e)
42             finally:
43                 DBcontroller.__engine.release(conn)
44                 return res
45         res = asyncio.get_event_loop().run_until_complete(select(res))
46         return res
47 
48     def executeTable(self,sql):
49         res=''
50         async def execute(res,sql):
51             conn = await DBcontroller.__engine.acquire()
52             try:
53                 result = await conn.execute(sql)
54                 res = result.lastrowid
55                 print('操作执行完毕')
56             except Exception as e:
57                 if e.args[0]== 1062:
58                     print('主键已存在')
59                 else:
60                     print(f'插入失败:{e}')
61             finally:
62                 DBcontroller.__engine.release(conn)
63                 return res
64         lastrowid = asyncio.get_event_loop().run_until_complete(execute(res,sql))
65         return lastrowid
DBcontroller

  2.自动生成Model.py,但前提必须使用sqlalchemy,在CMD里使用这串代码,就可以自动生成Model.py,解放了时间:

sqlacodegen mysql+pymysql://root:root@127.0.0.1:3306/automovie > models.py

    自动生成的Model里的类,也带有__table__,__mapper___等和sqlalchemy相同属性的类

  

  3.使用sqlalchemy生成sql语句,例如User类,ygy=User(name='杨归元',age=18),

使用sqlchemy.select('*').select_from(User.__table__).where(User.__table__.c.age==ygy.age),

那么可以生成"SELECT * FROM USER WHERE USER.AGE = 18"的句子;这里也就是为什么要使用ORM的原因吧!

1.为了防止SQL注入,用户不可能通过输入属性值来造成sql注入,因为中间有一层ORM;SQL没有直接裸露出来

2.为了是开发者,能够更加专注的去写业务逻辑层,不用去担心SQL语句到底要去怎么写;(当然直接写SQL也是种另外的感受)

  

  4.类似的语句还有这样的:self.__table__.update().values(attr).where(where)

具体网址在这里:https://www.osgeo.cn/sqlalchemy/core/dml.html

  

   5.为了获取user的属性,我去找了父类sqlalchemy.ext.declarative.declarative_base,去这里面的函数一个一个去看,然后又去百度了各种官方文档,

最后无解,时间都浪费在了这里,最后的解决方法是这样的,

  使用user.__dict__,获取属性;

  如果遇到inser操作时,插入成功了,那么我们要把user剩下的属性给返回,比如user.datatime,user.id;这些都是需要更新的;

  所以这个时候select一次user,然后将获得的属性值赋值给user.__dict__,结局失败了,原因不知;

  最后的解决方法是这样的:select返回一个对象,从数据库里取出属性,然后根据这个属性列表新建一个相应的对象

  6.如何使select方法返回一个对象?

   conn.execute(sql)之后,会返回一个resultProxy对象,

  可以for key, value in result.items()来获取列名和列表值:

    key:id value:1

    ...

    key:age value:18

  同时通过,type(self)获取它的类名

    那么 newuser = type(self)(),就可以新建了一个相同的对象

  7.当执行 result = await conn.execute(insertSQL)后,result.fetchall()会报异常,但是对系统运行没有影响:

  这里有关mysql的一个叫Nocount的东西:

  Set Nocount on

  当SET NOCOUNT on时候,将不向客户端发送存储过程每个语句的DONE_IN_proc消息,如果存储过程中包含一些并不返回实际数据的语句,网络通信流量便会大量减少,可以显著提高应用程序性能;

  插入执行结束后,没有返回值,但是我们却获取了返回值;但我们可以获取result.lastrowid,把刚插入的数据的id拿到

  8.以后再也不想研究ORM了。。。

  但是通过这几天的学习,我感觉自己的收获很多,从数据库引擎到数据库,从数据库到ORM,各方各面,条条划划的地方都有学习到,也算是不错的收获

原文地址:https://www.cnblogs.com/ygy1997/p/11795237.html