SQLAlchemy是著名的ORM(Object Relational Mapping-對(duì)象關(guān)系映射)框架。其主要作用是在編程中,把面向?qū)ο蟮母拍罡鷶?shù)據(jù)庫(kù)中表的概念對(duì)應(yīng)起來(lái)。對(duì)許多語(yǔ)言(例如JAVA/PYTHON)來(lái)說(shuō)就是定義一個(gè)對(duì)象,并且這個(gè)對(duì)象對(duì)應(yīng)著一張數(shù)據(jù)庫(kù)的表。而這個(gè)對(duì)象的實(shí)例,就對(duì)應(yīng)著表中的一條記錄。
其整體思路如下圖所示:
其中類、對(duì)象與屬性與數(shù)據(jù)庫(kù)相關(guān)內(nèi)容的對(duì)應(yīng)關(guān)系如下圖所示:
ORM的優(yōu)點(diǎn):
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-463125.html
-
數(shù)據(jù)模型與代碼統(tǒng)一定義,更新與維護(hù)簡(jiǎn)單,代碼高度重用一致。
-
ORM有現(xiàn)成的工具,很多功能都可以自動(dòng)完成,比如表格增刪、預(yù)處理、事務(wù)等。
-
基于ORM的業(yè)務(wù)代碼比較簡(jiǎn)單,代碼量少,語(yǔ)義性好,容易理解。
-
你不必編寫性能不佳的SQL。
ORM的缺點(diǎn):
?
-
ORM庫(kù)多層封裝,實(shí)現(xiàn)巧妙,需要花很多精力學(xué)習(xí)和設(shè)置。
-
對(duì)于復(fù)雜的查詢,ORM要么是無(wú)法表達(dá),要么是性能不如原生的SQL。
-
ORM抽象掉了數(shù)據(jù)庫(kù)層,開發(fā)者無(wú)法了解底層的數(shù)據(jù)庫(kù)操作,也無(wú)法定制一些特殊的SQL。
?
?
?從整體上看,ORM節(jié)省了開發(fā)時(shí)間,減少了代碼錯(cuò)誤的可能性,同時(shí)能夠方便地在多個(gè)數(shù)據(jù)庫(kù)間靈活遷移,還是非常值得使用。而在python語(yǔ)言中,SQLAlchemy是著名的ORM框架之一,它的整體架構(gòu)如下圖所示:
從圖中可以看出,SQLAIchemy是分層架構(gòu),由Core以及ORM兩部分組成。其中,Core完成了與數(shù)據(jù)庫(kù)操作的各類封閉,是相對(duì)低層的。而ORM層則利用Core層的能力進(jìn)行更宏觀的操作。因此,在一段python代碼中,使用Core與ORM層同時(shí)來(lái)操作數(shù)據(jù)庫(kù)也是可行的,并不矛盾與沖突。
下面先從最基本的表格創(chuàng)建做起。非ORM編程中,表格的創(chuàng)建無(wú)非兩個(gè)途徑:
●基于DBMS本身提供的CLI/GUI界面,發(fā)出DDL語(yǔ)句進(jìn)行數(shù)據(jù)庫(kù)/表格本身的增刪改查。
●使用語(yǔ)言連接數(shù)據(jù)庫(kù)后,發(fā)出命令來(lái)對(duì)數(shù)據(jù)庫(kù)/表格進(jìn)行增刪改查。
而由于每種數(shù)據(jù)庫(kù)都有自己的方言,所以命令語(yǔ)句各有差異,需要不斷地調(diào)整。而使用SQLAlchemy則實(shí)現(xiàn)了代碼統(tǒng)一。例如以下代碼在mssql以及mysql上創(chuàng)建表格,并且可以查詢表格的元數(shù)據(jù),以及插入數(shù)據(jù)后的查詢。
from sqlalchemy import (Column, Integer, MetaData, String, Table, create_engine, text, Float, DateTime, ForeignKey) from sqlalchemy_utils.functions import create_database, database_exists configure_pg = {"user": "postgres", 'password': '88488848', 'dns': 'dbserver.home', "port": 5432, 'prefix': 'postgresql+psycopg2', 'postfix': '' } configure_mssql = {"user": "sa", 'password': '88488848', 'dns': 'dbserver.home', "port": 1433, 'prefix': 'mssql+pymssql', 'postfix': '?charset=utf8' } configure_mysql = {"user": "root", 'password': '88488848', 'dns': 'dbserver.home', "port": 3306, 'prefix': 'mysql+mysqlconnector', 'postfix': '' } config = {'mssql': configure_mssql, 'mysql': configure_mysql, 'postgresql': configure_pg} database_name = 'testdb' table_sensor_location = "sensor_location" table_sensor_data = "sensor_data" def linkdb(targetstr): """ 連接不同的數(shù)據(jù)庫(kù) Args: targetstr (string): 數(shù)據(jù)庫(kù)名稱 Returns: engine: 用于后續(xù)的數(shù)據(jù)庫(kù)連接 """ if targetstr in config.keys(): item = config[targetstr] connectstring = f"{item['prefix']}://{item['user']}:{item['password']}@{item['dns']}:{item['port']}/{database_name}{item['postfix']}" engine = create_engine(connectstring, echo=True, future=True) # 如果數(shù)據(jù)庫(kù)不存在,則創(chuàng)建之 if not database_exists(engine.url): create_database(engine.url) # 做一個(gè)測(cè)試,不針對(duì)任何表 with engine.connect() as conn: result = conn.execute(text("select 'hello world'")) print(result.all()) return engine def createtbs(connector): """" 創(chuàng)建數(shù)據(jù)庫(kù)中的2張表。用于保存?zhèn)鞲衅鲾?shù)據(jù)與傳感器本身的信息 """ metadata_obj = MetaData() # 描述傳感器的表 sensor_location_tb = Table( table_sensor_location, metadata_obj, Column('id', Integer, primary_key=True, autoincrement=False), Column('location', String(30), nullable=False) ) # 保存?zhèn)鞲衅鲾?shù)據(jù)的表 sensor_data_tb = Table( table_sensor_data, metadata_obj, Column('id', Integer, primary_key=True, autoincrement=False), Column('sensor_id', ForeignKey( f'{table_sensor_location}.id'), nullable=False), Column('area', String(30)), Column('pm25', Float), Column('timestamp', DateTime) ) print(sensor_data_tb.compile()) # 創(chuàng)建并返回表 metadata_obj.create_all(connector) return sensor_data_tb, sensor_location_tb def tableinfo(connector, tablename): """ 獲得指定表名的相關(guān)元數(shù)據(jù)信息 Args: connector (engine): 數(shù)據(jù)庫(kù)連接器 tablename (string): 要查詢的表名 """ metadata_obj = MetaData() some_table = Table(tablename, metadata_obj, autoload_with=connector) print([c.name for c in some_table.columns]) def gensonsorinfo(connector): with connector.connect() as conn: conn.execute(text(f"INSERT INTO {table_sensor_location} (id, location) VALUES (:x, :y)"), [{"x": 1, "y": '1號(hào)樓'}, {"x": 2, "y": '2號(hào)樓'}]) conn.commit() result = conn.execute( text(f"SELECT id, location FROM {table_sensor_location}")) for x, y in result: print(f"id: {x} location: {y}") # 依次連接多個(gè)數(shù)據(jù)庫(kù)。從而驗(yàn)證代碼的一致性 for dbname in config.keys(): con = linkdb(dbname) createtbs(con) tableinfo(con, table_sensor_data) tableinfo(con, table_sensor_location) gensonsorinfo(con)
從代碼可以看出,可以用統(tǒng)一的訪問(wèn)方式來(lái)操作mssql/mysql/postgresql三種數(shù)據(jù)庫(kù)。而且,以上方式與前文中的基于游標(biāo)的寫法類似。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-463125.html
?
到了這里,關(guān)于Python工具箱系列(三十四)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!