赞
踩
sqlalchemy是python的第三方库,提供了SQL工具和对象关系映射(ORM)工具,类似的还有Django ORM等。
比如有个学生类stduent,属性和方法如图所示
可以在IntelliJ IDEA中,通过快捷键alt+insert生成对应的方法。
java的ORM框架,比如Mybatis等,假设现在有张stduent表,定义如下
- create table student(
- id int primary key auto_increment not null comment '学号',
- name varchar(16) not null comment '姓名',
- age int not null comment '年龄'
- )
如果要通过Mybatis实现CRUD操作,显然需要实体类student,笔者举得例子比较简单,如果表的属性比较多或者表很多,每加入个表都需要实体类,写起来就会繁琐。因此,笔者想法是通过sqlalchemy读取表,然后生成实体类,或者说生成Studnet.java文件。
以student表为例。表中id的类型为int,转换成实体类则id的类型变成Integer或者int。其他也是类似的,而且实体类的实现很相似,先写属性,然后是get方法、set方法,构造函数、toString方法的实现。
既然如此,python可以通过字符串的拼接实现,但可能更繁杂,因此,笔者决定使用模板语法,使用jinja2,当然还有其他模板语法,比如Djang Template Lanage等。jinja2也是python的第三方库。
Jinja是一个基于Python设计语言的“全功能模板引擎”,下面简单的使用一下jinja2
- from jinja2 import Template
- template = Template('hello {{text}}')
- result=template.render(text='jinja2')
- print(result)
结果如下。
具体可参考jinja2的官方文件。
欢迎来到 Jinja2 — Jinja2 2.7 documentation (jinkan.org)
写之前先创建一个目录,目录名叫python_sql_java,其中创建一个settings.py文件。代码如下,
- from sqlalchemy import create_engine,MetaData
- # 数据库、驱动、用户、密码、ip、端口、端口号、数据库
- engine=create_engine('mysql+pymysql://root:123456@localhost:3306/sqlalchemy') # 获得engine
- # metadata对象
- metadata=MetaData()
这一步其实可以不通过sqlalchemy,可以用pymysql,但相对来说,用sqlalchemy更好,毕竟已经是封装好的框架,不需要写sql语句。
在python_sql_java文件下创建get_sql.py文件。其中代码如下。
- from sqlalchemy import Table, inspect
- from settings import engine, metadata
-
- sql_java = {
- 'Varchar': 'String',
- }
-
-
- def get_sql_word_type(table_name) -> list:
- """
- :param table: 表名
- :return: list
- """
- inspector = inspect(engine)
- columns = inspector.get_columns(table_name)
- words = []
- for column in columns:
- word_type = type(column['type']).__name__.capitalize()
- if word_type in sql_java.keys():
- word_type = sql_java[word_type]
- word_name = column['name']
- words.append({'word_name': word_name, 'word_type': word_type})
- return words
-
-
- properties = get_sql_word_type('student')
- for property in properties:
- print(property)
打印结果如下。
也可以选择把Integer变成int类型的,或者还有其他类型的替换,差不多,具体情况具体分析。
通过pandas的read_sql_table方法,获取类型,实际上查不多,没什么区别,代码如下
- import pandas as pd
- from settings import engine
-
- sql_java = {
- 'int64': 'Integer',
- 'object': 'String',
- }
-
-
- def get_sql_word_type(table_name):
- df = pd.read_sql_table(table_name, con=engine)
- field_info = []
- for column in df.columns:
- field_name = column
- field_type = str(df[column].dtype)
- if field_type in sql_java:
- field_type = sql_java[field_type]
- field_info.append([field_name, field_type])
- return field_info
-
-
- field_info = get_sql_word_type('student')
- for i in field_info:
- print(i)
结果如下,笔者后面将使用第一种方法
在写模板之前,先看一下IntelliJ IDEA生成的实体类Student。
- public class stduent {
- private Integer id;
- private String name;
- private Integer age;
-
- public stduent() {
- }
-
- public stduent(Integer id, String name, Integer age) {
- this.id = id;
- this.name = name;
- this.age = age;
- }
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public Integer getAge() {
- return age;
- }
-
- public void setAge(Integer age) {
- this.age = age;
- }
-
- @Override
- public String toString() {
- return "stduent{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
现在对上面代码进行模仿。
在模仿之前,先在当前目录(python_sql_java)下进行一个包,叫templates,其中放模板
在templates目录下进行一个entity.java文件,作为模板。
在python_sql_java目录新建一个mapper.py和render.py,
根据上面实体类,entity的代码如下
-
-
- public class {{table_name | capitalize}}{ {#类名#}
-
- {%- for property in properties %} {# 属性 #}
- private {{property.word_type}} {{property.word_name}};
- {%- endfor %}
-
- public {{table_name | capitalize}}() { {# 无参构造 #}
- }
-
- public {{table_name | capitalize}}({# 有参构造 #}
- {%- for property in properties -%}
- {%- if loop.last -%}
- {{property.word_type}} {{property.word_name}}
- {%- else -%}
- {{property.word_type}} {{property.word_name}},
- {%-endif-%}
- {% endfor -%}
- ) {
- {%- for property in properties %}
- this.{{property.word_name}} = {{property.word_name}};
- {%- endfor %}
- }
- {% for property in properties %} {# get方法 #}
- public {{property.word_type}} get{{property.word_name | capitalize }}() {
- return {{property.word_name}};
- }
- {% endfor%}
- {% for property in properties %} {# set方法 #}
- public void set{{property.word_name | capitalize }}({{property.word_type}} {{property.word_name}}) {
- this.{{property.word_name}}={{property.word_name}};
- }
- {% endfor%}
- @Override
- public String toString() { {# toString方法 #}
- return "{{table_name | capitalize}}{" +
- {% for property in properties %}
- {%- if loop.first -%}
- "{{property.word_name}}=" + {{property.word_name}} +
- {% elif loop.last%}
- ",{{property.word_name}}=" + {{property.word_name}} +
- {%- else -%}
- ", {{property.word_name}}='" + {{property.word_name}} + '\'' +
- {%- endif -%}
- {% endfor %}
- '}';
- }
- }
render.py的代码如下
- from jinja2 import FileSystemLoader,Environment
- def get_mapper(table_name,properties):
- loader = FileSystemLoader('./templates')
- environment = Environment(loader=loader)
- template = environment.get_template('entity.java')
- return template.render(
- table_name=table_name,
- properties=properties
- )
-
- properties=[{'word_name': 'id', 'word_type': 'Integer'}, {'word_name': 'name', 'word_type': 'String'}, {'word_name': 'age', 'word_type': 'Integer'}]
- java=get_mapper('student',properties)
- print(java)
运行后结果如图所示
渲染后的结果还是可以的。
在mapper.py文件中写下最终的代码。
- from jinja2 import Template, FileSystemLoader, Environment
- from sqlalchemy import Table, inspect
- from settings import engine, metadata
- import os
-
-
- class Entity:
- def __init__(self, table_name):
- self.table_name = table_name
- self.sql_java = {
- 'Varchar': 'String',
- }
-
- def get_sql_word_type(self) -> list:
- """
- :return: list
- """
- inspector = inspect(engine)
- columns = inspector.get_columns(self.table_name)
- words = []
- for column in columns:
- word_type = type(column['type']).__name__.capitalize()
- if word_type in self.sql_java.keys():
- word_type = self.sql_java[word_type]
- word_name = column['name']
- words.append({'word_name': word_name, 'word_type': word_type})
- return words
-
- def get_mapper(self)->str:
- words = self.get_sql_word_type()
- loader = FileSystemLoader('./templates')
- environment = Environment(loader=loader)
- template = environment.get_template('entity.java')
- return template.render(
- table_name='student',
- properties=words
- )
-
- def get_result(self, java_str, file_path=None):
- if not file_path:
- file_path = f'{self.table_name}.java'
- if not os.path.exists(file_path):
- open(file_path, 'w').close()
- with open(file_path, 'w') as f:
- f.write(java_str)
-
- @staticmethod
- def start(table_name, file_path=None):
- entity = Entity(table_name)
- java = entity.get_mapper()
- entity.get_result(java)
-
-
- Entity.start('student')
运行后在当前目录下生成student.java文件,内容和上面的java一样。
因为这个实体的属性比较少,运行没有问题,但不一定全部适用,可以会有问题,后面会继续修改。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。